1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) { 35 DMPolytopeType ct; 36 PetscInt cStart, cEnd; 37 38 PetscFunctionBegin; 39 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 40 if (cEnd <= cStart) { 41 *simplex = PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 45 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 46 PetscFunctionReturn(0); 47 } 48 49 /*@ 50 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 51 52 Input Parameters: 53 + dm - The DMPlex object 54 - height - The cell height in the Plex, 0 is the default 55 56 Output Parameters: 57 + cStart - The first "normal" cell 58 - cEnd - The upper bound on "normal"" cells 59 60 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 61 62 Level: developer 63 64 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 65 @*/ 66 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) { 67 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 68 PetscInt cS, cE, c; 69 70 PetscFunctionBegin; 71 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 72 for (c = cS; c < cE; ++c) { 73 DMPolytopeType cct; 74 75 PetscCall(DMPlexGetCellType(dm, c, &cct)); 76 if ((PetscInt)cct < 0) break; 77 switch (cct) { 78 case DM_POLYTOPE_POINT: 79 case DM_POLYTOPE_SEGMENT: 80 case DM_POLYTOPE_TRIANGLE: 81 case DM_POLYTOPE_QUADRILATERAL: 82 case DM_POLYTOPE_TETRAHEDRON: 83 case DM_POLYTOPE_HEXAHEDRON: ct = cct; break; 84 default: break; 85 } 86 if (ct != DM_POLYTOPE_UNKNOWN) break; 87 } 88 if (ct != DM_POLYTOPE_UNKNOWN) { 89 DMLabel ctLabel; 90 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 93 // Reset label for fast lookup 94 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 95 } 96 if (cStart) *cStart = cS; 97 if (cEnd) *cEnd = cE; 98 PetscFunctionReturn(0); 99 } 100 101 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) { 102 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 103 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 104 105 PetscFunctionBegin; 106 *ft = PETSC_VTK_INVALID; 107 PetscCall(DMGetCoordinateDim(dm, &cdim)); 108 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 109 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 110 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 111 if (field >= 0) { 112 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 113 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 114 } else { 115 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 116 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 117 } 118 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 119 if (globalvcdof[0]) { 120 *sStart = vStart; 121 *sEnd = vEnd; 122 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 123 else *ft = PETSC_VTK_POINT_FIELD; 124 } else if (globalvcdof[1]) { 125 *sStart = cStart; 126 *sEnd = cEnd; 127 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 128 else *ft = PETSC_VTK_CELL_FIELD; 129 } else { 130 if (field >= 0) { 131 const char *fieldname; 132 133 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 134 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 135 } else { 136 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 137 } 138 } 139 PetscFunctionReturn(0); 140 } 141 142 /*@ 143 DMPlexVecView1D - Plot many 1D solutions on the same line graph 144 145 Collective on dm 146 147 Input Parameters: 148 + dm - The DMPlex 149 . n - The number of vectors 150 . u - The array of local vectors 151 - viewer - The Draw viewer 152 153 Level: advanced 154 155 .seealso: `VecViewFromOptions()`, `VecView()` 156 @*/ 157 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) { 158 PetscDS ds; 159 PetscDraw draw = NULL; 160 PetscDrawLG lg; 161 Vec coordinates; 162 const PetscScalar *coords, **sol; 163 PetscReal *vals; 164 PetscInt *Nc; 165 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 166 char **names; 167 168 PetscFunctionBegin; 169 PetscCall(DMGetDS(dm, &ds)); 170 PetscCall(PetscDSGetNumFields(ds, &Nf)); 171 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 172 PetscCall(PetscDSGetComponents(ds, &Nc)); 173 174 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 175 if (!draw) PetscFunctionReturn(0); 176 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 177 178 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 179 for (i = 0, l = 0; i < n; ++i) { 180 const char *vname; 181 182 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 183 for (f = 0; f < Nf; ++f) { 184 PetscObject disc; 185 const char *fname; 186 char tmpname[PETSC_MAX_PATH_LEN]; 187 188 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 189 /* TODO Create names for components */ 190 for (c = 0; c < Nc[f]; ++c, ++l) { 191 PetscCall(PetscObjectGetName(disc, &fname)); 192 PetscCall(PetscStrcpy(tmpname, vname)); 193 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 195 PetscCall(PetscStrallocpy(tmpname, &names[l])); 196 } 197 } 198 } 199 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 200 /* Just add P_1 support for now */ 201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 202 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 203 PetscCall(VecGetArrayRead(coordinates, &coords)); 204 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 205 for (v = vStart; v < vEnd; ++v) { 206 PetscScalar *x, *svals; 207 208 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 209 for (i = 0; i < n; ++i) { 210 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 211 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 212 } 213 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 214 } 215 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 216 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 217 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 218 PetscCall(PetscFree3(sol, names, vals)); 219 220 PetscCall(PetscDrawLGDraw(lg)); 221 PetscCall(PetscDrawLGDestroy(&lg)); 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) { 235 DM dm; 236 PetscSection s; 237 PetscDraw draw, popup; 238 DM cdm; 239 PetscSection coordSection; 240 Vec coordinates; 241 const PetscScalar *coords, *array; 242 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 243 PetscReal vbound[2], time; 244 PetscBool flg; 245 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 246 const char *name; 247 char title[PETSC_MAX_PATH_LEN]; 248 249 PetscFunctionBegin; 250 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 251 PetscCall(VecGetDM(v, &dm)); 252 PetscCall(DMGetCoordinateDim(dm, &dim)); 253 PetscCall(DMGetLocalSection(dm, &s)); 254 PetscCall(PetscSectionGetNumFields(s, &Nf)); 255 PetscCall(DMGetCoarsenLevel(dm, &level)); 256 PetscCall(DMGetCoordinateDM(dm, &cdm)); 257 PetscCall(DMGetLocalSection(cdm, &coordSection)); 258 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 259 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 260 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 261 262 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 263 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 264 265 PetscCall(VecGetLocalSize(coordinates, &N)); 266 PetscCall(VecGetArrayRead(coordinates, &coords)); 267 for (c = 0; c < N; c += dim) { 268 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 269 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 271 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 272 } 273 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 274 PetscCall(PetscDrawClear(draw)); 275 276 /* Could implement something like DMDASelectFields() */ 277 for (f = 0; f < Nf; ++f) { 278 DM fdm = dm; 279 Vec fv = v; 280 IS fis; 281 char prefix[PETSC_MAX_PATH_LEN]; 282 const char *fname; 283 284 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 285 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 286 287 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 288 else prefix[0] = '\0'; 289 if (Nf > 1) { 290 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 291 PetscCall(VecGetSubVector(v, fis, &fv)); 292 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 293 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 294 } 295 for (comp = 0; comp < Nc; ++comp, ++w) { 296 PetscInt nmax = 2; 297 298 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 299 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 300 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 301 PetscCall(PetscDrawSetTitle(draw, title)); 302 303 /* TODO Get max and min only for this component */ 304 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 305 if (!flg) { 306 PetscCall(VecMin(fv, NULL, &vbound[0])); 307 PetscCall(VecMax(fv, NULL, &vbound[1])); 308 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 309 } 310 PetscCall(PetscDrawGetPopup(draw, &popup)); 311 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 312 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 313 314 PetscCall(VecGetArrayRead(fv, &array)); 315 for (c = cStart; c < cEnd; ++c) { 316 PetscScalar *coords = NULL, *a = NULL; 317 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 318 319 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 320 if (a) { 321 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 322 color[1] = color[2] = color[3] = color[0]; 323 } else { 324 PetscScalar *vals = NULL; 325 PetscInt numVals, va; 326 327 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 328 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 329 switch (numVals / Nc) { 330 case 3: /* P1 Triangle */ 331 case 4: /* P1 Quadrangle */ 332 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 333 break; 334 case 6: /* P2 Triangle */ 335 case 8: /* P2 Quadrangle */ 336 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 337 break; 338 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 339 } 340 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 341 } 342 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 343 switch (numCoords) { 344 case 6: 345 case 12: /* Localized triangle */ 346 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 347 break; 348 case 8: 349 case 16: /* Localized quadrilateral */ 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 351 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 352 break; 353 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 354 } 355 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 356 } 357 PetscCall(VecRestoreArrayRead(fv, &array)); 358 PetscCall(PetscDrawFlush(draw)); 359 PetscCall(PetscDrawPause(draw)); 360 PetscCall(PetscDrawSave(draw)); 361 } 362 if (Nf > 1) { 363 PetscCall(VecRestoreSubVector(v, fis, &fv)); 364 PetscCall(ISDestroy(&fis)); 365 PetscCall(DMDestroy(&fdm)); 366 } 367 } 368 PetscFunctionReturn(0); 369 } 370 371 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); break; 387 default: SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) { 393 DM dm; 394 Vec locv; 395 const char *name; 396 PetscSection section; 397 PetscInt pStart, pEnd; 398 PetscInt numFields; 399 PetscViewerVTKFieldType ft; 400 401 PetscFunctionBegin; 402 PetscCall(VecGetDM(v, &dm)); 403 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 404 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 405 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 406 PetscCall(VecCopy(v, locv)); 407 PetscCall(DMGetLocalSection(dm, §ion)); 408 PetscCall(PetscSectionGetNumFields(section, &numFields)); 409 if (!numFields) { 410 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 411 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 412 } else { 413 PetscInt f; 414 415 for (f = 0; f < numFields; f++) { 416 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 417 if (ft == PETSC_VTK_INVALID) continue; 418 PetscCall(PetscObjectReference((PetscObject)locv)); 419 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 420 } 421 PetscCall(VecDestroy(&locv)); 422 } 423 PetscFunctionReturn(0); 424 } 425 426 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) { 427 DM dm; 428 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 429 430 PetscFunctionBegin; 431 PetscCall(VecGetDM(v, &dm)); 432 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 433 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 434 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 437 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 438 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 439 PetscInt i, numFields; 440 PetscObject fe; 441 PetscBool fem = PETSC_FALSE; 442 Vec locv = v; 443 const char *name; 444 PetscInt step; 445 PetscReal time; 446 447 PetscCall(DMGetNumFields(dm, &numFields)); 448 for (i = 0; i < numFields; i++) { 449 PetscCall(DMGetField(dm, i, NULL, &fe)); 450 if (fe->classid == PETSCFE_CLASSID) { 451 fem = PETSC_TRUE; 452 break; 453 } 454 } 455 if (fem) { 456 PetscObject isZero; 457 458 PetscCall(DMGetLocalVector(dm, &locv)); 459 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 460 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 461 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 462 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 463 PetscCall(VecCopy(v, locv)); 464 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 465 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 466 } 467 if (isvtk) { 468 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 469 } else if (ishdf5) { 470 #if defined(PETSC_HAVE_HDF5) 471 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 472 #else 473 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 474 #endif 475 } else if (isdraw) { 476 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 477 } else if (isglvis) { 478 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 479 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 480 PetscCall(VecView_GLVis(locv, viewer)); 481 } else if (iscgns) { 482 #if defined(PETSC_HAVE_CGNS) 483 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 484 #else 485 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 486 #endif 487 } 488 if (fem) { 489 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 490 PetscCall(DMRestoreLocalVector(dm, &locv)); 491 } 492 } else { 493 PetscBool isseq; 494 495 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 496 if (isseq) PetscCall(VecView_Seq(v, viewer)); 497 else PetscCall(VecView_MPI(v, viewer)); 498 } 499 PetscFunctionReturn(0); 500 } 501 502 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) { 503 DM dm; 504 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 505 506 PetscFunctionBegin; 507 PetscCall(VecGetDM(v, &dm)); 508 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 509 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 510 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 511 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 512 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 513 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 514 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 515 if (isvtk || isdraw || isglvis || iscgns) { 516 Vec locv; 517 PetscObject isZero; 518 const char *name; 519 520 PetscCall(DMGetLocalVector(dm, &locv)); 521 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 522 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 523 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 524 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 525 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 526 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 527 PetscCall(VecView_Plex_Local(locv, viewer)); 528 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 529 PetscCall(DMRestoreLocalVector(dm, &locv)); 530 } else if (ishdf5) { 531 #if defined(PETSC_HAVE_HDF5) 532 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 533 #else 534 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 535 #endif 536 } else if (isexodusii) { 537 #if defined(PETSC_HAVE_EXODUSII) 538 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 539 #else 540 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 541 #endif 542 } else { 543 PetscBool isseq; 544 545 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 546 if (isseq) PetscCall(VecView_Seq(v, viewer)); 547 else PetscCall(VecView_MPI(v, viewer)); 548 } 549 PetscFunctionReturn(0); 550 } 551 552 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) { 553 DM dm; 554 MPI_Comm comm; 555 PetscViewerFormat format; 556 Vec v; 557 PetscBool isvtk, ishdf5; 558 559 PetscFunctionBegin; 560 PetscCall(VecGetDM(originalv, &dm)); 561 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 562 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 563 PetscCall(PetscViewerGetFormat(viewer, &format)); 564 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 565 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 566 if (format == PETSC_VIEWER_NATIVE) { 567 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 568 /* this need a better fix */ 569 if (dm->useNatural) { 570 if (dm->sfNatural) { 571 const char *vecname; 572 PetscInt n, nroots; 573 574 PetscCall(VecGetLocalSize(originalv, &n)); 575 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 576 if (n == nroots) { 577 PetscCall(DMGetGlobalVector(dm, &v)); 578 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 579 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 580 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 581 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 582 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 583 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 584 } else v = originalv; 585 } else v = originalv; 586 587 if (ishdf5) { 588 #if defined(PETSC_HAVE_HDF5) 589 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 590 #else 591 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 592 #endif 593 } else if (isvtk) { 594 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 595 } else { 596 PetscBool isseq; 597 598 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 599 if (isseq) PetscCall(VecView_Seq(v, viewer)); 600 else PetscCall(VecView_MPI(v, viewer)); 601 } 602 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 603 PetscFunctionReturn(0); 604 } 605 606 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) { 607 DM dm; 608 PetscBool ishdf5; 609 610 PetscFunctionBegin; 611 PetscCall(VecGetDM(v, &dm)); 612 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 613 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 614 if (ishdf5) { 615 DM dmBC; 616 Vec gv; 617 const char *name; 618 619 PetscCall(DMGetOutputDM(dm, &dmBC)); 620 PetscCall(DMGetGlobalVector(dmBC, &gv)); 621 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 622 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 623 PetscCall(VecLoad_Default(gv, viewer)); 624 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 625 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 626 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 627 } else PetscCall(VecLoad_Default(v, viewer)); 628 PetscFunctionReturn(0); 629 } 630 631 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) { 632 DM dm; 633 PetscBool ishdf5, isexodusii; 634 635 PetscFunctionBegin; 636 PetscCall(VecGetDM(v, &dm)); 637 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (ishdf5) { 641 #if defined(PETSC_HAVE_HDF5) 642 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 643 #else 644 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 645 #endif 646 } else if (isexodusii) { 647 #if defined(PETSC_HAVE_EXODUSII) 648 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 649 #else 650 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 651 #endif 652 } else PetscCall(VecLoad_Default(v, viewer)); 653 PetscFunctionReturn(0); 654 } 655 656 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else PetscCall(VecLoad_Default(originalv, viewer)); 687 } 688 PetscFunctionReturn(0); 689 } 690 691 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) { 692 PetscSection coordSection; 693 Vec coordinates; 694 DMLabel depthLabel, celltypeLabel; 695 const char *name[4]; 696 const PetscScalar *a; 697 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 698 699 PetscFunctionBegin; 700 PetscCall(DMGetDimension(dm, &dim)); 701 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 702 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 703 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 704 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 705 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 706 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 707 PetscCall(VecGetArrayRead(coordinates, &a)); 708 name[0] = "vertex"; 709 name[1] = "edge"; 710 name[dim - 1] = "face"; 711 name[dim] = "cell"; 712 for (c = cStart; c < cEnd; ++c) { 713 PetscInt *closure = NULL; 714 PetscInt closureSize, cl, ct; 715 716 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 717 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 718 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 719 PetscCall(PetscViewerASCIIPushTab(viewer)); 720 for (cl = 0; cl < closureSize * 2; cl += 2) { 721 PetscInt point = closure[cl], depth, dof, off, d, p; 722 723 if ((point < pStart) || (point >= pEnd)) continue; 724 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 725 if (!dof) continue; 726 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 727 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 728 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 729 for (p = 0; p < dof / dim; ++p) { 730 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 731 for (d = 0; d < dim; ++d) { 732 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 733 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 734 } 735 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 736 } 737 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 738 } 739 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 740 PetscCall(PetscViewerASCIIPopTab(viewer)); 741 } 742 PetscCall(VecRestoreArrayRead(coordinates, &a)); 743 PetscFunctionReturn(0); 744 } 745 746 typedef enum { 747 CS_CARTESIAN, 748 CS_POLAR, 749 CS_CYLINDRICAL, 750 CS_SPHERICAL 751 } CoordSystem; 752 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 753 754 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) { 755 PetscInt i; 756 757 PetscFunctionBegin; 758 if (dim > 3) { 759 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 760 } else { 761 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 762 763 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 764 switch (cs) { 765 case CS_CARTESIAN: 766 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 767 break; 768 case CS_POLAR: 769 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 770 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 771 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 772 break; 773 case CS_CYLINDRICAL: 774 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 775 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 776 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 777 trcoords[2] = coords[2]; 778 break; 779 case CS_SPHERICAL: 780 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 781 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 782 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 783 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 784 break; 785 } 786 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 787 } 788 PetscFunctionReturn(0); 789 } 790 791 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) { 792 DM_Plex *mesh = (DM_Plex *)dm->data; 793 DM cdm, cdmCell; 794 PetscSection coordSection, coordSectionCell; 795 Vec coordinates, coordinatesCell; 796 PetscViewerFormat format; 797 798 PetscFunctionBegin; 799 PetscCall(DMGetCoordinateDM(dm, &cdm)); 800 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 801 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 802 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 803 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 804 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 805 PetscCall(PetscViewerGetFormat(viewer, &format)); 806 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 807 const char *name; 808 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 809 PetscInt pStart, pEnd, p, numLabels, l; 810 PetscMPIInt rank, size; 811 812 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 813 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 814 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 815 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 816 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 817 PetscCall(DMGetDimension(dm, &dim)); 818 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 819 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 820 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 821 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 822 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 823 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 824 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 825 for (p = pStart; p < pEnd; ++p) { 826 PetscInt dof, off, s; 827 828 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 829 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 830 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 831 } 832 PetscCall(PetscViewerFlush(viewer)); 833 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 834 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 835 for (p = pStart; p < pEnd; ++p) { 836 PetscInt dof, off, c; 837 838 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 839 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 840 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 841 } 842 PetscCall(PetscViewerFlush(viewer)); 843 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 844 if (coordSection && coordinates) { 845 CoordSystem cs = CS_CARTESIAN; 846 const PetscScalar *array, *arrayCell = NULL; 847 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 848 PetscMPIInt rank; 849 const char *name; 850 851 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 852 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 853 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 854 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 855 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 856 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 857 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 858 pStart = PetscMin(pvStart, pcStart); 859 pEnd = PetscMax(pvEnd, pcEnd); 860 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 863 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 864 865 PetscCall(VecGetArrayRead(coordinates, &array)); 866 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 867 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 868 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 869 for (p = pStart; p < pEnd; ++p) { 870 PetscInt dof, off; 871 872 if (p >= pvStart && p < pvEnd) { 873 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 874 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 875 if (dof) { 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 877 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 878 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 879 } 880 } 881 if (cdmCell && p >= pcStart && p < pcEnd) { 882 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 883 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 884 if (dof) { 885 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 886 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 887 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 888 } 889 } 890 } 891 PetscCall(PetscViewerFlush(viewer)); 892 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 893 PetscCall(VecRestoreArrayRead(coordinates, &array)); 894 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 895 } 896 PetscCall(DMGetNumLabels(dm, &numLabels)); 897 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 898 for (l = 0; l < numLabels; ++l) { 899 DMLabel label; 900 PetscBool isdepth; 901 const char *name; 902 903 PetscCall(DMGetLabelName(dm, l, &name)); 904 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 905 if (isdepth) continue; 906 PetscCall(DMGetLabel(dm, name, &label)); 907 PetscCall(DMLabelView(label, viewer)); 908 } 909 if (size > 1) { 910 PetscSF sf; 911 912 PetscCall(DMGetPointSF(dm, &sf)); 913 PetscCall(PetscSFView(sf, viewer)); 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 917 const char *name, *color; 918 const char *defcolors[3] = {"gray", "orange", "green"}; 919 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 920 char lname[PETSC_MAX_PATH_LEN]; 921 PetscReal scale = 2.0; 922 PetscReal tikzscale = 1.0; 923 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 924 double tcoords[3]; 925 PetscScalar *coords; 926 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 927 PetscMPIInt rank, size; 928 char **names, **colors, **lcolors; 929 PetscBool flg, lflg; 930 PetscBT wp = NULL; 931 PetscInt pEnd, pStart; 932 933 PetscCall(DMGetDimension(dm, &dim)); 934 PetscCall(DMPlexGetDepth(dm, &depth)); 935 PetscCall(DMGetNumLabels(dm, &numLabels)); 936 numLabels = PetscMax(numLabels, 10); 937 numColors = 10; 938 numLColors = 10; 939 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 940 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 941 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 942 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 943 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 944 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 945 n = 4; 946 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 947 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 948 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 949 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 950 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 951 if (!useLabels) numLabels = 0; 952 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 953 if (!useColors) { 954 numColors = 3; 955 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 956 } 957 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 958 if (!useColors) { 959 numLColors = 4; 960 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 961 } 962 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 963 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 964 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 965 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 966 if (depth < dim) plotEdges = PETSC_FALSE; 967 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 968 969 /* filter points with labelvalue != labeldefaultvalue */ 970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 971 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 972 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 973 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 974 if (lflg) { 975 DMLabel lbl; 976 977 PetscCall(DMGetLabel(dm, lname, &lbl)); 978 if (lbl) { 979 PetscInt val, defval; 980 981 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 982 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 983 for (c = pStart; c < pEnd; c++) { 984 PetscInt *closure = NULL; 985 PetscInt closureSize; 986 987 PetscCall(DMLabelGetValue(lbl, c, &val)); 988 if (val == defval) continue; 989 990 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 992 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 993 } 994 } 995 } 996 997 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 998 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 999 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1001 \\documentclass[tikz]{standalone}\n\n\ 1002 \\usepackage{pgflibraryshapes}\n\ 1003 \\usetikzlibrary{backgrounds}\n\ 1004 \\usetikzlibrary{arrows}\n\ 1005 \\begin{document}\n")); 1006 if (size > 1) { 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1008 for (p = 0; p < size; ++p) { 1009 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1011 } 1012 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1013 } 1014 if (drawHasse) { 1015 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1016 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1018 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1029 } 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1031 1032 /* Plot vertices */ 1033 PetscCall(VecGetArray(coordinates, &coords)); 1034 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1035 for (v = vStart; v < vEnd; ++v) { 1036 PetscInt off, dof, d; 1037 PetscBool isLabeled = PETSC_FALSE; 1038 1039 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1040 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1041 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1042 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1043 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1044 for (d = 0; d < dof; ++d) { 1045 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1046 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1047 } 1048 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1049 if (dim == 3) { 1050 PetscReal tmp = tcoords[1]; 1051 tcoords[1] = tcoords[2]; 1052 tcoords[2] = -tmp; 1053 } 1054 for (d = 0; d < dof; ++d) { 1055 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1056 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1057 } 1058 if (drawHasse) color = colors[0 % numColors]; 1059 else color = colors[rank % numColors]; 1060 for (l = 0; l < numLabels; ++l) { 1061 PetscInt val; 1062 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1063 if (val >= 0) { 1064 color = lcolors[l % numLColors]; 1065 isLabeled = PETSC_TRUE; 1066 break; 1067 } 1068 } 1069 if (drawNumbers[0]) { 1070 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1071 } else if (drawColors[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1073 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1074 } 1075 PetscCall(VecRestoreArray(coordinates, &coords)); 1076 PetscCall(PetscViewerFlush(viewer)); 1077 /* Plot edges */ 1078 if (plotEdges) { 1079 PetscCall(VecGetArray(coordinates, &coords)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1081 for (e = eStart; e < eEnd; ++e) { 1082 const PetscInt *cone; 1083 PetscInt coneSize, offA, offB, dof, d; 1084 1085 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1086 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1087 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1088 PetscCall(DMPlexGetCone(dm, e, &cone)); 1089 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1090 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1091 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1093 for (d = 0; d < dof; ++d) { 1094 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1095 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1096 } 1097 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1098 if (dim == 3) { 1099 PetscReal tmp = tcoords[1]; 1100 tcoords[1] = tcoords[2]; 1101 tcoords[2] = -tmp; 1102 } 1103 for (d = 0; d < dof; ++d) { 1104 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1106 } 1107 if (drawHasse) color = colors[1 % numColors]; 1108 else color = colors[rank % numColors]; 1109 for (l = 0; l < numLabels; ++l) { 1110 PetscInt val; 1111 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1112 if (val >= 0) { 1113 color = lcolors[l % numLColors]; 1114 break; 1115 } 1116 } 1117 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1118 } 1119 PetscCall(VecRestoreArray(coordinates, &coords)); 1120 PetscCall(PetscViewerFlush(viewer)); 1121 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1122 } 1123 /* Plot cells */ 1124 if (dim == 3 || !drawNumbers[1]) { 1125 for (e = eStart; e < eEnd; ++e) { 1126 const PetscInt *cone; 1127 1128 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1129 color = colors[rank % numColors]; 1130 for (l = 0; l < numLabels; ++l) { 1131 PetscInt val; 1132 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1133 if (val >= 0) { 1134 color = lcolors[l % numLColors]; 1135 break; 1136 } 1137 } 1138 PetscCall(DMPlexGetCone(dm, e, &cone)); 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1140 } 1141 } else { 1142 DMPolytopeType ct; 1143 1144 /* Drawing a 2D polygon */ 1145 for (c = cStart; c < cEnd; ++c) { 1146 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1147 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1148 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1149 const PetscInt *cone; 1150 PetscInt coneSize, e; 1151 1152 PetscCall(DMPlexGetCone(dm, c, &cone)); 1153 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1154 for (e = 0; e < coneSize; ++e) { 1155 const PetscInt *econe; 1156 1157 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1158 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1159 } 1160 } else { 1161 PetscInt *closure = NULL; 1162 PetscInt closureSize, Nv = 0, v; 1163 1164 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1165 for (p = 0; p < closureSize * 2; p += 2) { 1166 const PetscInt point = closure[p]; 1167 1168 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1169 } 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1171 for (v = 0; v <= Nv; ++v) { 1172 const PetscInt vertex = closure[v % Nv]; 1173 1174 if (v > 0) { 1175 if (plotEdges) { 1176 const PetscInt *edge; 1177 PetscInt endpoints[2], ne; 1178 1179 endpoints[0] = closure[v - 1]; 1180 endpoints[1] = vertex; 1181 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1182 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1183 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1184 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1185 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1186 } 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1188 } 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1190 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1191 } 1192 } 1193 } 1194 for (c = cStart; c < cEnd; ++c) { 1195 double ccoords[3] = {0.0, 0.0, 0.0}; 1196 PetscBool isLabeled = PETSC_FALSE; 1197 PetscScalar *cellCoords = NULL; 1198 const PetscScalar *array; 1199 PetscInt numCoords, cdim, d; 1200 PetscBool isDG; 1201 1202 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1203 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1204 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1205 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1207 for (p = 0; p < numCoords / cdim; ++p) { 1208 for (d = 0; d < cdim; ++d) { 1209 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1210 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1211 } 1212 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1213 if (cdim == 3) { 1214 PetscReal tmp = tcoords[1]; 1215 tcoords[1] = tcoords[2]; 1216 tcoords[2] = -tmp; 1217 } 1218 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1219 } 1220 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1221 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1222 for (d = 0; d < cdim; ++d) { 1223 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1224 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1225 } 1226 if (drawHasse) color = colors[depth % numColors]; 1227 else color = colors[rank % numColors]; 1228 for (l = 0; l < numLabels; ++l) { 1229 PetscInt val; 1230 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1231 if (val >= 0) { 1232 color = lcolors[l % numLColors]; 1233 isLabeled = PETSC_TRUE; 1234 break; 1235 } 1236 } 1237 if (drawNumbers[dim]) { 1238 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1239 } else if (drawColors[dim]) { 1240 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1241 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1242 } 1243 if (drawHasse) { 1244 color = colors[depth % numColors]; 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1250 1251 color = colors[1 % numColors]; 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1257 1258 color = colors[0 % numColors]; 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1264 1265 for (p = pStart; p < pEnd; ++p) { 1266 const PetscInt *cone; 1267 PetscInt coneSize, cp; 1268 1269 PetscCall(DMPlexGetCone(dm, p, &cone)); 1270 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1271 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1272 } 1273 } 1274 PetscCall(PetscViewerFlush(viewer)); 1275 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1278 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1279 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1280 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1281 PetscCall(PetscFree3(names, colors, lcolors)); 1282 PetscCall(PetscBTDestroy(&wp)); 1283 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1284 Vec cown, acown; 1285 VecScatter sct; 1286 ISLocalToGlobalMapping g2l; 1287 IS gid, acis; 1288 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1289 MPI_Group ggroup, ngroup; 1290 PetscScalar *array, nid; 1291 const PetscInt *idxs; 1292 PetscInt *idxs2, *start, *adjacency, *work; 1293 PetscInt64 lm[3], gm[3]; 1294 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1295 PetscMPIInt d1, d2, rank; 1296 1297 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1298 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1299 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1300 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1301 #endif 1302 if (ncomm != MPI_COMM_NULL) { 1303 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1304 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1305 d1 = 0; 1306 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1307 nid = d2; 1308 PetscCallMPI(MPI_Group_free(&ggroup)); 1309 PetscCallMPI(MPI_Group_free(&ngroup)); 1310 PetscCallMPI(MPI_Comm_free(&ncomm)); 1311 } else nid = 0.0; 1312 1313 /* Get connectivity */ 1314 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1315 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1316 1317 /* filter overlapped local cells */ 1318 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1319 PetscCall(ISGetIndices(gid, &idxs)); 1320 PetscCall(ISGetLocalSize(gid, &cum)); 1321 PetscCall(PetscMalloc1(cum, &idxs2)); 1322 for (c = cStart, cum = 0; c < cEnd; c++) { 1323 if (idxs[c - cStart] < 0) continue; 1324 idxs2[cum++] = idxs[c - cStart]; 1325 } 1326 PetscCall(ISRestoreIndices(gid, &idxs)); 1327 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1328 PetscCall(ISDestroy(&gid)); 1329 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1330 1331 /* support for node-aware cell locality */ 1332 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1333 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1334 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1335 PetscCall(VecGetArray(cown, &array)); 1336 for (c = 0; c < numVertices; c++) array[c] = nid; 1337 PetscCall(VecRestoreArray(cown, &array)); 1338 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1339 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1340 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1341 PetscCall(ISDestroy(&acis)); 1342 PetscCall(VecScatterDestroy(&sct)); 1343 PetscCall(VecDestroy(&cown)); 1344 1345 /* compute edgeCut */ 1346 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1347 PetscCall(PetscMalloc1(cum, &work)); 1348 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1349 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1350 PetscCall(ISDestroy(&gid)); 1351 PetscCall(VecGetArray(acown, &array)); 1352 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1353 PetscInt totl; 1354 1355 totl = start[c + 1] - start[c]; 1356 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1357 for (i = 0; i < totl; i++) { 1358 if (work[i] < 0) { 1359 ect += 1; 1360 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1361 } 1362 } 1363 } 1364 PetscCall(PetscFree(work)); 1365 PetscCall(VecRestoreArray(acown, &array)); 1366 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1367 lm[1] = -numVertices; 1368 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1369 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1370 lm[0] = ect; /* edgeCut */ 1371 lm[1] = ectn; /* node-aware edgeCut */ 1372 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1373 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1374 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1375 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1376 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1377 #else 1378 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1379 #endif 1380 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1381 PetscCall(PetscFree(start)); 1382 PetscCall(PetscFree(adjacency)); 1383 PetscCall(VecDestroy(&acown)); 1384 } else { 1385 const char *name; 1386 PetscInt *sizes, *hybsizes, *ghostsizes; 1387 PetscInt locDepth, depth, cellHeight, dim, d; 1388 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1389 PetscInt numLabels, l, maxSize = 17; 1390 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1391 MPI_Comm comm; 1392 PetscMPIInt size, rank; 1393 1394 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1395 PetscCallMPI(MPI_Comm_size(comm, &size)); 1396 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1397 PetscCall(DMGetDimension(dm, &dim)); 1398 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1399 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1400 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1401 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1402 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1403 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1404 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1405 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1406 gcNum = gcEnd - gcStart; 1407 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1408 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1409 for (d = 0; d <= depth; d++) { 1410 PetscInt Nc[2] = {0, 0}, ict; 1411 1412 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1413 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1414 ict = ct0; 1415 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1416 ct0 = (DMPolytopeType)ict; 1417 for (p = pStart; p < pEnd; ++p) { 1418 DMPolytopeType ct; 1419 1420 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1421 if (ct == ct0) ++Nc[0]; 1422 else ++Nc[1]; 1423 } 1424 if (size < maxSize) { 1425 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1426 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1427 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1429 for (p = 0; p < size; ++p) { 1430 if (rank == 0) { 1431 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1432 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1433 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1434 } 1435 } 1436 } else { 1437 PetscInt locMinMax[2]; 1438 1439 locMinMax[0] = Nc[0] + Nc[1]; 1440 locMinMax[1] = Nc[0] + Nc[1]; 1441 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1442 locMinMax[0] = Nc[1]; 1443 locMinMax[1] = Nc[1]; 1444 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1445 if (d == depth) { 1446 locMinMax[0] = gcNum; 1447 locMinMax[1] = gcNum; 1448 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1449 } 1450 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1451 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1452 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1453 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1454 } 1455 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1456 } 1457 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1458 { 1459 const PetscReal *maxCell; 1460 const PetscReal *L; 1461 PetscBool localized; 1462 1463 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1464 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1465 if (L || localized) { 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1467 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1468 if (L) { 1469 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1470 for (d = 0; d < dim; ++d) { 1471 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1473 } 1474 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1475 } 1476 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1477 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1478 } 1479 } 1480 PetscCall(DMGetNumLabels(dm, &numLabels)); 1481 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1482 for (l = 0; l < numLabels; ++l) { 1483 DMLabel label; 1484 const char *name; 1485 IS valueIS; 1486 const PetscInt *values; 1487 PetscInt numValues, v; 1488 1489 PetscCall(DMGetLabelName(dm, l, &name)); 1490 PetscCall(DMGetLabel(dm, name, &label)); 1491 PetscCall(DMLabelGetNumValues(label, &numValues)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1493 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1494 PetscCall(ISGetIndices(valueIS, &values)); 1495 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1496 for (v = 0; v < numValues; ++v) { 1497 PetscInt size; 1498 1499 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1500 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1502 } 1503 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1504 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1505 PetscCall(ISRestoreIndices(valueIS, &values)); 1506 PetscCall(ISDestroy(&valueIS)); 1507 } 1508 { 1509 char **labelNames; 1510 PetscInt Nl = numLabels; 1511 PetscBool flg; 1512 1513 PetscCall(PetscMalloc1(Nl, &labelNames)); 1514 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1515 for (l = 0; l < Nl; ++l) { 1516 DMLabel label; 1517 1518 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1519 if (flg) { 1520 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1521 PetscCall(DMLabelView(label, viewer)); 1522 } 1523 PetscCall(PetscFree(labelNames[l])); 1524 } 1525 PetscCall(PetscFree(labelNames)); 1526 } 1527 /* If no fields are specified, people do not want to see adjacency */ 1528 if (dm->Nf) { 1529 PetscInt f; 1530 1531 for (f = 0; f < dm->Nf; ++f) { 1532 const char *name; 1533 1534 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1535 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1536 PetscCall(PetscViewerASCIIPushTab(viewer)); 1537 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1538 if (dm->fields[f].adjacency[0]) { 1539 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1541 } else { 1542 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1543 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1544 } 1545 PetscCall(PetscViewerASCIIPopTab(viewer)); 1546 } 1547 } 1548 PetscCall(DMGetCoarseDM(dm, &cdm)); 1549 if (cdm) { 1550 PetscCall(PetscViewerASCIIPushTab(viewer)); 1551 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1552 PetscCall(PetscViewerASCIIPopTab(viewer)); 1553 } 1554 } 1555 PetscFunctionReturn(0); 1556 } 1557 1558 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) { 1559 DMPolytopeType ct; 1560 PetscMPIInt rank; 1561 PetscInt cdim; 1562 1563 PetscFunctionBegin; 1564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1565 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1566 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1567 switch (ct) { 1568 case DM_POLYTOPE_SEGMENT: 1569 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1570 switch (cdim) { 1571 case 1: { 1572 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1573 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1574 1575 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1576 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1577 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1578 } break; 1579 case 2: { 1580 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1581 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1582 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1583 1584 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1585 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1586 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1587 } break; 1588 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1589 } 1590 break; 1591 case DM_POLYTOPE_TRIANGLE: 1592 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1594 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1595 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1596 break; 1597 case DM_POLYTOPE_QUADRILATERAL: 1598 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1599 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1600 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1601 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1602 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1603 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1604 break; 1605 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1606 } 1607 PetscFunctionReturn(0); 1608 } 1609 1610 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) { 1611 DMPolytopeType ct; 1612 PetscReal centroid[2] = {0., 0.}; 1613 PetscMPIInt rank; 1614 PetscInt fillColor, v, e, d; 1615 1616 PetscFunctionBegin; 1617 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1618 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1619 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1620 switch (ct) { 1621 case DM_POLYTOPE_TRIANGLE: { 1622 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1623 1624 for (v = 0; v < 3; ++v) { 1625 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1626 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1627 } 1628 for (e = 0; e < 3; ++e) { 1629 refCoords[0] = refVertices[e * 2 + 0]; 1630 refCoords[1] = refVertices[e * 2 + 1]; 1631 for (d = 1; d <= edgeDiv; ++d) { 1632 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1633 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1634 } 1635 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1636 for (d = 0; d < edgeDiv; ++d) { 1637 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1638 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1639 } 1640 } 1641 } break; 1642 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1643 } 1644 PetscFunctionReturn(0); 1645 } 1646 1647 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) { 1648 PetscDraw draw; 1649 DM cdm; 1650 PetscSection coordSection; 1651 Vec coordinates; 1652 const PetscScalar *coords; 1653 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1654 PetscReal *refCoords, *edgeCoords; 1655 PetscBool isnull, drawAffine = PETSC_TRUE; 1656 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1657 1658 PetscFunctionBegin; 1659 PetscCall(DMGetCoordinateDim(dm, &dim)); 1660 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1661 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1662 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1663 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1664 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1665 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1666 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1667 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1668 1669 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1670 PetscCall(PetscDrawIsNull(draw, &isnull)); 1671 if (isnull) PetscFunctionReturn(0); 1672 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1673 1674 PetscCall(VecGetLocalSize(coordinates, &N)); 1675 PetscCall(VecGetArrayRead(coordinates, &coords)); 1676 for (c = 0; c < N; c += dim) { 1677 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1678 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1679 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1680 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1681 } 1682 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1683 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1684 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1685 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1686 PetscCall(PetscDrawClear(draw)); 1687 1688 for (c = cStart; c < cEnd; ++c) { 1689 PetscScalar *coords = NULL; 1690 PetscInt numCoords; 1691 1692 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1693 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1694 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1695 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1696 } 1697 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1698 PetscCall(PetscDrawFlush(draw)); 1699 PetscCall(PetscDrawPause(draw)); 1700 PetscCall(PetscDrawSave(draw)); 1701 PetscFunctionReturn(0); 1702 } 1703 1704 #if defined(PETSC_HAVE_EXODUSII) 1705 #include <exodusII.h> 1706 #include <petscviewerexodusii.h> 1707 #endif 1708 1709 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) { 1710 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1711 char name[PETSC_MAX_PATH_LEN]; 1712 1713 PetscFunctionBegin; 1714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1715 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1716 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1723 if (iascii) { 1724 PetscViewerFormat format; 1725 PetscCall(PetscViewerGetFormat(viewer, &format)); 1726 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1727 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1728 } else if (ishdf5) { 1729 #if defined(PETSC_HAVE_HDF5) 1730 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1731 #else 1732 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1733 #endif 1734 } else if (isvtk) { 1735 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1736 } else if (isdraw) { 1737 PetscCall(DMPlexView_Draw(dm, viewer)); 1738 } else if (isglvis) { 1739 PetscCall(DMPlexView_GLVis(dm, viewer)); 1740 #if defined(PETSC_HAVE_EXODUSII) 1741 } else if (isexodus) { 1742 /* 1743 exodusII requires that all sets be part of exactly one cell set. 1744 If the dm does not have a "Cell Sets" label defined, we create one 1745 with ID 1, containig all cells. 1746 Note that if the Cell Sets label is defined but does not cover all cells, 1747 we may still have a problem. This should probably be checked here or in the viewer; 1748 */ 1749 PetscInt numCS; 1750 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1751 if (!numCS) { 1752 PetscInt cStart, cEnd, c; 1753 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1754 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1755 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1756 } 1757 PetscCall(DMView_PlexExodusII(dm, viewer)); 1758 #endif 1759 #if defined(PETSC_HAVE_CGNS) 1760 } else if (iscgns) { 1761 PetscCall(DMView_PlexCGNS(dm, viewer)); 1762 #endif 1763 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1764 /* Optionally view the partition */ 1765 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1766 if (flg) { 1767 Vec ranks; 1768 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1769 PetscCall(VecView(ranks, viewer)); 1770 PetscCall(VecDestroy(&ranks)); 1771 } 1772 /* Optionally view a label */ 1773 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1774 if (flg) { 1775 DMLabel label; 1776 Vec val; 1777 1778 PetscCall(DMGetLabel(dm, name, &label)); 1779 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1780 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1781 PetscCall(VecView(val, viewer)); 1782 PetscCall(VecDestroy(&val)); 1783 } 1784 PetscFunctionReturn(0); 1785 } 1786 1787 /*@ 1788 DMPlexTopologyView - Saves a DMPlex topology into a file 1789 1790 Collective on DM 1791 1792 Input Parameters: 1793 + dm - The DM whose topology is to be saved 1794 - viewer - The PetscViewer for saving 1795 1796 Level: advanced 1797 1798 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1799 @*/ 1800 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) { 1801 PetscBool ishdf5; 1802 1803 PetscFunctionBegin; 1804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1805 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1806 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1807 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1808 if (ishdf5) { 1809 #if defined(PETSC_HAVE_HDF5) 1810 PetscViewerFormat format; 1811 PetscCall(PetscViewerGetFormat(viewer, &format)); 1812 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1813 IS globalPointNumbering; 1814 1815 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1816 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1817 PetscCall(ISDestroy(&globalPointNumbering)); 1818 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1819 #else 1820 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1821 #endif 1822 } 1823 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1824 PetscFunctionReturn(0); 1825 } 1826 1827 /*@ 1828 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1829 1830 Collective on DM 1831 1832 Input Parameters: 1833 + dm - The DM whose coordinates are to be saved 1834 - viewer - The PetscViewer for saving 1835 1836 Level: advanced 1837 1838 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1839 @*/ 1840 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) { 1841 PetscBool ishdf5; 1842 1843 PetscFunctionBegin; 1844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1845 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1846 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1847 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1848 if (ishdf5) { 1849 #if defined(PETSC_HAVE_HDF5) 1850 PetscViewerFormat format; 1851 PetscCall(PetscViewerGetFormat(viewer, &format)); 1852 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1853 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1854 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1855 #else 1856 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1857 #endif 1858 } 1859 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1860 PetscFunctionReturn(0); 1861 } 1862 1863 /*@ 1864 DMPlexLabelsView - Saves DMPlex labels into a file 1865 1866 Collective on DM 1867 1868 Input Parameters: 1869 + dm - The DM whose labels are to be saved 1870 - viewer - The PetscViewer for saving 1871 1872 Level: advanced 1873 1874 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1875 @*/ 1876 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) { 1877 PetscBool ishdf5; 1878 1879 PetscFunctionBegin; 1880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1881 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1882 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1883 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1884 if (ishdf5) { 1885 #if defined(PETSC_HAVE_HDF5) 1886 IS globalPointNumbering; 1887 PetscViewerFormat format; 1888 1889 PetscCall(PetscViewerGetFormat(viewer, &format)); 1890 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1891 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1892 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1893 PetscCall(ISDestroy(&globalPointNumbering)); 1894 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1895 #else 1896 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1897 #endif 1898 } 1899 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1900 PetscFunctionReturn(0); 1901 } 1902 1903 /*@ 1904 DMPlexSectionView - Saves a section associated with a DMPlex 1905 1906 Collective on DM 1907 1908 Input Parameters: 1909 + dm - The DM that contains the topology on which the section to be saved is defined 1910 . viewer - The PetscViewer for saving 1911 - sectiondm - The DM that contains the section to be saved 1912 1913 Level: advanced 1914 1915 Notes: 1916 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1917 1918 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1919 1920 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1921 @*/ 1922 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) { 1923 PetscBool ishdf5; 1924 1925 PetscFunctionBegin; 1926 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1927 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1928 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1930 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1931 if (ishdf5) { 1932 #if defined(PETSC_HAVE_HDF5) 1933 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1934 #else 1935 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1936 #endif 1937 } 1938 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1939 PetscFunctionReturn(0); 1940 } 1941 1942 /*@ 1943 DMPlexGlobalVectorView - Saves a global vector 1944 1945 Collective on DM 1946 1947 Input Parameters: 1948 + dm - The DM that represents the topology 1949 . viewer - The PetscViewer to save data with 1950 . sectiondm - The DM that contains the global section on which vec is defined 1951 - vec - The global vector to be saved 1952 1953 Level: advanced 1954 1955 Notes: 1956 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1957 1958 Typical calling sequence 1959 $ DMCreate(PETSC_COMM_WORLD, &dm); 1960 $ DMSetType(dm, DMPLEX); 1961 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1962 $ DMClone(dm, §iondm); 1963 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1964 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1965 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1966 $ PetscSectionSetChart(section, pStart, pEnd); 1967 $ PetscSectionSetUp(section); 1968 $ DMSetLocalSection(sectiondm, section); 1969 $ PetscSectionDestroy(§ion); 1970 $ DMGetGlobalVector(sectiondm, &vec); 1971 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1972 $ DMPlexTopologyView(dm, viewer); 1973 $ DMPlexSectionView(dm, viewer, sectiondm); 1974 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1975 $ DMRestoreGlobalVector(sectiondm, &vec); 1976 $ DMDestroy(§iondm); 1977 $ DMDestroy(&dm); 1978 1979 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1980 @*/ 1981 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 1982 PetscBool ishdf5; 1983 1984 PetscFunctionBegin; 1985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1986 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1987 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1988 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1989 /* Check consistency */ 1990 { 1991 PetscSection section; 1992 PetscBool includesConstraints; 1993 PetscInt m, m1; 1994 1995 PetscCall(VecGetLocalSize(vec, &m1)); 1996 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1997 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1998 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1999 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2000 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2001 } 2002 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2003 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2004 if (ishdf5) { 2005 #if defined(PETSC_HAVE_HDF5) 2006 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2007 #else 2008 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2009 #endif 2010 } 2011 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2012 PetscFunctionReturn(0); 2013 } 2014 2015 /*@ 2016 DMPlexLocalVectorView - Saves a local vector 2017 2018 Collective on DM 2019 2020 Input Parameters: 2021 + dm - The DM that represents the topology 2022 . viewer - The PetscViewer to save data with 2023 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2024 - vec - The local vector to be saved 2025 2026 Level: advanced 2027 2028 Notes: 2029 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2030 2031 Typical calling sequence 2032 $ DMCreate(PETSC_COMM_WORLD, &dm); 2033 $ DMSetType(dm, DMPLEX); 2034 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2035 $ DMClone(dm, §iondm); 2036 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2037 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2038 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2039 $ PetscSectionSetChart(section, pStart, pEnd); 2040 $ PetscSectionSetUp(section); 2041 $ DMSetLocalSection(sectiondm, section); 2042 $ DMGetLocalVector(sectiondm, &vec); 2043 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2044 $ DMPlexTopologyView(dm, viewer); 2045 $ DMPlexSectionView(dm, viewer, sectiondm); 2046 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2047 $ DMRestoreLocalVector(sectiondm, &vec); 2048 $ DMDestroy(§iondm); 2049 $ DMDestroy(&dm); 2050 2051 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2052 @*/ 2053 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 2054 PetscBool ishdf5; 2055 2056 PetscFunctionBegin; 2057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2058 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2059 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2060 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2061 /* Check consistency */ 2062 { 2063 PetscSection section; 2064 PetscBool includesConstraints; 2065 PetscInt m, m1; 2066 2067 PetscCall(VecGetLocalSize(vec, &m1)); 2068 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2069 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2070 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2071 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2072 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2073 } 2074 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2075 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2076 if (ishdf5) { 2077 #if defined(PETSC_HAVE_HDF5) 2078 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2079 #else 2080 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2081 #endif 2082 } 2083 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2084 PetscFunctionReturn(0); 2085 } 2086 2087 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) { 2088 PetscBool ishdf5; 2089 2090 PetscFunctionBegin; 2091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2092 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2093 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2094 if (ishdf5) { 2095 #if defined(PETSC_HAVE_HDF5) 2096 PetscViewerFormat format; 2097 PetscCall(PetscViewerGetFormat(viewer, &format)); 2098 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2099 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2100 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2101 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2102 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2103 PetscFunctionReturn(0); 2104 #else 2105 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2106 #endif 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2108 } 2109 2110 /*@ 2111 DMPlexTopologyLoad - Loads a topology into a DMPlex 2112 2113 Collective on DM 2114 2115 Input Parameters: 2116 + dm - The DM into which the topology is loaded 2117 - viewer - The PetscViewer for the saved topology 2118 2119 Output Parameters: 2120 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2121 2122 Level: advanced 2123 2124 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2125 @*/ 2126 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) { 2127 PetscBool ishdf5; 2128 2129 PetscFunctionBegin; 2130 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2131 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2132 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2133 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2134 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2135 if (ishdf5) { 2136 #if defined(PETSC_HAVE_HDF5) 2137 PetscViewerFormat format; 2138 PetscCall(PetscViewerGetFormat(viewer, &format)); 2139 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2140 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2141 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2142 #else 2143 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2144 #endif 2145 } 2146 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2147 PetscFunctionReturn(0); 2148 } 2149 2150 /*@ 2151 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2152 2153 Collective on DM 2154 2155 Input Parameters: 2156 + dm - The DM into which the coordinates are loaded 2157 . viewer - The PetscViewer for the saved coordinates 2158 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2159 2160 Level: advanced 2161 2162 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2163 @*/ 2164 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2165 PetscBool ishdf5; 2166 2167 PetscFunctionBegin; 2168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2169 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2170 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2171 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2172 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2173 if (ishdf5) { 2174 #if defined(PETSC_HAVE_HDF5) 2175 PetscViewerFormat format; 2176 PetscCall(PetscViewerGetFormat(viewer, &format)); 2177 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2178 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2179 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2180 #else 2181 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2182 #endif 2183 } 2184 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2185 PetscFunctionReturn(0); 2186 } 2187 2188 /*@ 2189 DMPlexLabelsLoad - Loads labels into a DMPlex 2190 2191 Collective on DM 2192 2193 Input Parameters: 2194 + dm - The DM into which the labels are loaded 2195 . viewer - The PetscViewer for the saved labels 2196 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2197 2198 Level: advanced 2199 2200 Notes: 2201 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2202 2203 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2204 @*/ 2205 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2206 PetscBool ishdf5; 2207 2208 PetscFunctionBegin; 2209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2210 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2211 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2212 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2213 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2214 if (ishdf5) { 2215 #if defined(PETSC_HAVE_HDF5) 2216 PetscViewerFormat format; 2217 2218 PetscCall(PetscViewerGetFormat(viewer, &format)); 2219 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2220 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2221 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2222 #else 2223 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2224 #endif 2225 } 2226 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2227 PetscFunctionReturn(0); 2228 } 2229 2230 /*@ 2231 DMPlexSectionLoad - Loads section into a DMPlex 2232 2233 Collective on DM 2234 2235 Input Parameters: 2236 + dm - The DM that represents the topology 2237 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2238 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2239 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2240 2241 Output Parameters 2242 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2243 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2244 2245 Level: advanced 2246 2247 Notes: 2248 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2249 2250 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2251 2252 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2253 2254 Example using 2 processes: 2255 $ NX (number of points on dm): 4 2256 $ sectionA : the on-disk section 2257 $ vecA : a vector associated with sectionA 2258 $ sectionB : sectiondm's local section constructed in this function 2259 $ vecB (local) : a vector associated with sectiondm's local section 2260 $ vecB (global) : a vector associated with sectiondm's global section 2261 $ 2262 $ rank 0 rank 1 2263 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2264 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2265 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2266 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2267 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2268 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2269 $ sectionB->atlasDof : 1 0 1 | 1 3 2270 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2271 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2272 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2273 $ 2274 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2275 2276 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2277 @*/ 2278 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) { 2279 PetscBool ishdf5; 2280 2281 PetscFunctionBegin; 2282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2283 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2284 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2285 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2286 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2287 if (localDofSF) PetscValidPointer(localDofSF, 6); 2288 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2289 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2290 if (ishdf5) { 2291 #if defined(PETSC_HAVE_HDF5) 2292 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2293 #else 2294 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2295 #endif 2296 } 2297 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2298 PetscFunctionReturn(0); 2299 } 2300 2301 /*@ 2302 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2303 2304 Collective on DM 2305 2306 Input Parameters: 2307 + dm - The DM that represents the topology 2308 . viewer - The PetscViewer that represents the on-disk vector data 2309 . sectiondm - The DM that contains the global section on which vec is defined 2310 . sf - The SF that migrates the on-disk vector data into vec 2311 - vec - The global vector to set values of 2312 2313 Level: advanced 2314 2315 Notes: 2316 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2317 2318 Typical calling sequence 2319 $ DMCreate(PETSC_COMM_WORLD, &dm); 2320 $ DMSetType(dm, DMPLEX); 2321 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2322 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2323 $ DMClone(dm, §iondm); 2324 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2325 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2326 $ DMGetGlobalVector(sectiondm, &vec); 2327 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2328 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2329 $ DMRestoreGlobalVector(sectiondm, &vec); 2330 $ PetscSFDestroy(&gsf); 2331 $ PetscSFDestroy(&sfX); 2332 $ DMDestroy(§iondm); 2333 $ DMDestroy(&dm); 2334 2335 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2336 @*/ 2337 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2344 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2345 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2346 /* Check consistency */ 2347 { 2348 PetscSection section; 2349 PetscBool includesConstraints; 2350 PetscInt m, m1; 2351 2352 PetscCall(VecGetLocalSize(vec, &m1)); 2353 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2354 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2355 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2356 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2357 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2358 } 2359 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2360 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2361 if (ishdf5) { 2362 #if defined(PETSC_HAVE_HDF5) 2363 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2364 #else 2365 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2366 #endif 2367 } 2368 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2369 PetscFunctionReturn(0); 2370 } 2371 2372 /*@ 2373 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2374 2375 Collective on DM 2376 2377 Input Parameters: 2378 + dm - The DM that represents the topology 2379 . viewer - The PetscViewer that represents the on-disk vector data 2380 . sectiondm - The DM that contains the local section on which vec is defined 2381 . sf - The SF that migrates the on-disk vector data into vec 2382 - vec - The local vector to set values of 2383 2384 Level: advanced 2385 2386 Notes: 2387 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2388 2389 Typical calling sequence 2390 $ DMCreate(PETSC_COMM_WORLD, &dm); 2391 $ DMSetType(dm, DMPLEX); 2392 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2393 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2394 $ DMClone(dm, §iondm); 2395 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2396 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2397 $ DMGetLocalVector(sectiondm, &vec); 2398 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2399 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2400 $ DMRestoreLocalVector(sectiondm, &vec); 2401 $ PetscSFDestroy(&lsf); 2402 $ PetscSFDestroy(&sfX); 2403 $ DMDestroy(§iondm); 2404 $ DMDestroy(&dm); 2405 2406 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2407 @*/ 2408 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2409 PetscBool ishdf5; 2410 2411 PetscFunctionBegin; 2412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2413 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2414 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2415 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2416 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2417 /* Check consistency */ 2418 { 2419 PetscSection section; 2420 PetscBool includesConstraints; 2421 PetscInt m, m1; 2422 2423 PetscCall(VecGetLocalSize(vec, &m1)); 2424 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2425 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2426 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2427 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2428 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2429 } 2430 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2431 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2432 if (ishdf5) { 2433 #if defined(PETSC_HAVE_HDF5) 2434 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2435 #else 2436 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2437 #endif 2438 } 2439 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2440 PetscFunctionReturn(0); 2441 } 2442 2443 PetscErrorCode DMDestroy_Plex(DM dm) { 2444 DM_Plex *mesh = (DM_Plex *)dm->data; 2445 2446 PetscFunctionBegin; 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2460 if (--mesh->refct > 0) PetscFunctionReturn(0); 2461 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2462 PetscCall(PetscFree(mesh->cones)); 2463 PetscCall(PetscFree(mesh->coneOrientations)); 2464 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2465 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2466 PetscCall(PetscFree(mesh->supports)); 2467 PetscCall(PetscFree(mesh->facesTmp)); 2468 PetscCall(PetscFree(mesh->tetgenOpts)); 2469 PetscCall(PetscFree(mesh->triangleOpts)); 2470 PetscCall(PetscFree(mesh->transformType)); 2471 PetscCall(PetscFree(mesh->distributionName)); 2472 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2473 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2474 PetscCall(ISDestroy(&mesh->subpointIS)); 2475 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2476 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2477 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2478 PetscCall(ISDestroy(&mesh->anchorIS)); 2479 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2480 PetscCall(PetscFree(mesh->parents)); 2481 PetscCall(PetscFree(mesh->childIDs)); 2482 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2483 PetscCall(PetscFree(mesh->children)); 2484 PetscCall(DMDestroy(&mesh->referenceTree)); 2485 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2486 PetscCall(PetscFree(mesh->neighbors)); 2487 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2488 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2489 PetscCall(PetscFree(mesh)); 2490 PetscFunctionReturn(0); 2491 } 2492 2493 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) { 2494 PetscSection sectionGlobal; 2495 PetscInt bs = -1, mbs; 2496 PetscInt localSize, localStart = 0; 2497 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2498 MatType mtype; 2499 ISLocalToGlobalMapping ltog; 2500 2501 PetscFunctionBegin; 2502 PetscCall(MatInitializePackage()); 2503 mtype = dm->mattype; 2504 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2505 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2506 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2507 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2508 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2509 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2510 PetscCall(MatSetType(*J, mtype)); 2511 PetscCall(MatSetFromOptions(*J)); 2512 PetscCall(MatGetBlockSize(*J, &mbs)); 2513 if (mbs > 1) bs = mbs; 2514 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2515 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2516 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2517 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2522 if (!isShell) { 2523 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2524 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2525 PetscInt pStart, pEnd, p, dof, cdof; 2526 2527 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2528 2529 PetscCall(PetscCalloc1(localSize, &pblocks)); 2530 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2531 for (p = pStart; p < pEnd; ++p) { 2532 PetscInt bdof, offset; 2533 2534 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2535 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2536 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2537 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2538 dof = dof < 0 ? -(dof + 1) : dof; 2539 bdof = cdof && (dof - cdof) ? 1 : dof; 2540 if (dof) { 2541 if (bs < 0) { 2542 bs = bdof; 2543 } else if (bs != bdof) { 2544 bs = 1; 2545 } 2546 } 2547 } 2548 /* Must have same blocksize on all procs (some might have no points) */ 2549 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2550 bsLocal[1] = bs; 2551 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2552 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2553 else bs = bsMinMax[0]; 2554 bs = PetscMax(1, bs); 2555 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2556 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2557 PetscCall(MatSetBlockSize(*J, bs)); 2558 PetscCall(MatSetUp(*J)); 2559 } else { 2560 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2561 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2562 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2563 } 2564 { // Consolidate blocks 2565 PetscInt nblocks = 0; 2566 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2567 if (pblocks[i] == 0) continue; 2568 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2569 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2570 } 2571 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2572 } 2573 PetscCall(PetscFree(pblocks)); 2574 } 2575 PetscCall(MatSetDM(*J, dm)); 2576 PetscFunctionReturn(0); 2577 } 2578 2579 /*@ 2580 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2581 2582 Not collective 2583 2584 Input Parameter: 2585 . mesh - The DMPlex 2586 2587 Output Parameters: 2588 . subsection - The subdomain section 2589 2590 Level: developer 2591 2592 .seealso: 2593 @*/ 2594 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) { 2595 DM_Plex *mesh = (DM_Plex *)dm->data; 2596 2597 PetscFunctionBegin; 2598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2599 if (!mesh->subdomainSection) { 2600 PetscSection section; 2601 PetscSF sf; 2602 2603 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2604 PetscCall(DMGetLocalSection(dm, §ion)); 2605 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2606 PetscCall(PetscSFDestroy(&sf)); 2607 } 2608 *subsection = mesh->subdomainSection; 2609 PetscFunctionReturn(0); 2610 } 2611 2612 /*@ 2613 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2614 2615 Not collective 2616 2617 Input Parameter: 2618 . mesh - The DMPlex 2619 2620 Output Parameters: 2621 + pStart - The first mesh point 2622 - pEnd - The upper bound for mesh points 2623 2624 Level: beginner 2625 2626 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2627 @*/ 2628 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) { 2629 DM_Plex *mesh = (DM_Plex *)dm->data; 2630 2631 PetscFunctionBegin; 2632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2633 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2634 PetscFunctionReturn(0); 2635 } 2636 2637 /*@ 2638 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2639 2640 Not collective 2641 2642 Input Parameters: 2643 + mesh - The DMPlex 2644 . pStart - The first mesh point 2645 - pEnd - The upper bound for mesh points 2646 2647 Output Parameters: 2648 2649 Level: beginner 2650 2651 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2652 @*/ 2653 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) { 2654 DM_Plex *mesh = (DM_Plex *)dm->data; 2655 2656 PetscFunctionBegin; 2657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2658 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2659 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2660 PetscFunctionReturn(0); 2661 } 2662 2663 /*@ 2664 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2665 2666 Not collective 2667 2668 Input Parameters: 2669 + mesh - The DMPlex 2670 - p - The point, which must lie in the chart set with DMPlexSetChart() 2671 2672 Output Parameter: 2673 . size - The cone size for point p 2674 2675 Level: beginner 2676 2677 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2678 @*/ 2679 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) { 2680 DM_Plex *mesh = (DM_Plex *)dm->data; 2681 2682 PetscFunctionBegin; 2683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2684 PetscValidIntPointer(size, 3); 2685 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2686 PetscFunctionReturn(0); 2687 } 2688 2689 /*@ 2690 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2691 2692 Not collective 2693 2694 Input Parameters: 2695 + mesh - The DMPlex 2696 . p - The point, which must lie in the chart set with DMPlexSetChart() 2697 - size - The cone size for point p 2698 2699 Output Parameter: 2700 2701 Note: 2702 This should be called after DMPlexSetChart(). 2703 2704 Level: beginner 2705 2706 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2707 @*/ 2708 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) { 2709 DM_Plex *mesh = (DM_Plex *)dm->data; 2710 2711 PetscFunctionBegin; 2712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2713 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2714 PetscFunctionReturn(0); 2715 } 2716 2717 /*@ 2718 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2719 2720 Not collective 2721 2722 Input Parameters: 2723 + mesh - The DMPlex 2724 . p - The point, which must lie in the chart set with DMPlexSetChart() 2725 - size - The additional cone size for point p 2726 2727 Output Parameter: 2728 2729 Note: 2730 This should be called after DMPlexSetChart(). 2731 2732 Level: beginner 2733 2734 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2735 @*/ 2736 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) { 2737 DM_Plex *mesh = (DM_Plex *)dm->data; 2738 PetscFunctionBegin; 2739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2740 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2741 PetscFunctionReturn(0); 2742 } 2743 2744 /*@C 2745 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2746 2747 Not collective 2748 2749 Input Parameters: 2750 + dm - The DMPlex 2751 - p - The point, which must lie in the chart set with DMPlexSetChart() 2752 2753 Output Parameter: 2754 . cone - An array of points which are on the in-edges for point p 2755 2756 Level: beginner 2757 2758 Fortran Notes: 2759 Since it returns an array, this routine is only available in Fortran 90, and you must 2760 include petsc.h90 in your code. 2761 You must also call DMPlexRestoreCone() after you finish using the returned array. 2762 DMPlexRestoreCone() is not needed/available in C. 2763 2764 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2765 @*/ 2766 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) { 2767 DM_Plex *mesh = (DM_Plex *)dm->data; 2768 PetscInt off; 2769 2770 PetscFunctionBegin; 2771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2772 PetscValidPointer(cone, 3); 2773 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2774 *cone = &mesh->cones[off]; 2775 PetscFunctionReturn(0); 2776 } 2777 2778 /*@C 2779 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2780 2781 Not collective 2782 2783 Input Parameters: 2784 + dm - The DMPlex 2785 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2786 2787 Output Parameters: 2788 + pConesSection - PetscSection describing the layout of pCones 2789 - pCones - An array of points which are on the in-edges for the point set p 2790 2791 Level: intermediate 2792 2793 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2794 @*/ 2795 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) { 2796 PetscSection cs, newcs; 2797 PetscInt *cones; 2798 PetscInt *newarr = NULL; 2799 PetscInt n; 2800 2801 PetscFunctionBegin; 2802 PetscCall(DMPlexGetCones(dm, &cones)); 2803 PetscCall(DMPlexGetConeSection(dm, &cs)); 2804 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2805 if (pConesSection) *pConesSection = newcs; 2806 if (pCones) { 2807 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2808 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2809 } 2810 PetscFunctionReturn(0); 2811 } 2812 2813 /*@ 2814 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2815 2816 Not collective 2817 2818 Input Parameters: 2819 + dm - The DMPlex 2820 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2821 2822 Output Parameter: 2823 . expandedPoints - An array of vertices recursively expanded from input points 2824 2825 Level: advanced 2826 2827 Notes: 2828 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2829 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2830 2831 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2832 @*/ 2833 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) { 2834 IS *expandedPointsAll; 2835 PetscInt depth; 2836 2837 PetscFunctionBegin; 2838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2839 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2840 PetscValidPointer(expandedPoints, 3); 2841 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2842 *expandedPoints = expandedPointsAll[0]; 2843 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2844 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2845 PetscFunctionReturn(0); 2846 } 2847 2848 /*@ 2849 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 2850 2851 Not collective 2852 2853 Input Parameters: 2854 + dm - The DMPlex 2855 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2856 2857 Output Parameters: 2858 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2859 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2860 - sections - (optional) An array of sections which describe mappings from points to their cone points 2861 2862 Level: advanced 2863 2864 Notes: 2865 Like DMPlexGetConeTuple() but recursive. 2866 2867 Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 2868 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2869 2870 Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows: 2871 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2872 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2873 2874 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2875 @*/ 2876 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2877 const PetscInt *arr0 = NULL, *cone = NULL; 2878 PetscInt *arr = NULL, *newarr = NULL; 2879 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2880 IS *expandedPoints_; 2881 PetscSection *sections_; 2882 2883 PetscFunctionBegin; 2884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2885 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2886 if (depth) PetscValidIntPointer(depth, 3); 2887 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2888 if (sections) PetscValidPointer(sections, 5); 2889 PetscCall(ISGetLocalSize(points, &n)); 2890 PetscCall(ISGetIndices(points, &arr0)); 2891 PetscCall(DMPlexGetDepth(dm, &depth_)); 2892 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2893 PetscCall(PetscCalloc1(depth_, §ions_)); 2894 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2895 for (d = depth_ - 1; d >= 0; d--) { 2896 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2897 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2898 for (i = 0; i < n; i++) { 2899 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2900 if (arr[i] >= start && arr[i] < end) { 2901 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2902 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2903 } else { 2904 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2905 } 2906 } 2907 PetscCall(PetscSectionSetUp(sections_[d])); 2908 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2909 PetscCall(PetscMalloc1(newn, &newarr)); 2910 for (i = 0; i < n; i++) { 2911 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2912 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2913 if (cn > 1) { 2914 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2915 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2916 } else { 2917 newarr[co] = arr[i]; 2918 } 2919 } 2920 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2921 arr = newarr; 2922 n = newn; 2923 } 2924 PetscCall(ISRestoreIndices(points, &arr0)); 2925 *depth = depth_; 2926 if (expandedPoints) *expandedPoints = expandedPoints_; 2927 else { 2928 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2929 PetscCall(PetscFree(expandedPoints_)); 2930 } 2931 if (sections) *sections = sections_; 2932 else { 2933 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2934 PetscCall(PetscFree(sections_)); 2935 } 2936 PetscFunctionReturn(0); 2937 } 2938 2939 /*@ 2940 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2941 2942 Not collective 2943 2944 Input Parameters: 2945 + dm - The DMPlex 2946 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2947 2948 Output Parameters: 2949 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2950 . expandedPoints - (optional) An array of recursively expanded cones 2951 - sections - (optional) An array of sections which describe mappings from points to their cone points 2952 2953 Level: advanced 2954 2955 Notes: 2956 See DMPlexGetConeRecursive() for details. 2957 2958 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2959 @*/ 2960 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2961 PetscInt d, depth_; 2962 2963 PetscFunctionBegin; 2964 PetscCall(DMPlexGetDepth(dm, &depth_)); 2965 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2966 if (depth) *depth = 0; 2967 if (expandedPoints) { 2968 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2969 PetscCall(PetscFree(*expandedPoints)); 2970 } 2971 if (sections) { 2972 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2973 PetscCall(PetscFree(*sections)); 2974 } 2975 PetscFunctionReturn(0); 2976 } 2977 2978 /*@ 2979 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 2980 2981 Not collective 2982 2983 Input Parameters: 2984 + mesh - The DMPlex 2985 . p - The point, which must lie in the chart set with DMPlexSetChart() 2986 - cone - An array of points which are on the in-edges for point p 2987 2988 Output Parameter: 2989 2990 Note: 2991 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2992 2993 Level: beginner 2994 2995 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2996 @*/ 2997 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) { 2998 DM_Plex *mesh = (DM_Plex *)dm->data; 2999 PetscInt pStart, pEnd; 3000 PetscInt dof, off, c; 3001 3002 PetscFunctionBegin; 3003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3004 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3005 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3006 if (dof) PetscValidIntPointer(cone, 3); 3007 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3008 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3009 for (c = 0; c < dof; ++c) { 3010 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3011 mesh->cones[off + c] = cone[c]; 3012 } 3013 PetscFunctionReturn(0); 3014 } 3015 3016 /*@C 3017 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3018 3019 Not collective 3020 3021 Input Parameters: 3022 + mesh - The DMPlex 3023 - p - The point, which must lie in the chart set with DMPlexSetChart() 3024 3025 Output Parameter: 3026 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3027 integer giving the prescription for cone traversal. 3028 3029 Level: beginner 3030 3031 Notes: 3032 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3033 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3034 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3035 with the identity. 3036 3037 Fortran Notes: 3038 Since it returns an array, this routine is only available in Fortran 90, and you must 3039 include petsc.h90 in your code. 3040 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3041 DMPlexRestoreConeOrientation() is not needed/available in C. 3042 3043 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3044 @*/ 3045 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) { 3046 DM_Plex *mesh = (DM_Plex *)dm->data; 3047 PetscInt off; 3048 3049 PetscFunctionBegin; 3050 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3051 if (PetscDefined(USE_DEBUG)) { 3052 PetscInt dof; 3053 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3054 if (dof) PetscValidPointer(coneOrientation, 3); 3055 } 3056 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3057 3058 *coneOrientation = &mesh->coneOrientations[off]; 3059 PetscFunctionReturn(0); 3060 } 3061 3062 /*@ 3063 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3064 3065 Not collective 3066 3067 Input Parameters: 3068 + mesh - The DMPlex 3069 . p - The point, which must lie in the chart set with DMPlexSetChart() 3070 - coneOrientation - An array of orientations 3071 Output Parameter: 3072 3073 Notes: 3074 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3075 3076 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3077 3078 Level: beginner 3079 3080 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3081 @*/ 3082 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) { 3083 DM_Plex *mesh = (DM_Plex *)dm->data; 3084 PetscInt pStart, pEnd; 3085 PetscInt dof, off, c; 3086 3087 PetscFunctionBegin; 3088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3089 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3090 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3091 if (dof) PetscValidIntPointer(coneOrientation, 3); 3092 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3093 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3094 for (c = 0; c < dof; ++c) { 3095 PetscInt cdof, o = coneOrientation[c]; 3096 3097 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3098 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3099 mesh->coneOrientations[off + c] = o; 3100 } 3101 PetscFunctionReturn(0); 3102 } 3103 3104 /*@ 3105 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3106 3107 Not collective 3108 3109 Input Parameters: 3110 + mesh - The DMPlex 3111 . p - The point, which must lie in the chart set with DMPlexSetChart() 3112 . conePos - The local index in the cone where the point should be put 3113 - conePoint - The mesh point to insert 3114 3115 Level: beginner 3116 3117 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3118 @*/ 3119 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) { 3120 DM_Plex *mesh = (DM_Plex *)dm->data; 3121 PetscInt pStart, pEnd; 3122 PetscInt dof, off; 3123 3124 PetscFunctionBegin; 3125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3126 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3127 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3128 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3129 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3130 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3131 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3132 mesh->cones[off + conePos] = conePoint; 3133 PetscFunctionReturn(0); 3134 } 3135 3136 /*@ 3137 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3138 3139 Not collective 3140 3141 Input Parameters: 3142 + mesh - The DMPlex 3143 . p - The point, which must lie in the chart set with DMPlexSetChart() 3144 . conePos - The local index in the cone where the point should be put 3145 - coneOrientation - The point orientation to insert 3146 3147 Level: beginner 3148 3149 Notes: 3150 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3151 3152 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3153 @*/ 3154 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) { 3155 DM_Plex *mesh = (DM_Plex *)dm->data; 3156 PetscInt pStart, pEnd; 3157 PetscInt dof, off; 3158 3159 PetscFunctionBegin; 3160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3161 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3162 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3163 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3164 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3165 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3166 mesh->coneOrientations[off + conePos] = coneOrientation; 3167 PetscFunctionReturn(0); 3168 } 3169 3170 /*@ 3171 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3172 3173 Not collective 3174 3175 Input Parameters: 3176 + mesh - The DMPlex 3177 - p - The point, which must lie in the chart set with DMPlexSetChart() 3178 3179 Output Parameter: 3180 . size - The support size for point p 3181 3182 Level: beginner 3183 3184 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3185 @*/ 3186 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) { 3187 DM_Plex *mesh = (DM_Plex *)dm->data; 3188 3189 PetscFunctionBegin; 3190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3191 PetscValidIntPointer(size, 3); 3192 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3193 PetscFunctionReturn(0); 3194 } 3195 3196 /*@ 3197 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3198 3199 Not collective 3200 3201 Input Parameters: 3202 + mesh - The DMPlex 3203 . p - The point, which must lie in the chart set with DMPlexSetChart() 3204 - size - The support size for point p 3205 3206 Output Parameter: 3207 3208 Note: 3209 This should be called after DMPlexSetChart(). 3210 3211 Level: beginner 3212 3213 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3214 @*/ 3215 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) { 3216 DM_Plex *mesh = (DM_Plex *)dm->data; 3217 3218 PetscFunctionBegin; 3219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3220 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3221 PetscFunctionReturn(0); 3222 } 3223 3224 /*@C 3225 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3226 3227 Not collective 3228 3229 Input Parameters: 3230 + mesh - The DMPlex 3231 - p - The point, which must lie in the chart set with DMPlexSetChart() 3232 3233 Output Parameter: 3234 . support - An array of points which are on the out-edges for point p 3235 3236 Level: beginner 3237 3238 Fortran Notes: 3239 Since it returns an array, this routine is only available in Fortran 90, and you must 3240 include petsc.h90 in your code. 3241 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3242 DMPlexRestoreSupport() is not needed/available in C. 3243 3244 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3245 @*/ 3246 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) { 3247 DM_Plex *mesh = (DM_Plex *)dm->data; 3248 PetscInt off; 3249 3250 PetscFunctionBegin; 3251 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3252 PetscValidPointer(support, 3); 3253 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3254 *support = &mesh->supports[off]; 3255 PetscFunctionReturn(0); 3256 } 3257 3258 /*@ 3259 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3260 3261 Not collective 3262 3263 Input Parameters: 3264 + mesh - The DMPlex 3265 . p - The point, which must lie in the chart set with DMPlexSetChart() 3266 - support - An array of points which are on the out-edges for point p 3267 3268 Output Parameter: 3269 3270 Note: 3271 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3272 3273 Level: beginner 3274 3275 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3276 @*/ 3277 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) { 3278 DM_Plex *mesh = (DM_Plex *)dm->data; 3279 PetscInt pStart, pEnd; 3280 PetscInt dof, off, c; 3281 3282 PetscFunctionBegin; 3283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3284 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3285 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3286 if (dof) PetscValidIntPointer(support, 3); 3287 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3288 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3289 for (c = 0; c < dof; ++c) { 3290 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3291 mesh->supports[off + c] = support[c]; 3292 } 3293 PetscFunctionReturn(0); 3294 } 3295 3296 /*@ 3297 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3298 3299 Not collective 3300 3301 Input Parameters: 3302 + mesh - The DMPlex 3303 . p - The point, which must lie in the chart set with DMPlexSetChart() 3304 . supportPos - The local index in the cone where the point should be put 3305 - supportPoint - The mesh point to insert 3306 3307 Level: beginner 3308 3309 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3310 @*/ 3311 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) { 3312 DM_Plex *mesh = (DM_Plex *)dm->data; 3313 PetscInt pStart, pEnd; 3314 PetscInt dof, off; 3315 3316 PetscFunctionBegin; 3317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3318 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3319 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3320 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3321 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3322 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3323 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3324 mesh->supports[off + supportPos] = supportPoint; 3325 PetscFunctionReturn(0); 3326 } 3327 3328 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3329 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3330 switch (ct) { 3331 case DM_POLYTOPE_SEGMENT: 3332 if (o == -1) return -2; 3333 break; 3334 case DM_POLYTOPE_TRIANGLE: 3335 if (o == -3) return -1; 3336 if (o == -2) return -3; 3337 if (o == -1) return -2; 3338 break; 3339 case DM_POLYTOPE_QUADRILATERAL: 3340 if (o == -4) return -2; 3341 if (o == -3) return -1; 3342 if (o == -2) return -4; 3343 if (o == -1) return -3; 3344 break; 3345 default: return o; 3346 } 3347 return o; 3348 } 3349 3350 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3351 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3352 switch (ct) { 3353 case DM_POLYTOPE_SEGMENT: 3354 if ((o == -2) || (o == 1)) return -1; 3355 if (o == -1) return 0; 3356 break; 3357 case DM_POLYTOPE_TRIANGLE: 3358 if (o == -3) return -2; 3359 if (o == -2) return -1; 3360 if (o == -1) return -3; 3361 break; 3362 case DM_POLYTOPE_QUADRILATERAL: 3363 if (o == -4) return -2; 3364 if (o == -3) return -1; 3365 if (o == -2) return -4; 3366 if (o == -1) return -3; 3367 break; 3368 default: return o; 3369 } 3370 return o; 3371 } 3372 3373 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3374 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) { 3375 PetscInt pStart, pEnd, p; 3376 3377 PetscFunctionBegin; 3378 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3379 for (p = pStart; p < pEnd; ++p) { 3380 const PetscInt *cone, *ornt; 3381 PetscInt coneSize, c; 3382 3383 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3384 PetscCall(DMPlexGetCone(dm, p, &cone)); 3385 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3386 for (c = 0; c < coneSize; ++c) { 3387 DMPolytopeType ct; 3388 const PetscInt o = ornt[c]; 3389 3390 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3391 switch (ct) { 3392 case DM_POLYTOPE_SEGMENT: 3393 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3394 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3395 break; 3396 case DM_POLYTOPE_TRIANGLE: 3397 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3398 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3399 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3400 break; 3401 case DM_POLYTOPE_QUADRILATERAL: 3402 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3403 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3404 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3405 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3406 break; 3407 default: break; 3408 } 3409 } 3410 } 3411 PetscFunctionReturn(0); 3412 } 3413 3414 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3415 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3416 PetscInt *closure; 3417 const PetscInt *tmp = NULL, *tmpO = NULL; 3418 PetscInt off = 0, tmpSize, t; 3419 3420 PetscFunctionBeginHot; 3421 if (ornt) { 3422 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3423 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3424 } 3425 if (*points) { 3426 closure = *points; 3427 } else { 3428 PetscInt maxConeSize, maxSupportSize; 3429 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3430 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3431 } 3432 if (useCone) { 3433 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3434 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3435 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3436 } else { 3437 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3438 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3439 } 3440 if (ct == DM_POLYTOPE_UNKNOWN) { 3441 closure[off++] = p; 3442 closure[off++] = 0; 3443 for (t = 0; t < tmpSize; ++t) { 3444 closure[off++] = tmp[t]; 3445 closure[off++] = tmpO ? tmpO[t] : 0; 3446 } 3447 } else { 3448 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3449 3450 /* We assume that cells with a valid type have faces with a valid type */ 3451 closure[off++] = p; 3452 closure[off++] = ornt; 3453 for (t = 0; t < tmpSize; ++t) { 3454 DMPolytopeType ft; 3455 3456 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3457 closure[off++] = tmp[arr[t]]; 3458 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3459 } 3460 } 3461 if (numPoints) *numPoints = tmpSize + 1; 3462 if (points) *points = closure; 3463 PetscFunctionReturn(0); 3464 } 3465 3466 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3467 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) { 3468 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3469 const PetscInt *cone, *ornt; 3470 PetscInt *pts, *closure = NULL; 3471 DMPolytopeType ft; 3472 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3473 PetscInt dim, coneSize, c, d, clSize, cl; 3474 3475 PetscFunctionBeginHot; 3476 PetscCall(DMGetDimension(dm, &dim)); 3477 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3478 PetscCall(DMPlexGetCone(dm, point, &cone)); 3479 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3480 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3481 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3482 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3483 maxSize = PetscMax(coneSeries, supportSeries); 3484 if (*points) { 3485 pts = *points; 3486 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3487 c = 0; 3488 pts[c++] = point; 3489 pts[c++] = o; 3490 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3491 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3492 for (cl = 0; cl < clSize * 2; cl += 2) { 3493 pts[c++] = closure[cl]; 3494 pts[c++] = closure[cl + 1]; 3495 } 3496 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3497 for (cl = 0; cl < clSize * 2; cl += 2) { 3498 pts[c++] = closure[cl]; 3499 pts[c++] = closure[cl + 1]; 3500 } 3501 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3502 for (d = 2; d < coneSize; ++d) { 3503 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3504 pts[c++] = cone[arr[d * 2 + 0]]; 3505 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3506 } 3507 if (dim >= 3) { 3508 for (d = 2; d < coneSize; ++d) { 3509 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3510 const PetscInt *fcone, *fornt; 3511 PetscInt fconeSize, fc, i; 3512 3513 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3514 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3515 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3516 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3517 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3518 for (fc = 0; fc < fconeSize; ++fc) { 3519 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3520 const PetscInt co = farr[fc * 2 + 1]; 3521 3522 for (i = 0; i < c; i += 2) 3523 if (pts[i] == cp) break; 3524 if (i == c) { 3525 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3526 pts[c++] = cp; 3527 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3528 } 3529 } 3530 } 3531 } 3532 *numPoints = c / 2; 3533 *points = pts; 3534 PetscFunctionReturn(0); 3535 } 3536 3537 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3538 DMPolytopeType ct; 3539 PetscInt *closure, *fifo; 3540 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3541 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3542 PetscInt depth, maxSize; 3543 3544 PetscFunctionBeginHot; 3545 PetscCall(DMPlexGetDepth(dm, &depth)); 3546 if (depth == 1) { 3547 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3548 PetscFunctionReturn(0); 3549 } 3550 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3551 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3552 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3553 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3554 PetscFunctionReturn(0); 3555 } 3556 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3557 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3558 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3559 maxSize = PetscMax(coneSeries, supportSeries); 3560 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3561 if (*points) { 3562 closure = *points; 3563 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3564 closure[closureSize++] = p; 3565 closure[closureSize++] = ornt; 3566 fifo[fifoSize++] = p; 3567 fifo[fifoSize++] = ornt; 3568 fifo[fifoSize++] = ct; 3569 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3570 while (fifoSize - fifoStart) { 3571 const PetscInt q = fifo[fifoStart++]; 3572 const PetscInt o = fifo[fifoStart++]; 3573 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3574 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3575 const PetscInt *tmp, *tmpO; 3576 PetscInt tmpSize, t; 3577 3578 if (PetscDefined(USE_DEBUG)) { 3579 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3580 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3581 } 3582 if (useCone) { 3583 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3584 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3585 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3586 } else { 3587 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3588 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3589 tmpO = NULL; 3590 } 3591 for (t = 0; t < tmpSize; ++t) { 3592 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3593 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3594 const PetscInt cp = tmp[ip]; 3595 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3596 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3597 PetscInt c; 3598 3599 /* Check for duplicate */ 3600 for (c = 0; c < closureSize; c += 2) { 3601 if (closure[c] == cp) break; 3602 } 3603 if (c == closureSize) { 3604 closure[closureSize++] = cp; 3605 closure[closureSize++] = co; 3606 fifo[fifoSize++] = cp; 3607 fifo[fifoSize++] = co; 3608 fifo[fifoSize++] = ct; 3609 } 3610 } 3611 } 3612 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3613 if (numPoints) *numPoints = closureSize / 2; 3614 if (points) *points = closure; 3615 PetscFunctionReturn(0); 3616 } 3617 3618 /*@C 3619 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3620 3621 Not collective 3622 3623 Input Parameters: 3624 + dm - The DMPlex 3625 . p - The mesh point 3626 - useCone - PETSC_TRUE for the closure, otherwise return the star 3627 3628 Input/Output Parameter: 3629 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3630 if NULL on input, internal storage will be returned, otherwise the provided array is used 3631 3632 Output Parameter: 3633 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3634 3635 Note: 3636 If using internal storage (points is NULL on input), each call overwrites the last output. 3637 3638 Fortran Note: 3639 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3640 3641 Level: beginner 3642 3643 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3644 @*/ 3645 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3646 PetscFunctionBeginHot; 3647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3648 if (numPoints) PetscValidIntPointer(numPoints, 4); 3649 if (points) PetscValidPointer(points, 5); 3650 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3651 PetscFunctionReturn(0); 3652 } 3653 3654 /*@C 3655 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3656 3657 Not collective 3658 3659 Input Parameters: 3660 + dm - The DMPlex 3661 . p - The mesh point 3662 . useCone - PETSC_TRUE for the closure, otherwise return the star 3663 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3664 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3665 3666 Note: 3667 If not using internal storage (points is not NULL on input), this call is unnecessary 3668 3669 Level: beginner 3670 3671 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3672 @*/ 3673 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3674 PetscFunctionBeginHot; 3675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3676 if (numPoints) *numPoints = 0; 3677 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3678 PetscFunctionReturn(0); 3679 } 3680 3681 /*@ 3682 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3683 3684 Not collective 3685 3686 Input Parameter: 3687 . mesh - The DMPlex 3688 3689 Output Parameters: 3690 + maxConeSize - The maximum number of in-edges 3691 - maxSupportSize - The maximum number of out-edges 3692 3693 Level: beginner 3694 3695 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3696 @*/ 3697 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) { 3698 DM_Plex *mesh = (DM_Plex *)dm->data; 3699 3700 PetscFunctionBegin; 3701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3702 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3703 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3704 PetscFunctionReturn(0); 3705 } 3706 3707 PetscErrorCode DMSetUp_Plex(DM dm) { 3708 DM_Plex *mesh = (DM_Plex *)dm->data; 3709 PetscInt size, maxSupportSize; 3710 3711 PetscFunctionBegin; 3712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3713 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3714 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3715 PetscCall(PetscMalloc1(size, &mesh->cones)); 3716 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3717 PetscCall(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 } 3723 PetscFunctionReturn(0); 3724 } 3725 3726 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) { 3727 PetscFunctionBegin; 3728 if (subdm) PetscCall(DMClone(dm, subdm)); 3729 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3730 if (subdm) (*subdm)->useNatural = dm->useNatural; 3731 if (dm->useNatural && dm->sfMigration) { 3732 PetscSF sfNatural; 3733 3734 (*subdm)->sfMigration = dm->sfMigration; 3735 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3736 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3737 (*subdm)->sfNatural = sfNatural; 3738 } 3739 PetscFunctionReturn(0); 3740 } 3741 3742 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) { 3743 PetscInt i = 0; 3744 3745 PetscFunctionBegin; 3746 PetscCall(DMClone(dms[0], superdm)); 3747 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3748 (*superdm)->useNatural = PETSC_FALSE; 3749 for (i = 0; i < len; i++) { 3750 if (dms[i]->useNatural && dms[i]->sfMigration) { 3751 PetscSF sfNatural; 3752 3753 (*superdm)->sfMigration = dms[i]->sfMigration; 3754 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3755 (*superdm)->useNatural = PETSC_TRUE; 3756 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3757 (*superdm)->sfNatural = sfNatural; 3758 break; 3759 } 3760 } 3761 PetscFunctionReturn(0); 3762 } 3763 3764 /*@ 3765 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3766 3767 Not collective 3768 3769 Input Parameter: 3770 . mesh - The DMPlex 3771 3772 Output Parameter: 3773 3774 Note: 3775 This should be called after all calls to DMPlexSetCone() 3776 3777 Level: beginner 3778 3779 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3780 @*/ 3781 PetscErrorCode DMPlexSymmetrize(DM dm) { 3782 DM_Plex *mesh = (DM_Plex *)dm->data; 3783 PetscInt *offsets; 3784 PetscInt supportSize; 3785 PetscInt pStart, pEnd, p; 3786 3787 PetscFunctionBegin; 3788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3789 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3790 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3791 /* Calculate support sizes */ 3792 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3793 for (p = pStart; p < pEnd; ++p) { 3794 PetscInt dof, off, c; 3795 3796 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3797 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3798 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3799 } 3800 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3801 /* Calculate supports */ 3802 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3803 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3804 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3805 for (p = pStart; p < pEnd; ++p) { 3806 PetscInt dof, off, c; 3807 3808 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3809 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3810 for (c = off; c < off + dof; ++c) { 3811 const PetscInt q = mesh->cones[c]; 3812 PetscInt offS; 3813 3814 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3815 3816 mesh->supports[offS + offsets[q]] = p; 3817 ++offsets[q]; 3818 } 3819 } 3820 PetscCall(PetscFree(offsets)); 3821 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3822 PetscFunctionReturn(0); 3823 } 3824 3825 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) { 3826 IS stratumIS; 3827 3828 PetscFunctionBegin; 3829 if (pStart >= pEnd) PetscFunctionReturn(0); 3830 if (PetscDefined(USE_DEBUG)) { 3831 PetscInt qStart, qEnd, numLevels, level; 3832 PetscBool overlap = PETSC_FALSE; 3833 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3834 for (level = 0; level < numLevels; level++) { 3835 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3836 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 3837 overlap = PETSC_TRUE; 3838 break; 3839 } 3840 } 3841 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); 3842 } 3843 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 3844 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3845 PetscCall(ISDestroy(&stratumIS)); 3846 PetscFunctionReturn(0); 3847 } 3848 3849 /*@ 3850 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3851 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3852 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3853 the DAG. 3854 3855 Collective on dm 3856 3857 Input Parameter: 3858 . mesh - The DMPlex 3859 3860 Output Parameter: 3861 3862 Notes: 3863 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3864 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3865 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3866 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3867 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3868 3869 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3870 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3871 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 3872 to interpolate only that one (e0), so that 3873 $ cone(c0) = {e0, v2} 3874 $ cone(e0) = {v0, v1} 3875 If DMPlexStratify() is run on this mesh, it will give depths 3876 $ depth 0 = {v0, v1, v2} 3877 $ depth 1 = {e0, c0} 3878 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3879 3880 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3881 3882 Level: beginner 3883 3884 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3885 @*/ 3886 PetscErrorCode DMPlexStratify(DM dm) { 3887 DM_Plex *mesh = (DM_Plex *)dm->data; 3888 DMLabel label; 3889 PetscInt pStart, pEnd, p; 3890 PetscInt numRoots = 0, numLeaves = 0; 3891 3892 PetscFunctionBegin; 3893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3894 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 3895 3896 /* Create depth label */ 3897 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3898 PetscCall(DMCreateLabel(dm, "depth")); 3899 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3900 3901 { 3902 /* Initialize roots and count leaves */ 3903 PetscInt sMin = PETSC_MAX_INT; 3904 PetscInt sMax = PETSC_MIN_INT; 3905 PetscInt coneSize, supportSize; 3906 3907 for (p = pStart; p < pEnd; ++p) { 3908 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3909 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3910 if (!coneSize && supportSize) { 3911 sMin = PetscMin(p, sMin); 3912 sMax = PetscMax(p, sMax); 3913 ++numRoots; 3914 } else if (!supportSize && coneSize) { 3915 ++numLeaves; 3916 } else if (!supportSize && !coneSize) { 3917 /* Isolated points */ 3918 sMin = PetscMin(p, sMin); 3919 sMax = PetscMax(p, sMax); 3920 } 3921 } 3922 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 3923 } 3924 3925 if (numRoots + numLeaves == (pEnd - pStart)) { 3926 PetscInt sMin = PETSC_MAX_INT; 3927 PetscInt sMax = PETSC_MIN_INT; 3928 PetscInt coneSize, supportSize; 3929 3930 for (p = pStart; p < pEnd; ++p) { 3931 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3932 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3933 if (!supportSize && coneSize) { 3934 sMin = PetscMin(p, sMin); 3935 sMax = PetscMax(p, sMax); 3936 } 3937 } 3938 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 3939 } else { 3940 PetscInt level = 0; 3941 PetscInt qStart, qEnd, q; 3942 3943 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3944 while (qEnd > qStart) { 3945 PetscInt sMin = PETSC_MAX_INT; 3946 PetscInt sMax = PETSC_MIN_INT; 3947 3948 for (q = qStart; q < qEnd; ++q) { 3949 const PetscInt *support; 3950 PetscInt supportSize, s; 3951 3952 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3953 PetscCall(DMPlexGetSupport(dm, q, &support)); 3954 for (s = 0; s < supportSize; ++s) { 3955 sMin = PetscMin(support[s], sMin); 3956 sMax = PetscMax(support[s], sMax); 3957 } 3958 } 3959 PetscCall(DMLabelGetNumValues(label, &level)); 3960 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 3961 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3962 } 3963 } 3964 { /* just in case there is an empty process */ 3965 PetscInt numValues, maxValues = 0, v; 3966 3967 PetscCall(DMLabelGetNumValues(label, &numValues)); 3968 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 3969 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 3970 } 3971 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 3972 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 3973 PetscFunctionReturn(0); 3974 } 3975 3976 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) { 3977 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3978 PetscInt dim, depth, pheight, coneSize; 3979 3980 PetscFunctionBeginHot; 3981 PetscCall(DMGetDimension(dm, &dim)); 3982 PetscCall(DMPlexGetDepth(dm, &depth)); 3983 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3984 pheight = depth - pdepth; 3985 if (depth <= 1) { 3986 switch (pdepth) { 3987 case 0: ct = DM_POLYTOPE_POINT; break; 3988 case 1: 3989 switch (coneSize) { 3990 case 2: ct = DM_POLYTOPE_SEGMENT; break; 3991 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 3992 case 4: 3993 switch (dim) { 3994 case 2: ct = DM_POLYTOPE_QUADRILATERAL; break; 3995 case 3: ct = DM_POLYTOPE_TETRAHEDRON; break; 3996 default: break; 3997 } 3998 break; 3999 case 5: ct = DM_POLYTOPE_PYRAMID; break; 4000 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4001 case 8: ct = DM_POLYTOPE_HEXAHEDRON; break; 4002 default: break; 4003 } 4004 } 4005 } else { 4006 if (pdepth == 0) { 4007 ct = DM_POLYTOPE_POINT; 4008 } else if (pheight == 0) { 4009 switch (dim) { 4010 case 1: 4011 switch (coneSize) { 4012 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4013 default: break; 4014 } 4015 break; 4016 case 2: 4017 switch (coneSize) { 4018 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4019 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4020 default: break; 4021 } 4022 break; 4023 case 3: 4024 switch (coneSize) { 4025 case 4: ct = DM_POLYTOPE_TETRAHEDRON; break; 4026 case 5: { 4027 const PetscInt *cone; 4028 PetscInt faceConeSize; 4029 4030 PetscCall(DMPlexGetCone(dm, p, &cone)); 4031 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4032 switch (faceConeSize) { 4033 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4034 case 4: ct = DM_POLYTOPE_PYRAMID; break; 4035 } 4036 } break; 4037 case 6: ct = DM_POLYTOPE_HEXAHEDRON; break; 4038 default: break; 4039 } 4040 break; 4041 default: break; 4042 } 4043 } else if (pheight > 0) { 4044 switch (coneSize) { 4045 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4046 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4047 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4048 default: break; 4049 } 4050 } 4051 } 4052 *pt = ct; 4053 PetscFunctionReturn(0); 4054 } 4055 4056 /*@ 4057 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4058 4059 Collective on dm 4060 4061 Input Parameter: 4062 . mesh - The DMPlex 4063 4064 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4065 4066 Level: developer 4067 4068 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4069 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4070 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4071 4072 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4073 @*/ 4074 PetscErrorCode DMPlexComputeCellTypes(DM dm) { 4075 DM_Plex *mesh; 4076 DMLabel ctLabel; 4077 PetscInt pStart, pEnd, p; 4078 4079 PetscFunctionBegin; 4080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4081 mesh = (DM_Plex *)dm->data; 4082 PetscCall(DMCreateLabel(dm, "celltype")); 4083 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4084 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4085 for (p = pStart; p < pEnd; ++p) { 4086 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4087 PetscInt pdepth; 4088 4089 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4090 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4091 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4092 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4093 } 4094 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4095 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4096 PetscFunctionReturn(0); 4097 } 4098 4099 /*@C 4100 DMPlexGetJoin - Get an array for the join of the set of points 4101 4102 Not Collective 4103 4104 Input Parameters: 4105 + dm - The DMPlex object 4106 . numPoints - The number of input points for the join 4107 - points - The input points 4108 4109 Output Parameters: 4110 + numCoveredPoints - The number of points in the join 4111 - coveredPoints - The points in the join 4112 4113 Level: intermediate 4114 4115 Note: Currently, this is restricted to a single level join 4116 4117 Fortran Notes: 4118 Since it returns an array, this routine is only available in Fortran 90, and you must 4119 include petsc.h90 in your code. 4120 4121 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4122 4123 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4124 @*/ 4125 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4126 DM_Plex *mesh = (DM_Plex *)dm->data; 4127 PetscInt *join[2]; 4128 PetscInt joinSize, i = 0; 4129 PetscInt dof, off, p, c, m; 4130 PetscInt maxSupportSize; 4131 4132 PetscFunctionBegin; 4133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4134 PetscValidIntPointer(points, 3); 4135 PetscValidIntPointer(numCoveredPoints, 4); 4136 PetscValidPointer(coveredPoints, 5); 4137 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4138 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4139 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4140 /* Copy in support of first point */ 4141 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4142 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4143 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4144 /* Check each successive support */ 4145 for (p = 1; p < numPoints; ++p) { 4146 PetscInt newJoinSize = 0; 4147 4148 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4149 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4150 for (c = 0; c < dof; ++c) { 4151 const PetscInt point = mesh->supports[off + c]; 4152 4153 for (m = 0; m < joinSize; ++m) { 4154 if (point == join[i][m]) { 4155 join[1 - i][newJoinSize++] = point; 4156 break; 4157 } 4158 } 4159 } 4160 joinSize = newJoinSize; 4161 i = 1 - i; 4162 } 4163 *numCoveredPoints = joinSize; 4164 *coveredPoints = join[i]; 4165 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4166 PetscFunctionReturn(0); 4167 } 4168 4169 /*@C 4170 DMPlexRestoreJoin - Restore an array for the join of the set of points 4171 4172 Not Collective 4173 4174 Input Parameters: 4175 + dm - The DMPlex object 4176 . numPoints - The number of input points for the join 4177 - points - The input points 4178 4179 Output Parameters: 4180 + numCoveredPoints - The number of points in the join 4181 - coveredPoints - The points in the join 4182 4183 Fortran Notes: 4184 Since it returns an array, this routine is only available in Fortran 90, and you must 4185 include petsc.h90 in your code. 4186 4187 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4188 4189 Level: intermediate 4190 4191 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4192 @*/ 4193 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4194 PetscFunctionBegin; 4195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4196 if (points) PetscValidIntPointer(points, 3); 4197 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4198 PetscValidPointer(coveredPoints, 5); 4199 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4200 if (numCoveredPoints) *numCoveredPoints = 0; 4201 PetscFunctionReturn(0); 4202 } 4203 4204 /*@C 4205 DMPlexGetFullJoin - Get an array for the join of the set of points 4206 4207 Not Collective 4208 4209 Input Parameters: 4210 + dm - The DMPlex object 4211 . numPoints - The number of input points for the join 4212 - points - The input points 4213 4214 Output Parameters: 4215 + numCoveredPoints - The number of points in the join 4216 - coveredPoints - The points in the join 4217 4218 Fortran Notes: 4219 Since it returns an array, this routine is only available in Fortran 90, and you must 4220 include petsc.h90 in your code. 4221 4222 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4223 4224 Level: intermediate 4225 4226 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4227 @*/ 4228 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4229 PetscInt *offsets, **closures; 4230 PetscInt *join[2]; 4231 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4232 PetscInt p, d, c, m, ms; 4233 4234 PetscFunctionBegin; 4235 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4236 PetscValidIntPointer(points, 3); 4237 PetscValidIntPointer(numCoveredPoints, 4); 4238 PetscValidPointer(coveredPoints, 5); 4239 4240 PetscCall(DMPlexGetDepth(dm, &depth)); 4241 PetscCall(PetscCalloc1(numPoints, &closures)); 4242 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4243 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4244 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4245 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4246 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4247 4248 for (p = 0; p < numPoints; ++p) { 4249 PetscInt closureSize; 4250 4251 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4252 4253 offsets[p * (depth + 2) + 0] = 0; 4254 for (d = 0; d < depth + 1; ++d) { 4255 PetscInt pStart, pEnd, i; 4256 4257 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4258 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4259 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4260 offsets[p * (depth + 2) + d + 1] = i; 4261 break; 4262 } 4263 } 4264 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4265 } 4266 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); 4267 } 4268 for (d = 0; d < depth + 1; ++d) { 4269 PetscInt dof; 4270 4271 /* Copy in support of first point */ 4272 dof = offsets[d + 1] - offsets[d]; 4273 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4274 /* Check each successive cone */ 4275 for (p = 1; p < numPoints && joinSize; ++p) { 4276 PetscInt newJoinSize = 0; 4277 4278 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4279 for (c = 0; c < dof; ++c) { 4280 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4281 4282 for (m = 0; m < joinSize; ++m) { 4283 if (point == join[i][m]) { 4284 join[1 - i][newJoinSize++] = point; 4285 break; 4286 } 4287 } 4288 } 4289 joinSize = newJoinSize; 4290 i = 1 - i; 4291 } 4292 if (joinSize) break; 4293 } 4294 *numCoveredPoints = joinSize; 4295 *coveredPoints = join[i]; 4296 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4297 PetscCall(PetscFree(closures)); 4298 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4299 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4300 PetscFunctionReturn(0); 4301 } 4302 4303 /*@C 4304 DMPlexGetMeet - Get an array for the meet of the set of points 4305 4306 Not Collective 4307 4308 Input Parameters: 4309 + dm - The DMPlex object 4310 . numPoints - The number of input points for the meet 4311 - points - The input points 4312 4313 Output Parameters: 4314 + numCoveredPoints - The number of points in the meet 4315 - coveredPoints - The points in the meet 4316 4317 Level: intermediate 4318 4319 Note: Currently, this is restricted to a single level meet 4320 4321 Fortran Notes: 4322 Since it returns an array, this routine is only available in Fortran 90, and you must 4323 include petsc.h90 in your code. 4324 4325 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4326 4327 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4328 @*/ 4329 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) { 4330 DM_Plex *mesh = (DM_Plex *)dm->data; 4331 PetscInt *meet[2]; 4332 PetscInt meetSize, i = 0; 4333 PetscInt dof, off, p, c, m; 4334 PetscInt maxConeSize; 4335 4336 PetscFunctionBegin; 4337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4338 PetscValidIntPointer(points, 3); 4339 PetscValidIntPointer(numCoveringPoints, 4); 4340 PetscValidPointer(coveringPoints, 5); 4341 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4342 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4343 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4344 /* Copy in cone of first point */ 4345 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4346 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4347 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4348 /* Check each successive cone */ 4349 for (p = 1; p < numPoints; ++p) { 4350 PetscInt newMeetSize = 0; 4351 4352 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4353 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4354 for (c = 0; c < dof; ++c) { 4355 const PetscInt point = mesh->cones[off + c]; 4356 4357 for (m = 0; m < meetSize; ++m) { 4358 if (point == meet[i][m]) { 4359 meet[1 - i][newMeetSize++] = point; 4360 break; 4361 } 4362 } 4363 } 4364 meetSize = newMeetSize; 4365 i = 1 - i; 4366 } 4367 *numCoveringPoints = meetSize; 4368 *coveringPoints = meet[i]; 4369 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4370 PetscFunctionReturn(0); 4371 } 4372 4373 /*@C 4374 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4375 4376 Not Collective 4377 4378 Input Parameters: 4379 + dm - The DMPlex object 4380 . numPoints - The number of input points for the meet 4381 - points - The input points 4382 4383 Output Parameters: 4384 + numCoveredPoints - The number of points in the meet 4385 - coveredPoints - The points in the meet 4386 4387 Level: intermediate 4388 4389 Fortran Notes: 4390 Since it returns an array, this routine is only available in Fortran 90, and you must 4391 include petsc.h90 in your code. 4392 4393 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4394 4395 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4396 @*/ 4397 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4398 PetscFunctionBegin; 4399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4400 if (points) PetscValidIntPointer(points, 3); 4401 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4402 PetscValidPointer(coveredPoints, 5); 4403 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4404 if (numCoveredPoints) *numCoveredPoints = 0; 4405 PetscFunctionReturn(0); 4406 } 4407 4408 /*@C 4409 DMPlexGetFullMeet - Get an array for the meet of the set of points 4410 4411 Not Collective 4412 4413 Input Parameters: 4414 + dm - The DMPlex object 4415 . numPoints - The number of input points for the meet 4416 - points - The input points 4417 4418 Output Parameters: 4419 + numCoveredPoints - The number of points in the meet 4420 - coveredPoints - The points in the meet 4421 4422 Level: intermediate 4423 4424 Fortran Notes: 4425 Since it returns an array, this routine is only available in Fortran 90, and you must 4426 include petsc.h90 in your code. 4427 4428 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4429 4430 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4431 @*/ 4432 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4433 PetscInt *offsets, **closures; 4434 PetscInt *meet[2]; 4435 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4436 PetscInt p, h, c, m, mc; 4437 4438 PetscFunctionBegin; 4439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4440 PetscValidIntPointer(points, 3); 4441 PetscValidIntPointer(numCoveredPoints, 4); 4442 PetscValidPointer(coveredPoints, 5); 4443 4444 PetscCall(DMPlexGetDepth(dm, &height)); 4445 PetscCall(PetscMalloc1(numPoints, &closures)); 4446 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4447 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4448 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4449 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4450 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4451 4452 for (p = 0; p < numPoints; ++p) { 4453 PetscInt closureSize; 4454 4455 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4456 4457 offsets[p * (height + 2) + 0] = 0; 4458 for (h = 0; h < height + 1; ++h) { 4459 PetscInt pStart, pEnd, i; 4460 4461 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4462 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4463 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4464 offsets[p * (height + 2) + h + 1] = i; 4465 break; 4466 } 4467 } 4468 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4469 } 4470 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); 4471 } 4472 for (h = 0; h < height + 1; ++h) { 4473 PetscInt dof; 4474 4475 /* Copy in cone of first point */ 4476 dof = offsets[h + 1] - offsets[h]; 4477 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4478 /* Check each successive cone */ 4479 for (p = 1; p < numPoints && meetSize; ++p) { 4480 PetscInt newMeetSize = 0; 4481 4482 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4483 for (c = 0; c < dof; ++c) { 4484 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4485 4486 for (m = 0; m < meetSize; ++m) { 4487 if (point == meet[i][m]) { 4488 meet[1 - i][newMeetSize++] = point; 4489 break; 4490 } 4491 } 4492 } 4493 meetSize = newMeetSize; 4494 i = 1 - i; 4495 } 4496 if (meetSize) break; 4497 } 4498 *numCoveredPoints = meetSize; 4499 *coveredPoints = meet[i]; 4500 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4501 PetscCall(PetscFree(closures)); 4502 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4503 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4504 PetscFunctionReturn(0); 4505 } 4506 4507 /*@C 4508 DMPlexEqual - Determine if two DMs have the same topology 4509 4510 Not Collective 4511 4512 Input Parameters: 4513 + dmA - A DMPlex object 4514 - dmB - A DMPlex object 4515 4516 Output Parameters: 4517 . equal - PETSC_TRUE if the topologies are identical 4518 4519 Level: intermediate 4520 4521 Notes: 4522 We are not solving graph isomorphism, so we do not permutation. 4523 4524 .seealso: `DMPlexGetCone()` 4525 @*/ 4526 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) { 4527 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4528 4529 PetscFunctionBegin; 4530 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4531 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4532 PetscValidBoolPointer(equal, 3); 4533 4534 *equal = PETSC_FALSE; 4535 PetscCall(DMPlexGetDepth(dmA, &depth)); 4536 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4537 if (depth != depthB) PetscFunctionReturn(0); 4538 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4539 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4540 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4541 for (p = pStart; p < pEnd; ++p) { 4542 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4543 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4544 4545 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4546 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4547 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4548 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4549 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4550 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4551 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4552 for (c = 0; c < coneSize; ++c) { 4553 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4554 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4555 } 4556 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4557 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4558 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4559 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4560 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4561 for (s = 0; s < supportSize; ++s) { 4562 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4563 } 4564 } 4565 *equal = PETSC_TRUE; 4566 PetscFunctionReturn(0); 4567 } 4568 4569 /*@C 4570 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4571 4572 Not Collective 4573 4574 Input Parameters: 4575 + dm - The DMPlex 4576 . cellDim - The cell dimension 4577 - numCorners - The number of vertices on a cell 4578 4579 Output Parameters: 4580 . numFaceVertices - The number of vertices on a face 4581 4582 Level: developer 4583 4584 Notes: 4585 Of course this can only work for a restricted set of symmetric shapes 4586 4587 .seealso: `DMPlexGetCone()` 4588 @*/ 4589 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) { 4590 MPI_Comm comm; 4591 4592 PetscFunctionBegin; 4593 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4594 PetscValidIntPointer(numFaceVertices, 4); 4595 switch (cellDim) { 4596 case 0: *numFaceVertices = 0; break; 4597 case 1: *numFaceVertices = 1; break; 4598 case 2: 4599 switch (numCorners) { 4600 case 3: /* triangle */ 4601 *numFaceVertices = 2; /* Edge has 2 vertices */ 4602 break; 4603 case 4: /* quadrilateral */ 4604 *numFaceVertices = 2; /* Edge has 2 vertices */ 4605 break; 4606 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4607 *numFaceVertices = 3; /* Edge has 3 vertices */ 4608 break; 4609 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4610 *numFaceVertices = 3; /* Edge has 3 vertices */ 4611 break; 4612 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4613 } 4614 break; 4615 case 3: 4616 switch (numCorners) { 4617 case 4: /* tetradehdron */ 4618 *numFaceVertices = 3; /* Face has 3 vertices */ 4619 break; 4620 case 6: /* tet cohesive cells */ 4621 *numFaceVertices = 4; /* Face has 4 vertices */ 4622 break; 4623 case 8: /* hexahedron */ 4624 *numFaceVertices = 4; /* Face has 4 vertices */ 4625 break; 4626 case 9: /* tet cohesive Lagrange cells */ 4627 *numFaceVertices = 6; /* Face has 6 vertices */ 4628 break; 4629 case 10: /* quadratic tetrahedron */ 4630 *numFaceVertices = 6; /* Face has 6 vertices */ 4631 break; 4632 case 12: /* hex cohesive Lagrange cells */ 4633 *numFaceVertices = 6; /* Face has 6 vertices */ 4634 break; 4635 case 18: /* quadratic tet cohesive Lagrange cells */ 4636 *numFaceVertices = 6; /* Face has 6 vertices */ 4637 break; 4638 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4639 *numFaceVertices = 9; /* Face has 9 vertices */ 4640 break; 4641 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4642 } 4643 break; 4644 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4645 } 4646 PetscFunctionReturn(0); 4647 } 4648 4649 /*@ 4650 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4651 4652 Not Collective 4653 4654 Input Parameter: 4655 . dm - The DMPlex object 4656 4657 Output Parameter: 4658 . depthLabel - The DMLabel recording point depth 4659 4660 Level: developer 4661 4662 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4663 @*/ 4664 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) { 4665 PetscFunctionBegin; 4666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4667 PetscValidPointer(depthLabel, 2); 4668 *depthLabel = dm->depthLabel; 4669 PetscFunctionReturn(0); 4670 } 4671 4672 /*@ 4673 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4674 4675 Not Collective 4676 4677 Input Parameter: 4678 . dm - The DMPlex object 4679 4680 Output Parameter: 4681 . depth - The number of strata (breadth first levels) in the DAG 4682 4683 Level: developer 4684 4685 Notes: 4686 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4687 The point depth is described more in detail in DMPlexGetDepthStratum(). 4688 An empty mesh gives -1. 4689 4690 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4691 @*/ 4692 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) { 4693 DMLabel label; 4694 PetscInt d = 0; 4695 4696 PetscFunctionBegin; 4697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4698 PetscValidIntPointer(depth, 2); 4699 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4700 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4701 *depth = d - 1; 4702 PetscFunctionReturn(0); 4703 } 4704 4705 /*@ 4706 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4707 4708 Not Collective 4709 4710 Input Parameters: 4711 + dm - The DMPlex object 4712 - depth - The requested depth 4713 4714 Output Parameters: 4715 + start - The first point at this depth 4716 - end - One beyond the last point at this depth 4717 4718 Notes: 4719 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4720 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4721 higher dimension, e.g., "edges". 4722 4723 Level: developer 4724 4725 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4726 @*/ 4727 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) { 4728 DMLabel label; 4729 PetscInt pStart, pEnd; 4730 4731 PetscFunctionBegin; 4732 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4733 if (start) { 4734 PetscValidIntPointer(start, 3); 4735 *start = 0; 4736 } 4737 if (end) { 4738 PetscValidIntPointer(end, 4); 4739 *end = 0; 4740 } 4741 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4742 if (pStart == pEnd) PetscFunctionReturn(0); 4743 if (depth < 0) { 4744 if (start) *start = pStart; 4745 if (end) *end = pEnd; 4746 PetscFunctionReturn(0); 4747 } 4748 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4749 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4750 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4751 PetscFunctionReturn(0); 4752 } 4753 4754 /*@ 4755 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4756 4757 Not Collective 4758 4759 Input Parameters: 4760 + dm - The DMPlex object 4761 - height - The requested height 4762 4763 Output Parameters: 4764 + start - The first point at this height 4765 - end - One beyond the last point at this height 4766 4767 Notes: 4768 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4769 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4770 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4771 4772 Level: developer 4773 4774 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4775 @*/ 4776 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) { 4777 DMLabel label; 4778 PetscInt depth, pStart, pEnd; 4779 4780 PetscFunctionBegin; 4781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4782 if (start) { 4783 PetscValidIntPointer(start, 3); 4784 *start = 0; 4785 } 4786 if (end) { 4787 PetscValidIntPointer(end, 4); 4788 *end = 0; 4789 } 4790 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4791 if (pStart == pEnd) PetscFunctionReturn(0); 4792 if (height < 0) { 4793 if (start) *start = pStart; 4794 if (end) *end = pEnd; 4795 PetscFunctionReturn(0); 4796 } 4797 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4798 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4799 PetscCall(DMLabelGetNumValues(label, &depth)); 4800 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 4801 PetscFunctionReturn(0); 4802 } 4803 4804 /*@ 4805 DMPlexGetPointDepth - Get the depth of a given point 4806 4807 Not Collective 4808 4809 Input Parameters: 4810 + dm - The DMPlex object 4811 - point - The point 4812 4813 Output Parameter: 4814 . depth - The depth of the point 4815 4816 Level: intermediate 4817 4818 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4819 @*/ 4820 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) { 4821 PetscFunctionBegin; 4822 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4823 PetscValidIntPointer(depth, 3); 4824 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4825 PetscFunctionReturn(0); 4826 } 4827 4828 /*@ 4829 DMPlexGetPointHeight - Get the height of a given point 4830 4831 Not Collective 4832 4833 Input Parameters: 4834 + dm - The DMPlex object 4835 - point - The point 4836 4837 Output Parameter: 4838 . height - The height of the point 4839 4840 Level: intermediate 4841 4842 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4843 @*/ 4844 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) { 4845 PetscInt n, pDepth; 4846 4847 PetscFunctionBegin; 4848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4849 PetscValidIntPointer(height, 3); 4850 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4851 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4852 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4853 PetscFunctionReturn(0); 4854 } 4855 4856 /*@ 4857 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4858 4859 Not Collective 4860 4861 Input Parameter: 4862 . dm - The DMPlex object 4863 4864 Output Parameter: 4865 . celltypeLabel - The DMLabel recording cell polytope type 4866 4867 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4868 DMCreateLabel(dm, "celltype") beforehand. 4869 4870 Level: developer 4871 4872 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4873 @*/ 4874 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) { 4875 PetscFunctionBegin; 4876 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4877 PetscValidPointer(celltypeLabel, 2); 4878 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4879 *celltypeLabel = dm->celltypeLabel; 4880 PetscFunctionReturn(0); 4881 } 4882 4883 /*@ 4884 DMPlexGetCellType - Get the polytope type of a given cell 4885 4886 Not Collective 4887 4888 Input Parameters: 4889 + dm - The DMPlex object 4890 - cell - The cell 4891 4892 Output Parameter: 4893 . celltype - The polytope type of the cell 4894 4895 Level: intermediate 4896 4897 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4898 @*/ 4899 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) { 4900 DMLabel label; 4901 PetscInt ct; 4902 4903 PetscFunctionBegin; 4904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4905 PetscValidPointer(celltype, 3); 4906 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4907 PetscCall(DMLabelGetValue(label, cell, &ct)); 4908 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4909 *celltype = (DMPolytopeType)ct; 4910 PetscFunctionReturn(0); 4911 } 4912 4913 /*@ 4914 DMPlexSetCellType - Set the polytope type of a given cell 4915 4916 Not Collective 4917 4918 Input Parameters: 4919 + dm - The DMPlex object 4920 . cell - The cell 4921 - celltype - The polytope type of the cell 4922 4923 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4924 is executed. This function will override the computed type. However, if automatic classification will not succeed 4925 and a user wants to manually specify all types, the classification must be disabled by calling 4926 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4927 4928 Level: advanced 4929 4930 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 4931 @*/ 4932 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) { 4933 DMLabel label; 4934 4935 PetscFunctionBegin; 4936 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4937 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4938 PetscCall(DMLabelSetValue(label, cell, celltype)); 4939 PetscFunctionReturn(0); 4940 } 4941 4942 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) { 4943 PetscSection section, s; 4944 Mat m; 4945 PetscInt maxHeight; 4946 4947 PetscFunctionBegin; 4948 PetscCall(DMClone(dm, cdm)); 4949 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 4950 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 4951 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 4952 PetscCall(DMSetLocalSection(*cdm, section)); 4953 PetscCall(PetscSectionDestroy(§ion)); 4954 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 4955 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 4956 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 4957 PetscCall(PetscSectionDestroy(&s)); 4958 PetscCall(MatDestroy(&m)); 4959 4960 PetscCall(DMSetNumFields(*cdm, 1)); 4961 PetscCall(DMCreateDS(*cdm)); 4962 PetscFunctionReturn(0); 4963 } 4964 4965 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) { 4966 Vec coordsLocal, cellCoordsLocal; 4967 DM coordsDM, cellCoordsDM; 4968 4969 PetscFunctionBegin; 4970 *field = NULL; 4971 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 4972 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 4973 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 4974 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 4975 if (coordsLocal && coordsDM) { 4976 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 4977 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 4978 } 4979 PetscFunctionReturn(0); 4980 } 4981 4982 /*@C 4983 DMPlexGetConeSection - Return a section which describes the layout of cone data 4984 4985 Not Collective 4986 4987 Input Parameters: 4988 . dm - The DMPlex object 4989 4990 Output Parameter: 4991 . section - The PetscSection object 4992 4993 Level: developer 4994 4995 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 4996 @*/ 4997 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) { 4998 DM_Plex *mesh = (DM_Plex *)dm->data; 4999 5000 PetscFunctionBegin; 5001 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5002 if (section) *section = mesh->coneSection; 5003 PetscFunctionReturn(0); 5004 } 5005 5006 /*@C 5007 DMPlexGetSupportSection - Return a section which describes the layout of support data 5008 5009 Not Collective 5010 5011 Input Parameters: 5012 . dm - The DMPlex object 5013 5014 Output Parameter: 5015 . section - The PetscSection object 5016 5017 Level: developer 5018 5019 .seealso: `DMPlexGetConeSection()` 5020 @*/ 5021 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) { 5022 DM_Plex *mesh = (DM_Plex *)dm->data; 5023 5024 PetscFunctionBegin; 5025 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5026 if (section) *section = mesh->supportSection; 5027 PetscFunctionReturn(0); 5028 } 5029 5030 /*@C 5031 DMPlexGetCones - Return cone data 5032 5033 Not Collective 5034 5035 Input Parameters: 5036 . dm - The DMPlex object 5037 5038 Output Parameter: 5039 . cones - The cone for each point 5040 5041 Level: developer 5042 5043 .seealso: `DMPlexGetConeSection()` 5044 @*/ 5045 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) { 5046 DM_Plex *mesh = (DM_Plex *)dm->data; 5047 5048 PetscFunctionBegin; 5049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5050 if (cones) *cones = mesh->cones; 5051 PetscFunctionReturn(0); 5052 } 5053 5054 /*@C 5055 DMPlexGetConeOrientations - Return cone orientation data 5056 5057 Not Collective 5058 5059 Input Parameters: 5060 . dm - The DMPlex object 5061 5062 Output Parameter: 5063 . coneOrientations - The array of cone orientations for all points 5064 5065 Level: developer 5066 5067 Notes: 5068 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5069 5070 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5071 5072 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5073 @*/ 5074 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) { 5075 DM_Plex *mesh = (DM_Plex *)dm->data; 5076 5077 PetscFunctionBegin; 5078 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5079 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5080 PetscFunctionReturn(0); 5081 } 5082 5083 /******************************** FEM Support **********************************/ 5084 5085 /* 5086 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5087 representing a line in the section. 5088 */ 5089 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) { 5090 PetscFunctionBeginHot; 5091 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5092 if (line < 0) { 5093 *k = 0; 5094 *Nc = 0; 5095 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5096 *k = 1; 5097 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5098 /* An order k SEM disc has k-1 dofs on an edge */ 5099 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5100 *k = *k / *Nc + 1; 5101 } 5102 PetscFunctionReturn(0); 5103 } 5104 5105 /*@ 5106 5107 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5108 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5109 section provided (or the section of the DM). 5110 5111 Input Parameters: 5112 + dm - The DM 5113 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5114 - section - The PetscSection to reorder, or NULL for the default section 5115 5116 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5117 degree of the basis. 5118 5119 Example: 5120 A typical interpolated single-quad mesh might order points as 5121 .vb 5122 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5123 5124 v4 -- e6 -- v3 5125 | | 5126 e7 c0 e8 5127 | | 5128 v1 -- e5 -- v2 5129 .ve 5130 5131 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5132 dofs in the order of points, e.g., 5133 .vb 5134 c0 -> [0,1,2,3] 5135 v1 -> [4] 5136 ... 5137 e5 -> [8, 9] 5138 .ve 5139 5140 which corresponds to the dofs 5141 .vb 5142 6 10 11 7 5143 13 2 3 15 5144 12 0 1 14 5145 4 8 9 5 5146 .ve 5147 5148 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5149 .vb 5150 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5151 .ve 5152 5153 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5154 .vb 5155 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5156 .ve 5157 5158 Level: developer 5159 5160 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5161 @*/ 5162 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) { 5163 DMLabel label; 5164 PetscInt dim, depth = -1, eStart = -1, Nf; 5165 PetscBool vertexchart; 5166 5167 PetscFunctionBegin; 5168 PetscCall(DMGetDimension(dm, &dim)); 5169 if (dim < 1) PetscFunctionReturn(0); 5170 if (point < 0) { 5171 PetscInt sStart, sEnd; 5172 5173 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5174 point = sEnd - sStart ? sStart : point; 5175 } 5176 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5177 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5178 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5179 if (depth == 1) { 5180 eStart = point; 5181 } else if (depth == dim) { 5182 const PetscInt *cone; 5183 5184 PetscCall(DMPlexGetCone(dm, point, &cone)); 5185 if (dim == 2) eStart = cone[0]; 5186 else if (dim == 3) { 5187 const PetscInt *cone2; 5188 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5189 eStart = cone2[0]; 5190 } 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); 5191 } 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); 5192 { /* Determine whether the chart covers all points or just vertices. */ 5193 PetscInt pStart, pEnd, cStart, cEnd; 5194 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5195 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5196 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5197 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5198 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5199 } 5200 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5201 for (PetscInt d = 1; d <= dim; d++) { 5202 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5203 PetscInt *perm; 5204 5205 for (f = 0; f < Nf; ++f) { 5206 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5207 size += PetscPowInt(k + 1, d) * Nc; 5208 } 5209 PetscCall(PetscMalloc1(size, &perm)); 5210 for (f = 0; f < Nf; ++f) { 5211 switch (d) { 5212 case 1: 5213 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5214 /* 5215 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5216 We want [ vtx0; edge of length k-1; vtx1 ] 5217 */ 5218 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5219 for (i = 0; i < k - 1; i++) 5220 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5221 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5222 foffset = offset; 5223 break; 5224 case 2: 5225 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5226 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5227 /* The SEM order is 5228 5229 v_lb, {e_b}, v_rb, 5230 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5231 v_lt, reverse {e_t}, v_rt 5232 */ 5233 { 5234 const PetscInt of = 0; 5235 const PetscInt oeb = of + PetscSqr(k - 1); 5236 const PetscInt oer = oeb + (k - 1); 5237 const PetscInt oet = oer + (k - 1); 5238 const PetscInt oel = oet + (k - 1); 5239 const PetscInt ovlb = oel + (k - 1); 5240 const PetscInt ovrb = ovlb + 1; 5241 const PetscInt ovrt = ovrb + 1; 5242 const PetscInt ovlt = ovrt + 1; 5243 PetscInt o; 5244 5245 /* bottom */ 5246 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5247 for (o = oeb; o < oer; ++o) 5248 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5250 /* middle */ 5251 for (i = 0; i < k - 1; ++i) { 5252 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5253 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5254 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5255 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5256 } 5257 /* top */ 5258 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5259 for (o = oel - 1; o >= oet; --o) 5260 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5261 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5262 foffset = offset; 5263 } 5264 break; 5265 case 3: 5266 /* The original hex closure is 5267 5268 {c, 5269 f_b, f_t, f_f, f_b, f_r, f_l, 5270 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5271 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5272 */ 5273 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5274 /* The SEM order is 5275 Bottom Slice 5276 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5277 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5278 v_blb, {e_bb}, v_brb, 5279 5280 Middle Slice (j) 5281 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5282 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5283 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5284 5285 Top Slice 5286 v_tlf, {e_tf}, v_trf, 5287 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5288 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5289 */ 5290 { 5291 const PetscInt oc = 0; 5292 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5293 const PetscInt oft = ofb + PetscSqr(k - 1); 5294 const PetscInt off = oft + PetscSqr(k - 1); 5295 const PetscInt ofk = off + PetscSqr(k - 1); 5296 const PetscInt ofr = ofk + PetscSqr(k - 1); 5297 const PetscInt ofl = ofr + PetscSqr(k - 1); 5298 const PetscInt oebl = ofl + PetscSqr(k - 1); 5299 const PetscInt oebb = oebl + (k - 1); 5300 const PetscInt oebr = oebb + (k - 1); 5301 const PetscInt oebf = oebr + (k - 1); 5302 const PetscInt oetf = oebf + (k - 1); 5303 const PetscInt oetr = oetf + (k - 1); 5304 const PetscInt oetb = oetr + (k - 1); 5305 const PetscInt oetl = oetb + (k - 1); 5306 const PetscInt oerf = oetl + (k - 1); 5307 const PetscInt oelf = oerf + (k - 1); 5308 const PetscInt oelb = oelf + (k - 1); 5309 const PetscInt oerb = oelb + (k - 1); 5310 const PetscInt ovblf = oerb + (k - 1); 5311 const PetscInt ovblb = ovblf + 1; 5312 const PetscInt ovbrb = ovblb + 1; 5313 const PetscInt ovbrf = ovbrb + 1; 5314 const PetscInt ovtlf = ovbrf + 1; 5315 const PetscInt ovtrf = ovtlf + 1; 5316 const PetscInt ovtrb = ovtrf + 1; 5317 const PetscInt ovtlb = ovtrb + 1; 5318 PetscInt o, n; 5319 5320 /* Bottom Slice */ 5321 /* bottom */ 5322 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5323 for (o = oetf - 1; o >= oebf; --o) 5324 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5325 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5326 /* middle */ 5327 for (i = 0; i < k - 1; ++i) { 5328 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5329 for (n = 0; n < k - 1; ++n) { 5330 o = ofb + n * (k - 1) + i; 5331 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5332 } 5333 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5334 } 5335 /* top */ 5336 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5337 for (o = oebb; o < oebr; ++o) 5338 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5339 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5340 5341 /* Middle Slice */ 5342 for (j = 0; j < k - 1; ++j) { 5343 /* bottom */ 5344 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5345 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5346 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5347 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5348 /* middle */ 5349 for (i = 0; i < k - 1; ++i) { 5350 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5351 for (n = 0; n < k - 1; ++n) 5352 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5353 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5354 } 5355 /* top */ 5356 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5357 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5358 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5359 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5360 } 5361 5362 /* Top Slice */ 5363 /* bottom */ 5364 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5365 for (o = oetf; o < oetr; ++o) 5366 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5367 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5368 /* middle */ 5369 for (i = 0; i < k - 1; ++i) { 5370 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5371 for (n = 0; n < k - 1; ++n) 5372 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5373 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5374 } 5375 /* top */ 5376 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5377 for (o = oetl - 1; o >= oetb; --o) 5378 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5379 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5380 5381 foffset = offset; 5382 } 5383 break; 5384 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5385 } 5386 } 5387 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5388 /* Check permutation */ 5389 { 5390 PetscInt *check; 5391 5392 PetscCall(PetscMalloc1(size, &check)); 5393 for (i = 0; i < size; ++i) { 5394 check[i] = -1; 5395 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5396 } 5397 for (i = 0; i < size; ++i) check[perm[i]] = i; 5398 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5399 PetscCall(PetscFree(check)); 5400 } 5401 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5402 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5403 PetscInt *loc_perm; 5404 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5405 for (PetscInt i = 0; i < size; i++) { 5406 loc_perm[i] = perm[i]; 5407 loc_perm[size + i] = size + perm[i]; 5408 } 5409 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5410 } 5411 } 5412 PetscFunctionReturn(0); 5413 } 5414 5415 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) { 5416 PetscDS prob; 5417 PetscInt depth, Nf, h; 5418 DMLabel label; 5419 5420 PetscFunctionBeginHot; 5421 PetscCall(DMGetDS(dm, &prob)); 5422 Nf = prob->Nf; 5423 label = dm->depthLabel; 5424 *dspace = NULL; 5425 if (field < Nf) { 5426 PetscObject disc = prob->disc[field]; 5427 5428 if (disc->classid == PETSCFE_CLASSID) { 5429 PetscDualSpace dsp; 5430 5431 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5432 PetscCall(DMLabelGetNumValues(label, &depth)); 5433 PetscCall(DMLabelGetValue(label, point, &h)); 5434 h = depth - 1 - h; 5435 if (h) { 5436 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5437 } else { 5438 *dspace = dsp; 5439 } 5440 } 5441 } 5442 PetscFunctionReturn(0); 5443 } 5444 5445 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5446 PetscScalar *array; 5447 const PetscScalar *vArray; 5448 const PetscInt *cone, *coneO; 5449 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5450 5451 PetscFunctionBeginHot; 5452 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5453 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5454 PetscCall(DMPlexGetCone(dm, point, &cone)); 5455 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5456 if (!values || !*values) { 5457 if ((point >= pStart) && (point < pEnd)) { 5458 PetscInt dof; 5459 5460 PetscCall(PetscSectionGetDof(section, point, &dof)); 5461 size += dof; 5462 } 5463 for (p = 0; p < numPoints; ++p) { 5464 const PetscInt cp = cone[p]; 5465 PetscInt dof; 5466 5467 if ((cp < pStart) || (cp >= pEnd)) continue; 5468 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5469 size += dof; 5470 } 5471 if (!values) { 5472 if (csize) *csize = size; 5473 PetscFunctionReturn(0); 5474 } 5475 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5476 } else { 5477 array = *values; 5478 } 5479 size = 0; 5480 PetscCall(VecGetArrayRead(v, &vArray)); 5481 if ((point >= pStart) && (point < pEnd)) { 5482 PetscInt dof, off, d; 5483 const PetscScalar *varr; 5484 5485 PetscCall(PetscSectionGetDof(section, point, &dof)); 5486 PetscCall(PetscSectionGetOffset(section, point, &off)); 5487 varr = &vArray[off]; 5488 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5489 size += dof; 5490 } 5491 for (p = 0; p < numPoints; ++p) { 5492 const PetscInt cp = cone[p]; 5493 PetscInt o = coneO[p]; 5494 PetscInt dof, off, d; 5495 const PetscScalar *varr; 5496 5497 if ((cp < pStart) || (cp >= pEnd)) continue; 5498 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5499 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5500 varr = &vArray[off]; 5501 if (o >= 0) { 5502 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5503 } else { 5504 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5505 } 5506 size += dof; 5507 } 5508 PetscCall(VecRestoreArrayRead(v, &vArray)); 5509 if (!*values) { 5510 if (csize) *csize = size; 5511 *values = array; 5512 } else { 5513 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5514 *csize = size; 5515 } 5516 PetscFunctionReturn(0); 5517 } 5518 5519 /* Compress out points not in the section */ 5520 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) { 5521 const PetscInt np = *numPoints; 5522 PetscInt pStart, pEnd, p, q; 5523 5524 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5525 for (p = 0, q = 0; p < np; ++p) { 5526 const PetscInt r = points[p * 2]; 5527 if ((r >= pStart) && (r < pEnd)) { 5528 points[q * 2] = r; 5529 points[q * 2 + 1] = points[p * 2 + 1]; 5530 ++q; 5531 } 5532 } 5533 *numPoints = q; 5534 return 0; 5535 } 5536 5537 /* Compressed closure does not apply closure permutation */ 5538 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5539 const PetscInt *cla = NULL; 5540 PetscInt np, *pts = NULL; 5541 5542 PetscFunctionBeginHot; 5543 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5544 if (*clPoints) { 5545 PetscInt dof, off; 5546 5547 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5548 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5549 PetscCall(ISGetIndices(*clPoints, &cla)); 5550 np = dof / 2; 5551 pts = (PetscInt *)&cla[off]; 5552 } else { 5553 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5554 PetscCall(CompressPoints_Private(section, &np, pts)); 5555 } 5556 *numPoints = np; 5557 *points = pts; 5558 *clp = cla; 5559 PetscFunctionReturn(0); 5560 } 5561 5562 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5563 PetscFunctionBeginHot; 5564 if (!*clPoints) { 5565 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5566 } else { 5567 PetscCall(ISRestoreIndices(*clPoints, clp)); 5568 } 5569 *numPoints = 0; 5570 *points = NULL; 5571 *clSec = NULL; 5572 *clPoints = NULL; 5573 *clp = NULL; 5574 PetscFunctionReturn(0); 5575 } 5576 5577 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) { 5578 PetscInt offset = 0, p; 5579 const PetscInt **perms = NULL; 5580 const PetscScalar **flips = NULL; 5581 5582 PetscFunctionBeginHot; 5583 *size = 0; 5584 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5585 for (p = 0; p < numPoints; p++) { 5586 const PetscInt point = points[2 * p]; 5587 const PetscInt *perm = perms ? perms[p] : NULL; 5588 const PetscScalar *flip = flips ? flips[p] : NULL; 5589 PetscInt dof, off, d; 5590 const PetscScalar *varr; 5591 5592 PetscCall(PetscSectionGetDof(section, point, &dof)); 5593 PetscCall(PetscSectionGetOffset(section, point, &off)); 5594 varr = &vArray[off]; 5595 if (clperm) { 5596 if (perm) { 5597 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5598 } else { 5599 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5600 } 5601 if (flip) { 5602 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5603 } 5604 } else { 5605 if (perm) { 5606 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5607 } else { 5608 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5609 } 5610 if (flip) { 5611 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5612 } 5613 } 5614 offset += dof; 5615 } 5616 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5617 *size = offset; 5618 PetscFunctionReturn(0); 5619 } 5620 5621 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[]) { 5622 PetscInt offset = 0, f; 5623 5624 PetscFunctionBeginHot; 5625 *size = 0; 5626 for (f = 0; f < numFields; ++f) { 5627 PetscInt p; 5628 const PetscInt **perms = NULL; 5629 const PetscScalar **flips = NULL; 5630 5631 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5632 for (p = 0; p < numPoints; p++) { 5633 const PetscInt point = points[2 * p]; 5634 PetscInt fdof, foff, b; 5635 const PetscScalar *varr; 5636 const PetscInt *perm = perms ? perms[p] : NULL; 5637 const PetscScalar *flip = flips ? flips[p] : NULL; 5638 5639 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5640 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5641 varr = &vArray[foff]; 5642 if (clperm) { 5643 if (perm) { 5644 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5645 } else { 5646 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5647 } 5648 if (flip) { 5649 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5650 } 5651 } else { 5652 if (perm) { 5653 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5654 } else { 5655 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5656 } 5657 if (flip) { 5658 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5659 } 5660 } 5661 offset += fdof; 5662 } 5663 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5664 } 5665 *size = offset; 5666 PetscFunctionReturn(0); 5667 } 5668 5669 /*@C 5670 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5671 5672 Not collective 5673 5674 Input Parameters: 5675 + dm - The DM 5676 . section - The section describing the layout in v, or NULL to use the default section 5677 . v - The local vector 5678 - point - The point in the DM 5679 5680 Input/Output Parameters: 5681 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5682 - values - An array to use for the values, or NULL to have it allocated automatically; 5683 if the user provided NULL, it is a borrowed array and should not be freed 5684 5685 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5686 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5687 $ assembly function, and a user may already have allocated storage for this operation. 5688 $ 5689 $ A typical use could be 5690 $ 5691 $ values = NULL; 5692 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5693 $ for (cl = 0; cl < clSize; ++cl) { 5694 $ <Compute on closure> 5695 $ } 5696 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5697 $ 5698 $ or 5699 $ 5700 $ PetscMalloc1(clMaxSize, &values); 5701 $ for (p = pStart; p < pEnd; ++p) { 5702 $ clSize = clMaxSize; 5703 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5704 $ for (cl = 0; cl < clSize; ++cl) { 5705 $ <Compute on closure> 5706 $ } 5707 $ } 5708 $ PetscFree(values); 5709 5710 Fortran Notes: 5711 Since it returns an array, this routine is only available in Fortran 90, and you must 5712 include petsc.h90 in your code. 5713 5714 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5715 5716 Level: intermediate 5717 5718 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5719 @*/ 5720 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5721 PetscSection clSection; 5722 IS clPoints; 5723 PetscInt *points = NULL; 5724 const PetscInt *clp, *perm; 5725 PetscInt depth, numFields, numPoints, asize; 5726 5727 PetscFunctionBeginHot; 5728 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5729 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5730 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5731 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5732 PetscCall(DMPlexGetDepth(dm, &depth)); 5733 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5734 if (depth == 1 && numFields < 2) { 5735 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5736 PetscFunctionReturn(0); 5737 } 5738 /* Get points */ 5739 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5740 /* Get sizes */ 5741 asize = 0; 5742 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5743 PetscInt dof; 5744 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5745 asize += dof; 5746 } 5747 if (values) { 5748 const PetscScalar *vArray; 5749 PetscInt size; 5750 5751 if (*values) { 5752 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); 5753 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5754 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5755 PetscCall(VecGetArrayRead(v, &vArray)); 5756 /* Get values */ 5757 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5758 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5759 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5760 /* Cleanup array */ 5761 PetscCall(VecRestoreArrayRead(v, &vArray)); 5762 } 5763 if (csize) *csize = asize; 5764 /* Cleanup points */ 5765 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5766 PetscFunctionReturn(0); 5767 } 5768 5769 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) { 5770 DMLabel depthLabel; 5771 PetscSection clSection; 5772 IS clPoints; 5773 PetscScalar *array; 5774 const PetscScalar *vArray; 5775 PetscInt *points = NULL; 5776 const PetscInt *clp, *perm = NULL; 5777 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5778 5779 PetscFunctionBeginHot; 5780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5781 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5782 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5783 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5784 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5785 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5786 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5787 if (mdepth == 1 && numFields < 2) { 5788 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5789 PetscFunctionReturn(0); 5790 } 5791 /* Get points */ 5792 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5793 for (clsize = 0, p = 0; p < Np; p++) { 5794 PetscInt dof; 5795 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 5796 clsize += dof; 5797 } 5798 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 5799 /* Filter points */ 5800 for (p = 0; p < numPoints * 2; p += 2) { 5801 PetscInt dep; 5802 5803 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5804 if (dep != depth) continue; 5805 points[Np * 2 + 0] = points[p]; 5806 points[Np * 2 + 1] = points[p + 1]; 5807 ++Np; 5808 } 5809 /* Get array */ 5810 if (!values || !*values) { 5811 PetscInt asize = 0, dof; 5812 5813 for (p = 0; p < Np * 2; p += 2) { 5814 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5815 asize += dof; 5816 } 5817 if (!values) { 5818 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5819 if (csize) *csize = asize; 5820 PetscFunctionReturn(0); 5821 } 5822 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5823 } else { 5824 array = *values; 5825 } 5826 PetscCall(VecGetArrayRead(v, &vArray)); 5827 /* Get values */ 5828 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5829 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5830 /* Cleanup points */ 5831 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5832 /* Cleanup array */ 5833 PetscCall(VecRestoreArrayRead(v, &vArray)); 5834 if (!*values) { 5835 if (csize) *csize = size; 5836 *values = array; 5837 } else { 5838 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5839 *csize = size; 5840 } 5841 PetscFunctionReturn(0); 5842 } 5843 5844 /*@C 5845 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5846 5847 Not collective 5848 5849 Input Parameters: 5850 + dm - The DM 5851 . section - The section describing the layout in v, or NULL to use the default section 5852 . v - The local vector 5853 . point - The point in the DM 5854 . csize - The number of values in the closure, or NULL 5855 - values - The array of values, which is a borrowed array and should not be freed 5856 5857 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5858 5859 Fortran Notes: 5860 Since it returns an array, this routine is only available in Fortran 90, and you must 5861 include petsc.h90 in your code. 5862 5863 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5864 5865 Level: intermediate 5866 5867 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5868 @*/ 5869 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5870 PetscInt size = 0; 5871 5872 PetscFunctionBegin; 5873 /* Should work without recalculating size */ 5874 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 5875 *values = NULL; 5876 PetscFunctionReturn(0); 5877 } 5878 5879 static inline void add(PetscScalar *x, PetscScalar y) { 5880 *x += y; 5881 } 5882 static inline void insert(PetscScalar *x, PetscScalar y) { 5883 *x = y; 5884 } 5885 5886 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[]) { 5887 PetscInt cdof; /* The number of constraints on this point */ 5888 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5889 PetscScalar *a; 5890 PetscInt off, cind = 0, k; 5891 5892 PetscFunctionBegin; 5893 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5894 PetscCall(PetscSectionGetOffset(section, point, &off)); 5895 a = &array[off]; 5896 if (!cdof || setBC) { 5897 if (clperm) { 5898 if (perm) { 5899 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5900 } else { 5901 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5902 } 5903 } else { 5904 if (perm) { 5905 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5906 } else { 5907 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5908 } 5909 } 5910 } else { 5911 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5912 if (clperm) { 5913 if (perm) { 5914 for (k = 0; k < dof; ++k) { 5915 if ((cind < cdof) && (k == cdofs[cind])) { 5916 ++cind; 5917 continue; 5918 } 5919 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5920 } 5921 } else { 5922 for (k = 0; k < dof; ++k) { 5923 if ((cind < cdof) && (k == cdofs[cind])) { 5924 ++cind; 5925 continue; 5926 } 5927 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5928 } 5929 } 5930 } else { 5931 if (perm) { 5932 for (k = 0; k < dof; ++k) { 5933 if ((cind < cdof) && (k == cdofs[cind])) { 5934 ++cind; 5935 continue; 5936 } 5937 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5938 } 5939 } else { 5940 for (k = 0; k < dof; ++k) { 5941 if ((cind < cdof) && (k == cdofs[cind])) { 5942 ++cind; 5943 continue; 5944 } 5945 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5946 } 5947 } 5948 } 5949 } 5950 PetscFunctionReturn(0); 5951 } 5952 5953 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[]) { 5954 PetscInt cdof; /* The number of constraints on this point */ 5955 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5956 PetscScalar *a; 5957 PetscInt off, cind = 0, k; 5958 5959 PetscFunctionBegin; 5960 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5961 PetscCall(PetscSectionGetOffset(section, point, &off)); 5962 a = &array[off]; 5963 if (cdof) { 5964 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5965 if (clperm) { 5966 if (perm) { 5967 for (k = 0; k < dof; ++k) { 5968 if ((cind < cdof) && (k == cdofs[cind])) { 5969 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5970 cind++; 5971 } 5972 } 5973 } else { 5974 for (k = 0; k < dof; ++k) { 5975 if ((cind < cdof) && (k == cdofs[cind])) { 5976 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5977 cind++; 5978 } 5979 } 5980 } 5981 } else { 5982 if (perm) { 5983 for (k = 0; k < dof; ++k) { 5984 if ((cind < cdof) && (k == cdofs[cind])) { 5985 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5986 cind++; 5987 } 5988 } 5989 } else { 5990 for (k = 0; k < dof; ++k) { 5991 if ((cind < cdof) && (k == cdofs[cind])) { 5992 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5993 cind++; 5994 } 5995 } 5996 } 5997 } 5998 } 5999 PetscFunctionReturn(0); 6000 } 6001 6002 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[]) { 6003 PetscScalar *a; 6004 PetscInt fdof, foff, fcdof, foffset = *offset; 6005 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6006 PetscInt cind = 0, b; 6007 6008 PetscFunctionBegin; 6009 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6010 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6011 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6012 a = &array[foff]; 6013 if (!fcdof || setBC) { 6014 if (clperm) { 6015 if (perm) { 6016 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6017 } else { 6018 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6019 } 6020 } else { 6021 if (perm) { 6022 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6023 } else { 6024 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6025 } 6026 } 6027 } else { 6028 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6029 if (clperm) { 6030 if (perm) { 6031 for (b = 0; b < fdof; b++) { 6032 if ((cind < fcdof) && (b == fcdofs[cind])) { 6033 ++cind; 6034 continue; 6035 } 6036 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6037 } 6038 } else { 6039 for (b = 0; b < fdof; b++) { 6040 if ((cind < fcdof) && (b == fcdofs[cind])) { 6041 ++cind; 6042 continue; 6043 } 6044 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6045 } 6046 } 6047 } else { 6048 if (perm) { 6049 for (b = 0; b < fdof; b++) { 6050 if ((cind < fcdof) && (b == fcdofs[cind])) { 6051 ++cind; 6052 continue; 6053 } 6054 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6055 } 6056 } else { 6057 for (b = 0; b < fdof; b++) { 6058 if ((cind < fcdof) && (b == fcdofs[cind])) { 6059 ++cind; 6060 continue; 6061 } 6062 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6063 } 6064 } 6065 } 6066 } 6067 *offset += fdof; 6068 PetscFunctionReturn(0); 6069 } 6070 6071 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[]) { 6072 PetscScalar *a; 6073 PetscInt fdof, foff, fcdof, foffset = *offset; 6074 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6075 PetscInt Nc, cind = 0, ncind = 0, b; 6076 PetscBool ncSet, fcSet; 6077 6078 PetscFunctionBegin; 6079 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6080 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6081 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6082 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6083 a = &array[foff]; 6084 if (fcdof) { 6085 /* We just override fcdof and fcdofs with Ncc and comps */ 6086 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6087 if (clperm) { 6088 if (perm) { 6089 if (comps) { 6090 for (b = 0; b < fdof; b++) { 6091 ncSet = fcSet = PETSC_FALSE; 6092 if (b % Nc == comps[ncind]) { 6093 ncind = (ncind + 1) % Ncc; 6094 ncSet = PETSC_TRUE; 6095 } 6096 if ((cind < fcdof) && (b == fcdofs[cind])) { 6097 ++cind; 6098 fcSet = PETSC_TRUE; 6099 } 6100 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6101 } 6102 } else { 6103 for (b = 0; b < fdof; b++) { 6104 if ((cind < fcdof) && (b == fcdofs[cind])) { 6105 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6106 ++cind; 6107 } 6108 } 6109 } 6110 } else { 6111 if (comps) { 6112 for (b = 0; b < fdof; b++) { 6113 ncSet = fcSet = PETSC_FALSE; 6114 if (b % Nc == comps[ncind]) { 6115 ncind = (ncind + 1) % Ncc; 6116 ncSet = PETSC_TRUE; 6117 } 6118 if ((cind < fcdof) && (b == fcdofs[cind])) { 6119 ++cind; 6120 fcSet = PETSC_TRUE; 6121 } 6122 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6123 } 6124 } else { 6125 for (b = 0; b < fdof; b++) { 6126 if ((cind < fcdof) && (b == fcdofs[cind])) { 6127 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6128 ++cind; 6129 } 6130 } 6131 } 6132 } 6133 } else { 6134 if (perm) { 6135 if (comps) { 6136 for (b = 0; b < fdof; b++) { 6137 ncSet = fcSet = PETSC_FALSE; 6138 if (b % Nc == comps[ncind]) { 6139 ncind = (ncind + 1) % Ncc; 6140 ncSet = PETSC_TRUE; 6141 } 6142 if ((cind < fcdof) && (b == fcdofs[cind])) { 6143 ++cind; 6144 fcSet = PETSC_TRUE; 6145 } 6146 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6147 } 6148 } else { 6149 for (b = 0; b < fdof; b++) { 6150 if ((cind < fcdof) && (b == fcdofs[cind])) { 6151 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6152 ++cind; 6153 } 6154 } 6155 } 6156 } else { 6157 if (comps) { 6158 for (b = 0; b < fdof; b++) { 6159 ncSet = fcSet = PETSC_FALSE; 6160 if (b % Nc == comps[ncind]) { 6161 ncind = (ncind + 1) % Ncc; 6162 ncSet = PETSC_TRUE; 6163 } 6164 if ((cind < fcdof) && (b == fcdofs[cind])) { 6165 ++cind; 6166 fcSet = PETSC_TRUE; 6167 } 6168 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6169 } 6170 } else { 6171 for (b = 0; b < fdof; b++) { 6172 if ((cind < fcdof) && (b == fcdofs[cind])) { 6173 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6174 ++cind; 6175 } 6176 } 6177 } 6178 } 6179 } 6180 } 6181 *offset += fdof; 6182 PetscFunctionReturn(0); 6183 } 6184 6185 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6186 PetscScalar *array; 6187 const PetscInt *cone, *coneO; 6188 PetscInt pStart, pEnd, p, numPoints, off, dof; 6189 6190 PetscFunctionBeginHot; 6191 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6192 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6193 PetscCall(DMPlexGetCone(dm, point, &cone)); 6194 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6195 PetscCall(VecGetArray(v, &array)); 6196 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6197 const PetscInt cp = !p ? point : cone[p - 1]; 6198 const PetscInt o = !p ? 0 : coneO[p - 1]; 6199 6200 if ((cp < pStart) || (cp >= pEnd)) { 6201 dof = 0; 6202 continue; 6203 } 6204 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6205 /* ADD_VALUES */ 6206 { 6207 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6208 PetscScalar *a; 6209 PetscInt cdof, coff, cind = 0, k; 6210 6211 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6212 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6213 a = &array[coff]; 6214 if (!cdof) { 6215 if (o >= 0) { 6216 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6217 } else { 6218 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6219 } 6220 } else { 6221 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6222 if (o >= 0) { 6223 for (k = 0; k < dof; ++k) { 6224 if ((cind < cdof) && (k == cdofs[cind])) { 6225 ++cind; 6226 continue; 6227 } 6228 a[k] += values[off + k]; 6229 } 6230 } else { 6231 for (k = 0; k < dof; ++k) { 6232 if ((cind < cdof) && (k == cdofs[cind])) { 6233 ++cind; 6234 continue; 6235 } 6236 a[k] += values[off + dof - k - 1]; 6237 } 6238 } 6239 } 6240 } 6241 } 6242 PetscCall(VecRestoreArray(v, &array)); 6243 PetscFunctionReturn(0); 6244 } 6245 6246 /*@C 6247 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6248 6249 Not collective 6250 6251 Input Parameters: 6252 + dm - The DM 6253 . section - The section describing the layout in v, or NULL to use the default section 6254 . v - The local vector 6255 . point - The point in the DM 6256 . values - The array of values 6257 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6258 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6259 6260 Fortran Notes: 6261 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6262 6263 Level: intermediate 6264 6265 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6266 @*/ 6267 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6268 PetscSection clSection; 6269 IS clPoints; 6270 PetscScalar *array; 6271 PetscInt *points = NULL; 6272 const PetscInt *clp, *clperm = NULL; 6273 PetscInt depth, numFields, numPoints, p, clsize; 6274 6275 PetscFunctionBeginHot; 6276 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6277 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6278 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6279 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6280 PetscCall(DMPlexGetDepth(dm, &depth)); 6281 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6282 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6283 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6284 PetscFunctionReturn(0); 6285 } 6286 /* Get points */ 6287 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6288 for (clsize = 0, p = 0; p < numPoints; p++) { 6289 PetscInt dof; 6290 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6291 clsize += dof; 6292 } 6293 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6294 /* Get array */ 6295 PetscCall(VecGetArray(v, &array)); 6296 /* Get values */ 6297 if (numFields > 0) { 6298 PetscInt offset = 0, f; 6299 for (f = 0; f < numFields; ++f) { 6300 const PetscInt **perms = NULL; 6301 const PetscScalar **flips = NULL; 6302 6303 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6304 switch (mode) { 6305 case INSERT_VALUES: 6306 for (p = 0; p < numPoints; p++) { 6307 const PetscInt point = points[2 * p]; 6308 const PetscInt *perm = perms ? perms[p] : NULL; 6309 const PetscScalar *flip = flips ? flips[p] : NULL; 6310 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6311 } 6312 break; 6313 case INSERT_ALL_VALUES: 6314 for (p = 0; p < numPoints; p++) { 6315 const PetscInt point = points[2 * p]; 6316 const PetscInt *perm = perms ? perms[p] : NULL; 6317 const PetscScalar *flip = flips ? flips[p] : NULL; 6318 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6319 } 6320 break; 6321 case INSERT_BC_VALUES: 6322 for (p = 0; p < numPoints; p++) { 6323 const PetscInt point = points[2 * p]; 6324 const PetscInt *perm = perms ? perms[p] : NULL; 6325 const PetscScalar *flip = flips ? flips[p] : NULL; 6326 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6327 } 6328 break; 6329 case ADD_VALUES: 6330 for (p = 0; p < numPoints; p++) { 6331 const PetscInt point = points[2 * p]; 6332 const PetscInt *perm = perms ? perms[p] : NULL; 6333 const PetscScalar *flip = flips ? flips[p] : NULL; 6334 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6335 } 6336 break; 6337 case ADD_ALL_VALUES: 6338 for (p = 0; p < numPoints; p++) { 6339 const PetscInt point = points[2 * p]; 6340 const PetscInt *perm = perms ? perms[p] : NULL; 6341 const PetscScalar *flip = flips ? flips[p] : NULL; 6342 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6343 } 6344 break; 6345 case ADD_BC_VALUES: 6346 for (p = 0; p < numPoints; p++) { 6347 const PetscInt point = points[2 * p]; 6348 const PetscInt *perm = perms ? perms[p] : NULL; 6349 const PetscScalar *flip = flips ? flips[p] : NULL; 6350 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6351 } 6352 break; 6353 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6354 } 6355 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6356 } 6357 } else { 6358 PetscInt dof, off; 6359 const PetscInt **perms = NULL; 6360 const PetscScalar **flips = NULL; 6361 6362 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6363 switch (mode) { 6364 case INSERT_VALUES: 6365 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6366 const PetscInt point = points[2 * p]; 6367 const PetscInt *perm = perms ? perms[p] : NULL; 6368 const PetscScalar *flip = flips ? flips[p] : NULL; 6369 PetscCall(PetscSectionGetDof(section, point, &dof)); 6370 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6371 } 6372 break; 6373 case INSERT_ALL_VALUES: 6374 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6375 const PetscInt point = points[2 * p]; 6376 const PetscInt *perm = perms ? perms[p] : NULL; 6377 const PetscScalar *flip = flips ? flips[p] : NULL; 6378 PetscCall(PetscSectionGetDof(section, point, &dof)); 6379 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6380 } 6381 break; 6382 case INSERT_BC_VALUES: 6383 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6384 const PetscInt point = points[2 * p]; 6385 const PetscInt *perm = perms ? perms[p] : NULL; 6386 const PetscScalar *flip = flips ? flips[p] : NULL; 6387 PetscCall(PetscSectionGetDof(section, point, &dof)); 6388 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6389 } 6390 break; 6391 case ADD_VALUES: 6392 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6393 const PetscInt point = points[2 * p]; 6394 const PetscInt *perm = perms ? perms[p] : NULL; 6395 const PetscScalar *flip = flips ? flips[p] : NULL; 6396 PetscCall(PetscSectionGetDof(section, point, &dof)); 6397 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6398 } 6399 break; 6400 case ADD_ALL_VALUES: 6401 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6402 const PetscInt point = points[2 * p]; 6403 const PetscInt *perm = perms ? perms[p] : NULL; 6404 const PetscScalar *flip = flips ? flips[p] : NULL; 6405 PetscCall(PetscSectionGetDof(section, point, &dof)); 6406 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6407 } 6408 break; 6409 case ADD_BC_VALUES: 6410 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6411 const PetscInt point = points[2 * p]; 6412 const PetscInt *perm = perms ? perms[p] : NULL; 6413 const PetscScalar *flip = flips ? flips[p] : NULL; 6414 PetscCall(PetscSectionGetDof(section, point, &dof)); 6415 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6416 } 6417 break; 6418 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6419 } 6420 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6421 } 6422 /* Cleanup points */ 6423 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6424 /* Cleanup array */ 6425 PetscCall(VecRestoreArray(v, &array)); 6426 PetscFunctionReturn(0); 6427 } 6428 6429 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6430 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) { 6431 PetscFunctionBegin; 6432 *contains = PETSC_TRUE; 6433 if (label) { 6434 PetscInt fdof; 6435 6436 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6437 if (!*contains) { 6438 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6439 *offset += fdof; 6440 PetscFunctionReturn(0); 6441 } 6442 } 6443 PetscFunctionReturn(0); 6444 } 6445 6446 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6447 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) { 6448 PetscSection clSection; 6449 IS clPoints; 6450 PetscScalar *array; 6451 PetscInt *points = NULL; 6452 const PetscInt *clp; 6453 PetscInt numFields, numPoints, p; 6454 PetscInt offset = 0, f; 6455 6456 PetscFunctionBeginHot; 6457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6458 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6459 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6460 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6461 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6462 /* Get points */ 6463 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6464 /* Get array */ 6465 PetscCall(VecGetArray(v, &array)); 6466 /* Get values */ 6467 for (f = 0; f < numFields; ++f) { 6468 const PetscInt **perms = NULL; 6469 const PetscScalar **flips = NULL; 6470 PetscBool contains; 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 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6488 if (!contains) continue; 6489 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6490 } 6491 break; 6492 case INSERT_ALL_VALUES: 6493 for (p = 0; p < numPoints; p++) { 6494 const PetscInt point = points[2 * p]; 6495 const PetscInt *perm = perms ? perms[p] : NULL; 6496 const PetscScalar *flip = flips ? flips[p] : NULL; 6497 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6498 if (!contains) continue; 6499 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6500 } 6501 break; 6502 case INSERT_BC_VALUES: 6503 for (p = 0; p < numPoints; p++) { 6504 const PetscInt point = points[2 * p]; 6505 const PetscInt *perm = perms ? perms[p] : NULL; 6506 const PetscScalar *flip = flips ? flips[p] : NULL; 6507 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6508 if (!contains) continue; 6509 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6510 } 6511 break; 6512 case ADD_VALUES: 6513 for (p = 0; p < numPoints; p++) { 6514 const PetscInt point = points[2 * p]; 6515 const PetscInt *perm = perms ? perms[p] : NULL; 6516 const PetscScalar *flip = flips ? flips[p] : NULL; 6517 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6518 if (!contains) continue; 6519 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6520 } 6521 break; 6522 case ADD_ALL_VALUES: 6523 for (p = 0; p < numPoints; p++) { 6524 const PetscInt point = points[2 * p]; 6525 const PetscInt *perm = perms ? perms[p] : NULL; 6526 const PetscScalar *flip = flips ? flips[p] : NULL; 6527 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6528 if (!contains) continue; 6529 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6530 } 6531 break; 6532 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6533 } 6534 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6535 } 6536 /* Cleanup points */ 6537 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6538 /* Cleanup array */ 6539 PetscCall(VecRestoreArray(v, &array)); 6540 PetscFunctionReturn(0); 6541 } 6542 6543 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) { 6544 PetscMPIInt rank; 6545 PetscInt i, j; 6546 6547 PetscFunctionBegin; 6548 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6549 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6550 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6551 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6552 numCIndices = numCIndices ? numCIndices : numRIndices; 6553 if (!values) PetscFunctionReturn(0); 6554 for (i = 0; i < numRIndices; i++) { 6555 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6556 for (j = 0; j < numCIndices; j++) { 6557 #if defined(PETSC_USE_COMPLEX) 6558 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6559 #else 6560 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6561 #endif 6562 } 6563 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6564 } 6565 PetscFunctionReturn(0); 6566 } 6567 6568 /* 6569 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6570 6571 Input Parameters: 6572 + section - The section for this data layout 6573 . islocal - Is the section (and thus indices being requested) local or global? 6574 . point - The point contributing dofs with these indices 6575 . off - The global offset of this point 6576 . loff - The local offset of each field 6577 . setBC - The flag determining whether to include indices of boundary values 6578 . perm - A permutation of the dofs on this point, or NULL 6579 - indperm - A permutation of the entire indices array, or NULL 6580 6581 Output Parameter: 6582 . indices - Indices for dofs on this point 6583 6584 Level: developer 6585 6586 Note: The indices could be local or global, depending on the value of 'off'. 6587 */ 6588 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) { 6589 PetscInt dof; /* The number of unknowns on this point */ 6590 PetscInt cdof; /* The number of constraints on this point */ 6591 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6592 PetscInt cind = 0, k; 6593 6594 PetscFunctionBegin; 6595 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6596 PetscCall(PetscSectionGetDof(section, point, &dof)); 6597 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6598 if (!cdof || setBC) { 6599 for (k = 0; k < dof; ++k) { 6600 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6601 const PetscInt ind = indperm ? indperm[preind] : preind; 6602 6603 indices[ind] = off + k; 6604 } 6605 } else { 6606 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6607 for (k = 0; k < dof; ++k) { 6608 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6609 const PetscInt ind = indperm ? indperm[preind] : preind; 6610 6611 if ((cind < cdof) && (k == cdofs[cind])) { 6612 /* Insert check for returning constrained indices */ 6613 indices[ind] = -(off + k + 1); 6614 ++cind; 6615 } else { 6616 indices[ind] = off + k - (islocal ? 0 : cind); 6617 } 6618 } 6619 } 6620 *loff += dof; 6621 PetscFunctionReturn(0); 6622 } 6623 6624 /* 6625 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6626 6627 Input Parameters: 6628 + section - a section (global or local) 6629 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6630 . point - point within section 6631 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6632 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6633 . setBC - identify constrained (boundary condition) points via involution. 6634 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6635 . permsoff - offset 6636 - indperm - index permutation 6637 6638 Output Parameter: 6639 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6640 . indices - array to hold indices (as defined by section) of each dof associated with point 6641 6642 Notes: 6643 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6644 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6645 in the local vector. 6646 6647 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6648 significant). It is invalid to call with a global section and setBC=true. 6649 6650 Developer Note: 6651 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6652 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6653 offset could be obtained from the section instead of passing it explicitly as we do now. 6654 6655 Example: 6656 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6657 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6658 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6659 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. 6660 6661 Level: developer 6662 */ 6663 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[]) { 6664 PetscInt numFields, foff, f; 6665 6666 PetscFunctionBegin; 6667 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6668 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6669 for (f = 0, foff = 0; f < numFields; ++f) { 6670 PetscInt fdof, cfdof; 6671 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6672 PetscInt cind = 0, b; 6673 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6674 6675 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6676 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6677 if (!cfdof || setBC) { 6678 for (b = 0; b < fdof; ++b) { 6679 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6680 const PetscInt ind = indperm ? indperm[preind] : preind; 6681 6682 indices[ind] = off + foff + b; 6683 } 6684 } else { 6685 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6686 for (b = 0; b < fdof; ++b) { 6687 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6688 const PetscInt ind = indperm ? indperm[preind] : preind; 6689 6690 if ((cind < cfdof) && (b == fcdofs[cind])) { 6691 indices[ind] = -(off + foff + b + 1); 6692 ++cind; 6693 } else { 6694 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6695 } 6696 } 6697 } 6698 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6699 foffs[f] += fdof; 6700 } 6701 PetscFunctionReturn(0); 6702 } 6703 6704 /* 6705 This version believes the globalSection offsets for each field, rather than just the point offset 6706 6707 . foffs - The offset into 'indices' for each field, since it is segregated by field 6708 6709 Notes: 6710 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6711 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6712 */ 6713 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) { 6714 PetscInt numFields, foff, f; 6715 6716 PetscFunctionBegin; 6717 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6718 for (f = 0; f < numFields; ++f) { 6719 PetscInt fdof, cfdof; 6720 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6721 PetscInt cind = 0, b; 6722 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6723 6724 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6725 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6726 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6727 if (!cfdof) { 6728 for (b = 0; b < fdof; ++b) { 6729 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6730 const PetscInt ind = indperm ? indperm[preind] : preind; 6731 6732 indices[ind] = foff + b; 6733 } 6734 } else { 6735 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6736 for (b = 0; b < fdof; ++b) { 6737 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6738 const PetscInt ind = indperm ? indperm[preind] : preind; 6739 6740 if ((cind < cfdof) && (b == fcdofs[cind])) { 6741 indices[ind] = -(foff + b + 1); 6742 ++cind; 6743 } else { 6744 indices[ind] = foff + b - cind; 6745 } 6746 } 6747 } 6748 foffs[f] += fdof; 6749 } 6750 PetscFunctionReturn(0); 6751 } 6752 6753 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) { 6754 Mat cMat; 6755 PetscSection aSec, cSec; 6756 IS aIS; 6757 PetscInt aStart = -1, aEnd = -1; 6758 const PetscInt *anchors; 6759 PetscInt numFields, f, p, q, newP = 0; 6760 PetscInt newNumPoints = 0, newNumIndices = 0; 6761 PetscInt *newPoints, *indices, *newIndices; 6762 PetscInt maxAnchor, maxDof; 6763 PetscInt newOffsets[32]; 6764 PetscInt *pointMatOffsets[32]; 6765 PetscInt *newPointOffsets[32]; 6766 PetscScalar *pointMat[32]; 6767 PetscScalar *newValues = NULL, *tmpValues; 6768 PetscBool anyConstrained = PETSC_FALSE; 6769 6770 PetscFunctionBegin; 6771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6772 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6773 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6774 6775 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6776 /* if there are point-to-point constraints */ 6777 if (aSec) { 6778 PetscCall(PetscArrayzero(newOffsets, 32)); 6779 PetscCall(ISGetIndices(aIS, &anchors)); 6780 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6781 /* figure out how many points are going to be in the new element matrix 6782 * (we allow double counting, because it's all just going to be summed 6783 * into the global matrix anyway) */ 6784 for (p = 0; p < 2 * numPoints; p += 2) { 6785 PetscInt b = points[p]; 6786 PetscInt bDof = 0, bSecDof; 6787 6788 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6789 if (!bSecDof) continue; 6790 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6791 if (bDof) { 6792 /* this point is constrained */ 6793 /* it is going to be replaced by its anchors */ 6794 PetscInt bOff, q; 6795 6796 anyConstrained = PETSC_TRUE; 6797 newNumPoints += bDof; 6798 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6799 for (q = 0; q < bDof; q++) { 6800 PetscInt a = anchors[bOff + q]; 6801 PetscInt aDof; 6802 6803 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6804 newNumIndices += aDof; 6805 for (f = 0; f < numFields; ++f) { 6806 PetscInt fDof; 6807 6808 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6809 newOffsets[f + 1] += fDof; 6810 } 6811 } 6812 } else { 6813 /* this point is not constrained */ 6814 newNumPoints++; 6815 newNumIndices += bSecDof; 6816 for (f = 0; f < numFields; ++f) { 6817 PetscInt fDof; 6818 6819 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6820 newOffsets[f + 1] += fDof; 6821 } 6822 } 6823 } 6824 } 6825 if (!anyConstrained) { 6826 if (outNumPoints) *outNumPoints = 0; 6827 if (outNumIndices) *outNumIndices = 0; 6828 if (outPoints) *outPoints = NULL; 6829 if (outValues) *outValues = NULL; 6830 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6831 PetscFunctionReturn(0); 6832 } 6833 6834 if (outNumPoints) *outNumPoints = newNumPoints; 6835 if (outNumIndices) *outNumIndices = newNumIndices; 6836 6837 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 6838 6839 if (!outPoints && !outValues) { 6840 if (offsets) { 6841 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 6842 } 6843 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6844 PetscFunctionReturn(0); 6845 } 6846 6847 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6848 6849 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6850 6851 /* workspaces */ 6852 if (numFields) { 6853 for (f = 0; f < numFields; f++) { 6854 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 6855 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 6856 } 6857 } else { 6858 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 6859 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 6860 } 6861 6862 /* get workspaces for the point-to-point matrices */ 6863 if (numFields) { 6864 PetscInt totalOffset, totalMatOffset; 6865 6866 for (p = 0; p < numPoints; p++) { 6867 PetscInt b = points[2 * p]; 6868 PetscInt bDof = 0, bSecDof; 6869 6870 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6871 if (!bSecDof) { 6872 for (f = 0; f < numFields; f++) { 6873 newPointOffsets[f][p + 1] = 0; 6874 pointMatOffsets[f][p + 1] = 0; 6875 } 6876 continue; 6877 } 6878 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6879 if (bDof) { 6880 for (f = 0; f < numFields; f++) { 6881 PetscInt fDof, q, bOff, allFDof = 0; 6882 6883 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6884 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6885 for (q = 0; q < bDof; q++) { 6886 PetscInt a = anchors[bOff + q]; 6887 PetscInt aFDof; 6888 6889 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6890 allFDof += aFDof; 6891 } 6892 newPointOffsets[f][p + 1] = allFDof; 6893 pointMatOffsets[f][p + 1] = fDof * allFDof; 6894 } 6895 } else { 6896 for (f = 0; f < numFields; f++) { 6897 PetscInt fDof; 6898 6899 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6900 newPointOffsets[f][p + 1] = fDof; 6901 pointMatOffsets[f][p + 1] = 0; 6902 } 6903 } 6904 } 6905 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6906 newPointOffsets[f][0] = totalOffset; 6907 pointMatOffsets[f][0] = totalMatOffset; 6908 for (p = 0; p < numPoints; p++) { 6909 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 6910 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 6911 } 6912 totalOffset = newPointOffsets[f][numPoints]; 6913 totalMatOffset = pointMatOffsets[f][numPoints]; 6914 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 6915 } 6916 } else { 6917 for (p = 0; p < numPoints; p++) { 6918 PetscInt b = points[2 * p]; 6919 PetscInt bDof = 0, bSecDof; 6920 6921 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6922 if (!bSecDof) { 6923 newPointOffsets[0][p + 1] = 0; 6924 pointMatOffsets[0][p + 1] = 0; 6925 continue; 6926 } 6927 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6928 if (bDof) { 6929 PetscInt bOff, q, allDof = 0; 6930 6931 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6932 for (q = 0; q < bDof; q++) { 6933 PetscInt a = anchors[bOff + q], aDof; 6934 6935 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6936 allDof += aDof; 6937 } 6938 newPointOffsets[0][p + 1] = allDof; 6939 pointMatOffsets[0][p + 1] = bSecDof * allDof; 6940 } else { 6941 newPointOffsets[0][p + 1] = bSecDof; 6942 pointMatOffsets[0][p + 1] = 0; 6943 } 6944 } 6945 newPointOffsets[0][0] = 0; 6946 pointMatOffsets[0][0] = 0; 6947 for (p = 0; p < numPoints; p++) { 6948 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 6949 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 6950 } 6951 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 6952 } 6953 6954 /* output arrays */ 6955 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 6956 6957 /* get the point-to-point matrices; construct newPoints */ 6958 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6959 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6960 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 6961 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 6962 if (numFields) { 6963 for (p = 0, newP = 0; p < numPoints; p++) { 6964 PetscInt b = points[2 * p]; 6965 PetscInt o = points[2 * p + 1]; 6966 PetscInt bDof = 0, bSecDof; 6967 6968 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6969 if (!bSecDof) continue; 6970 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6971 if (bDof) { 6972 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6973 6974 fStart[0] = 0; 6975 fEnd[0] = 0; 6976 for (f = 0; f < numFields; f++) { 6977 PetscInt fDof; 6978 6979 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6980 fStart[f + 1] = fStart[f] + fDof; 6981 fEnd[f + 1] = fStart[f + 1]; 6982 } 6983 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6984 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6985 6986 fAnchorStart[0] = 0; 6987 fAnchorEnd[0] = 0; 6988 for (f = 0; f < numFields; f++) { 6989 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6990 6991 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 6992 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 6993 } 6994 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6995 for (q = 0; q < bDof; q++) { 6996 PetscInt a = anchors[bOff + q], aOff; 6997 6998 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6999 newPoints[2 * (newP + q)] = a; 7000 newPoints[2 * (newP + q) + 1] = 0; 7001 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7002 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7003 } 7004 newP += bDof; 7005 7006 if (outValues) { 7007 /* get the point-to-point submatrix */ 7008 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])); 7009 } 7010 } else { 7011 newPoints[2 * newP] = b; 7012 newPoints[2 * newP + 1] = o; 7013 newP++; 7014 } 7015 } 7016 } else { 7017 for (p = 0; p < numPoints; p++) { 7018 PetscInt b = points[2 * p]; 7019 PetscInt o = points[2 * p + 1]; 7020 PetscInt bDof = 0, bSecDof; 7021 7022 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7023 if (!bSecDof) continue; 7024 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7025 if (bDof) { 7026 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7027 7028 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7029 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7030 7031 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7032 for (q = 0; q < bDof; q++) { 7033 PetscInt a = anchors[bOff + q], aOff; 7034 7035 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7036 7037 newPoints[2 * (newP + q)] = a; 7038 newPoints[2 * (newP + q) + 1] = 0; 7039 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7040 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7041 } 7042 newP += bDof; 7043 7044 /* get the point-to-point submatrix */ 7045 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7046 } else { 7047 newPoints[2 * newP] = b; 7048 newPoints[2 * newP + 1] = o; 7049 newP++; 7050 } 7051 } 7052 } 7053 7054 if (outValues) { 7055 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7056 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7057 /* multiply constraints on the right */ 7058 if (numFields) { 7059 for (f = 0; f < numFields; f++) { 7060 PetscInt oldOff = offsets[f]; 7061 7062 for (p = 0; p < numPoints; p++) { 7063 PetscInt cStart = newPointOffsets[f][p]; 7064 PetscInt b = points[2 * p]; 7065 PetscInt c, r, k; 7066 PetscInt dof; 7067 7068 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7069 if (!dof) continue; 7070 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7071 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7072 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7073 7074 for (r = 0; r < numIndices; r++) { 7075 for (c = 0; c < nCols; c++) { 7076 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7077 } 7078 } 7079 } else { 7080 /* copy this column as is */ 7081 for (r = 0; r < numIndices; r++) { 7082 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7083 } 7084 } 7085 oldOff += dof; 7086 } 7087 } 7088 } else { 7089 PetscInt oldOff = 0; 7090 for (p = 0; p < numPoints; p++) { 7091 PetscInt cStart = newPointOffsets[0][p]; 7092 PetscInt b = points[2 * p]; 7093 PetscInt c, r, k; 7094 PetscInt dof; 7095 7096 PetscCall(PetscSectionGetDof(section, b, &dof)); 7097 if (!dof) continue; 7098 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7099 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7100 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7101 7102 for (r = 0; r < numIndices; r++) { 7103 for (c = 0; c < nCols; c++) { 7104 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7105 } 7106 } 7107 } else { 7108 /* copy this column as is */ 7109 for (r = 0; r < numIndices; r++) { 7110 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7111 } 7112 } 7113 oldOff += dof; 7114 } 7115 } 7116 7117 if (multiplyLeft) { 7118 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7119 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7120 /* multiply constraints transpose on the left */ 7121 if (numFields) { 7122 for (f = 0; f < numFields; f++) { 7123 PetscInt oldOff = offsets[f]; 7124 7125 for (p = 0; p < numPoints; p++) { 7126 PetscInt rStart = newPointOffsets[f][p]; 7127 PetscInt b = points[2 * p]; 7128 PetscInt c, r, k; 7129 PetscInt dof; 7130 7131 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7132 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7133 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7134 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7135 7136 for (r = 0; r < nRows; r++) { 7137 for (c = 0; c < newNumIndices; c++) { 7138 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7139 } 7140 } 7141 } else { 7142 /* copy this row as is */ 7143 for (r = 0; r < dof; r++) { 7144 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7145 } 7146 } 7147 oldOff += dof; 7148 } 7149 } 7150 } else { 7151 PetscInt oldOff = 0; 7152 7153 for (p = 0; p < numPoints; p++) { 7154 PetscInt rStart = newPointOffsets[0][p]; 7155 PetscInt b = points[2 * p]; 7156 PetscInt c, r, k; 7157 PetscInt dof; 7158 7159 PetscCall(PetscSectionGetDof(section, b, &dof)); 7160 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7161 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7162 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7163 7164 for (r = 0; r < nRows; r++) { 7165 for (c = 0; c < newNumIndices; c++) { 7166 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7167 } 7168 } 7169 } else { 7170 /* copy this row as is */ 7171 for (r = 0; r < dof; r++) { 7172 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7173 } 7174 } 7175 oldOff += dof; 7176 } 7177 } 7178 7179 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7180 } else { 7181 newValues = tmpValues; 7182 } 7183 } 7184 7185 /* clean up */ 7186 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7187 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7188 7189 if (numFields) { 7190 for (f = 0; f < numFields; f++) { 7191 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7192 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7193 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7194 } 7195 } else { 7196 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7197 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7198 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7199 } 7200 PetscCall(ISRestoreIndices(aIS, &anchors)); 7201 7202 /* output */ 7203 if (outPoints) { 7204 *outPoints = newPoints; 7205 } else { 7206 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7207 } 7208 if (outValues) *outValues = newValues; 7209 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7210 PetscFunctionReturn(0); 7211 } 7212 7213 /*@C 7214 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7215 7216 Not collective 7217 7218 Input Parameters: 7219 + dm - The DM 7220 . section - The PetscSection describing the points (a local section) 7221 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7222 . point - The point defining the closure 7223 - useClPerm - Use the closure point permutation if available 7224 7225 Output Parameters: 7226 + numIndices - The number of dof indices in the closure of point with the input sections 7227 . indices - The dof indices 7228 . outOffsets - Array to write the field offsets into, or NULL 7229 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7230 7231 Notes: 7232 Must call DMPlexRestoreClosureIndices() to free allocated memory 7233 7234 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7235 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7236 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7237 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7238 indices (with the above semantics) are implied. 7239 7240 Level: advanced 7241 7242 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7243 @*/ 7244 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7245 /* Closure ordering */ 7246 PetscSection clSection; 7247 IS clPoints; 7248 const PetscInt *clp; 7249 PetscInt *points; 7250 const PetscInt *clperm = NULL; 7251 /* Dof permutation and sign flips */ 7252 const PetscInt **perms[32] = {NULL}; 7253 const PetscScalar **flips[32] = {NULL}; 7254 PetscScalar *valCopy = NULL; 7255 /* Hanging node constraints */ 7256 PetscInt *pointsC = NULL; 7257 PetscScalar *valuesC = NULL; 7258 PetscInt NclC, NiC; 7259 7260 PetscInt *idx; 7261 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7262 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7263 7264 PetscFunctionBeginHot; 7265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7266 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7267 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7268 if (numIndices) PetscValidIntPointer(numIndices, 6); 7269 if (indices) PetscValidPointer(indices, 7); 7270 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7271 if (values) PetscValidPointer(values, 9); 7272 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7273 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7274 PetscCall(PetscArrayzero(offsets, 32)); 7275 /* 1) Get points in closure */ 7276 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7277 if (useClPerm) { 7278 PetscInt depth, clsize; 7279 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7280 for (clsize = 0, p = 0; p < Ncl; p++) { 7281 PetscInt dof; 7282 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7283 clsize += dof; 7284 } 7285 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7286 } 7287 /* 2) Get number of indices on these points and field offsets from section */ 7288 for (p = 0; p < Ncl * 2; p += 2) { 7289 PetscInt dof, fdof; 7290 7291 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7292 for (f = 0; f < Nf; ++f) { 7293 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7294 offsets[f + 1] += fdof; 7295 } 7296 Ni += dof; 7297 } 7298 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7299 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7300 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7301 for (f = 0; f < PetscMax(1, Nf); ++f) { 7302 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7303 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7304 /* may need to apply sign changes to the element matrix */ 7305 if (values && flips[f]) { 7306 PetscInt foffset = offsets[f]; 7307 7308 for (p = 0; p < Ncl; ++p) { 7309 PetscInt pnt = points[2 * p], fdof; 7310 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7311 7312 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7313 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7314 if (flip) { 7315 PetscInt i, j, k; 7316 7317 if (!valCopy) { 7318 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7319 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7320 *values = valCopy; 7321 } 7322 for (i = 0; i < fdof; ++i) { 7323 PetscScalar fval = flip[i]; 7324 7325 for (k = 0; k < Ni; ++k) { 7326 valCopy[Ni * (foffset + i) + k] *= fval; 7327 valCopy[Ni * k + (foffset + i)] *= fval; 7328 } 7329 } 7330 } 7331 foffset += fdof; 7332 } 7333 } 7334 } 7335 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7336 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7337 if (NclC) { 7338 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7339 for (f = 0; f < PetscMax(1, Nf); ++f) { 7340 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7341 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7342 } 7343 for (f = 0; f < PetscMax(1, Nf); ++f) { 7344 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7345 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7346 } 7347 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7348 Ncl = NclC; 7349 Ni = NiC; 7350 points = pointsC; 7351 if (values) *values = valuesC; 7352 } 7353 /* 5) Calculate indices */ 7354 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7355 if (Nf) { 7356 PetscInt idxOff; 7357 PetscBool useFieldOffsets; 7358 7359 if (outOffsets) { 7360 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7361 } 7362 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7363 if (useFieldOffsets) { 7364 for (p = 0; p < Ncl; ++p) { 7365 const PetscInt pnt = points[p * 2]; 7366 7367 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7368 } 7369 } else { 7370 for (p = 0; p < Ncl; ++p) { 7371 const PetscInt pnt = points[p * 2]; 7372 7373 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7374 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7375 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7376 * global section. */ 7377 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7378 } 7379 } 7380 } else { 7381 PetscInt off = 0, idxOff; 7382 7383 for (p = 0; p < Ncl; ++p) { 7384 const PetscInt pnt = points[p * 2]; 7385 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7386 7387 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7388 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7389 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7390 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7391 } 7392 } 7393 /* 6) Cleanup */ 7394 for (f = 0; f < PetscMax(1, Nf); ++f) { 7395 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7396 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7397 } 7398 if (NclC) { 7399 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7400 } else { 7401 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7402 } 7403 7404 if (numIndices) *numIndices = Ni; 7405 if (indices) *indices = idx; 7406 PetscFunctionReturn(0); 7407 } 7408 7409 /*@C 7410 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7411 7412 Not collective 7413 7414 Input Parameters: 7415 + dm - The DM 7416 . section - The PetscSection describing the points (a local section) 7417 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7418 . point - The point defining the closure 7419 - useClPerm - Use the closure point permutation if available 7420 7421 Output Parameters: 7422 + numIndices - The number of dof indices in the closure of point with the input sections 7423 . indices - The dof indices 7424 . outOffsets - Array to write the field offsets into, or NULL 7425 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7426 7427 Notes: 7428 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7429 7430 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7431 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7432 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7433 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7434 indices (with the above semantics) are implied. 7435 7436 Level: advanced 7437 7438 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7439 @*/ 7440 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7441 PetscFunctionBegin; 7442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7443 PetscValidPointer(indices, 7); 7444 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7445 PetscFunctionReturn(0); 7446 } 7447 7448 /*@C 7449 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7450 7451 Not collective 7452 7453 Input Parameters: 7454 + dm - The DM 7455 . section - The section describing the layout in v, or NULL to use the default section 7456 . globalSection - The section describing the layout in v, or NULL to use the default global section 7457 . A - The matrix 7458 . point - The point in the DM 7459 . values - The array of values 7460 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7461 7462 Fortran Notes: 7463 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7464 7465 Level: intermediate 7466 7467 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7468 @*/ 7469 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7470 DM_Plex *mesh = (DM_Plex *)dm->data; 7471 PetscInt *indices; 7472 PetscInt numIndices; 7473 const PetscScalar *valuesOrig = values; 7474 PetscErrorCode ierr; 7475 7476 PetscFunctionBegin; 7477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7478 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7479 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7480 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7481 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7482 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7483 7484 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7485 7486 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7487 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7488 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7489 if (ierr) { 7490 PetscMPIInt rank; 7491 7492 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7493 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7494 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7495 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7496 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7497 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7498 } 7499 if (mesh->printFEM > 1) { 7500 PetscInt i; 7501 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7502 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7503 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7504 } 7505 7506 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7507 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7508 PetscFunctionReturn(0); 7509 } 7510 7511 /*@C 7512 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7513 7514 Not collective 7515 7516 Input Parameters: 7517 + dmRow - The DM for the row fields 7518 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7519 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7520 . dmCol - The DM for the column fields 7521 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7522 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7523 . A - The matrix 7524 . point - The point in the DMs 7525 . values - The array of values 7526 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7527 7528 Level: intermediate 7529 7530 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7531 @*/ 7532 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7533 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7534 PetscInt *indicesRow, *indicesCol; 7535 PetscInt numIndicesRow, numIndicesCol; 7536 const PetscScalar *valuesOrig = values; 7537 PetscErrorCode ierr; 7538 7539 PetscFunctionBegin; 7540 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7541 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7542 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7543 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7544 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7545 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7546 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7547 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7548 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7549 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7550 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7551 7552 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7553 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7554 7555 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7556 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7557 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7558 if (ierr) { 7559 PetscMPIInt rank; 7560 7561 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7562 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7563 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7564 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7565 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7566 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7567 } 7568 7569 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7570 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7571 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7572 PetscFunctionReturn(0); 7573 } 7574 7575 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7576 DM_Plex *mesh = (DM_Plex *)dmf->data; 7577 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7578 PetscInt *cpoints = NULL; 7579 PetscInt *findices, *cindices; 7580 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7581 PetscInt foffsets[32], coffsets[32]; 7582 DMPolytopeType ct; 7583 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7584 PetscErrorCode ierr; 7585 7586 PetscFunctionBegin; 7587 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7588 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7589 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7590 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7591 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7592 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7593 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7594 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7595 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7596 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7597 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7598 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7599 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7600 PetscCall(PetscArrayzero(foffsets, 32)); 7601 PetscCall(PetscArrayzero(coffsets, 32)); 7602 /* Column indices */ 7603 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7604 maxFPoints = numCPoints; 7605 /* Compress out points not in the section */ 7606 /* TODO: Squeeze out points with 0 dof as well */ 7607 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7608 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7609 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7610 cpoints[q * 2] = cpoints[p]; 7611 cpoints[q * 2 + 1] = cpoints[p + 1]; 7612 ++q; 7613 } 7614 } 7615 numCPoints = q; 7616 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7617 PetscInt fdof; 7618 7619 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7620 if (!dof) continue; 7621 for (f = 0; f < numFields; ++f) { 7622 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7623 coffsets[f + 1] += fdof; 7624 } 7625 numCIndices += dof; 7626 } 7627 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7628 /* Row indices */ 7629 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7630 { 7631 DMPlexTransform tr; 7632 DMPolytopeType *rct; 7633 PetscInt *rsize, *rcone, *rornt, Nt; 7634 7635 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7636 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7637 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7638 numSubcells = rsize[Nt - 1]; 7639 PetscCall(DMPlexTransformDestroy(&tr)); 7640 } 7641 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7642 for (r = 0, q = 0; r < numSubcells; ++r) { 7643 /* TODO Map from coarse to fine cells */ 7644 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7645 /* Compress out points not in the section */ 7646 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7647 for (p = 0; p < numFPoints * 2; p += 2) { 7648 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7649 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7650 if (!dof) continue; 7651 for (s = 0; s < q; ++s) 7652 if (fpoints[p] == ftotpoints[s * 2]) break; 7653 if (s < q) continue; 7654 ftotpoints[q * 2] = fpoints[p]; 7655 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7656 ++q; 7657 } 7658 } 7659 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7660 } 7661 numFPoints = q; 7662 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7663 PetscInt fdof; 7664 7665 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7666 if (!dof) continue; 7667 for (f = 0; f < numFields; ++f) { 7668 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7669 foffsets[f + 1] += fdof; 7670 } 7671 numFIndices += dof; 7672 } 7673 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7674 7675 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7676 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7677 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7678 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7679 if (numFields) { 7680 const PetscInt **permsF[32] = {NULL}; 7681 const PetscInt **permsC[32] = {NULL}; 7682 7683 for (f = 0; f < numFields; f++) { 7684 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7685 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7686 } 7687 for (p = 0; p < numFPoints; p++) { 7688 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7689 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7690 } 7691 for (p = 0; p < numCPoints; p++) { 7692 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7693 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7694 } 7695 for (f = 0; f < numFields; f++) { 7696 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7697 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7698 } 7699 } else { 7700 const PetscInt **permsF = NULL; 7701 const PetscInt **permsC = NULL; 7702 7703 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7704 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7705 for (p = 0, off = 0; p < numFPoints; p++) { 7706 const PetscInt *perm = permsF ? permsF[p] : NULL; 7707 7708 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7709 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7710 } 7711 for (p = 0, off = 0; p < numCPoints; p++) { 7712 const PetscInt *perm = permsC ? permsC[p] : NULL; 7713 7714 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7715 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7716 } 7717 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7718 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7719 } 7720 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7721 /* TODO: flips */ 7722 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7723 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7724 if (ierr) { 7725 PetscMPIInt rank; 7726 7727 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7728 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7729 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7730 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7731 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7732 } 7733 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7734 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7735 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7736 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7737 PetscFunctionReturn(0); 7738 } 7739 7740 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) { 7741 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7742 PetscInt *cpoints = NULL; 7743 PetscInt foffsets[32], coffsets[32]; 7744 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7745 DMPolytopeType ct; 7746 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7747 7748 PetscFunctionBegin; 7749 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7750 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7751 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7752 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7753 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7754 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7755 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7756 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7757 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7758 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7759 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7760 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7761 PetscCall(PetscArrayzero(foffsets, 32)); 7762 PetscCall(PetscArrayzero(coffsets, 32)); 7763 /* Column indices */ 7764 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7765 maxFPoints = numCPoints; 7766 /* Compress out points not in the section */ 7767 /* TODO: Squeeze out points with 0 dof as well */ 7768 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7769 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7770 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7771 cpoints[q * 2] = cpoints[p]; 7772 cpoints[q * 2 + 1] = cpoints[p + 1]; 7773 ++q; 7774 } 7775 } 7776 numCPoints = q; 7777 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7778 PetscInt fdof; 7779 7780 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7781 if (!dof) continue; 7782 for (f = 0; f < numFields; ++f) { 7783 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7784 coffsets[f + 1] += fdof; 7785 } 7786 numCIndices += dof; 7787 } 7788 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7789 /* Row indices */ 7790 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7791 { 7792 DMPlexTransform tr; 7793 DMPolytopeType *rct; 7794 PetscInt *rsize, *rcone, *rornt, Nt; 7795 7796 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7797 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7798 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7799 numSubcells = rsize[Nt - 1]; 7800 PetscCall(DMPlexTransformDestroy(&tr)); 7801 } 7802 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7803 for (r = 0, q = 0; r < numSubcells; ++r) { 7804 /* TODO Map from coarse to fine cells */ 7805 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7806 /* Compress out points not in the section */ 7807 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7808 for (p = 0; p < numFPoints * 2; p += 2) { 7809 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7810 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7811 if (!dof) continue; 7812 for (s = 0; s < q; ++s) 7813 if (fpoints[p] == ftotpoints[s * 2]) break; 7814 if (s < q) continue; 7815 ftotpoints[q * 2] = fpoints[p]; 7816 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7817 ++q; 7818 } 7819 } 7820 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7821 } 7822 numFPoints = q; 7823 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7824 PetscInt fdof; 7825 7826 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7827 if (!dof) continue; 7828 for (f = 0; f < numFields; ++f) { 7829 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7830 foffsets[f + 1] += fdof; 7831 } 7832 numFIndices += dof; 7833 } 7834 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7835 7836 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7837 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7838 if (numFields) { 7839 const PetscInt **permsF[32] = {NULL}; 7840 const PetscInt **permsC[32] = {NULL}; 7841 7842 for (f = 0; f < numFields; f++) { 7843 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7844 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7845 } 7846 for (p = 0; p < numFPoints; p++) { 7847 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7848 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7849 } 7850 for (p = 0; p < numCPoints; p++) { 7851 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7852 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7853 } 7854 for (f = 0; f < numFields; f++) { 7855 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7856 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7857 } 7858 } else { 7859 const PetscInt **permsF = NULL; 7860 const PetscInt **permsC = NULL; 7861 7862 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7863 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7864 for (p = 0, off = 0; p < numFPoints; p++) { 7865 const PetscInt *perm = permsF ? permsF[p] : NULL; 7866 7867 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7868 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7869 } 7870 for (p = 0, off = 0; p < numCPoints; p++) { 7871 const PetscInt *perm = permsC ? permsC[p] : NULL; 7872 7873 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7874 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7875 } 7876 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7877 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7878 } 7879 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7880 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7881 PetscFunctionReturn(0); 7882 } 7883 7884 /*@C 7885 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7886 7887 Input Parameter: 7888 . dm - The DMPlex object 7889 7890 Output Parameter: 7891 . cellHeight - The height of a cell 7892 7893 Level: developer 7894 7895 .seealso `DMPlexSetVTKCellHeight()` 7896 @*/ 7897 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) { 7898 DM_Plex *mesh = (DM_Plex *)dm->data; 7899 7900 PetscFunctionBegin; 7901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7902 PetscValidIntPointer(cellHeight, 2); 7903 *cellHeight = mesh->vtkCellHeight; 7904 PetscFunctionReturn(0); 7905 } 7906 7907 /*@C 7908 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7909 7910 Input Parameters: 7911 + dm - The DMPlex object 7912 - cellHeight - The height of a cell 7913 7914 Level: developer 7915 7916 .seealso `DMPlexGetVTKCellHeight()` 7917 @*/ 7918 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) { 7919 DM_Plex *mesh = (DM_Plex *)dm->data; 7920 7921 PetscFunctionBegin; 7922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7923 mesh->vtkCellHeight = cellHeight; 7924 PetscFunctionReturn(0); 7925 } 7926 7927 /*@ 7928 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7929 7930 Input Parameter: 7931 . dm - The DMPlex object 7932 7933 Output Parameters: 7934 + gcStart - The first ghost cell, or NULL 7935 - gcEnd - The upper bound on ghost cells, or NULL 7936 7937 Level: advanced 7938 7939 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7940 @*/ 7941 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) { 7942 DMLabel ctLabel; 7943 7944 PetscFunctionBegin; 7945 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7946 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7947 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7948 // Reset label for fast lookup 7949 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 7950 PetscFunctionReturn(0); 7951 } 7952 7953 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) { 7954 PetscSection section, globalSection; 7955 PetscInt *numbers, p; 7956 7957 PetscFunctionBegin; 7958 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 7959 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 7960 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 7961 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 7962 PetscCall(PetscSectionSetUp(section)); 7963 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 7964 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 7965 for (p = pStart; p < pEnd; ++p) { 7966 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 7967 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 7968 else numbers[p - pStart] += shift; 7969 } 7970 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 7971 if (globalSize) { 7972 PetscLayout layout; 7973 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 7974 PetscCall(PetscLayoutGetSize(layout, globalSize)); 7975 PetscCall(PetscLayoutDestroy(&layout)); 7976 } 7977 PetscCall(PetscSectionDestroy(§ion)); 7978 PetscCall(PetscSectionDestroy(&globalSection)); 7979 PetscFunctionReturn(0); 7980 } 7981 7982 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) { 7983 PetscInt cellHeight, cStart, cEnd; 7984 7985 PetscFunctionBegin; 7986 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 7987 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 7988 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 7989 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 7990 PetscFunctionReturn(0); 7991 } 7992 7993 /*@ 7994 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 7995 7996 Input Parameter: 7997 . dm - The DMPlex object 7998 7999 Output Parameter: 8000 . globalCellNumbers - Global cell numbers for all cells on this process 8001 8002 Level: developer 8003 8004 .seealso `DMPlexGetVertexNumbering()` 8005 @*/ 8006 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) { 8007 DM_Plex *mesh = (DM_Plex *)dm->data; 8008 8009 PetscFunctionBegin; 8010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8011 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8012 *globalCellNumbers = mesh->globalCellNumbers; 8013 PetscFunctionReturn(0); 8014 } 8015 8016 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) { 8017 PetscInt vStart, vEnd; 8018 8019 PetscFunctionBegin; 8020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8021 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8022 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8023 PetscFunctionReturn(0); 8024 } 8025 8026 /*@ 8027 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8028 8029 Input Parameter: 8030 . dm - The DMPlex object 8031 8032 Output Parameter: 8033 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8034 8035 Level: developer 8036 8037 .seealso `DMPlexGetCellNumbering()` 8038 @*/ 8039 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) { 8040 DM_Plex *mesh = (DM_Plex *)dm->data; 8041 8042 PetscFunctionBegin; 8043 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8044 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8045 *globalVertexNumbers = mesh->globalVertexNumbers; 8046 PetscFunctionReturn(0); 8047 } 8048 8049 /*@ 8050 DMPlexCreatePointNumbering - Create a global numbering for all points. 8051 8052 Collective on dm 8053 8054 Input Parameter: 8055 . dm - The DMPlex object 8056 8057 Output Parameter: 8058 . globalPointNumbers - Global numbers for all points on this process 8059 8060 Notes: 8061 8062 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8063 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8064 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8065 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8066 8067 The partitioned mesh is 8068 ``` 8069 (2)--0--(3)--1--(4) (1)--0--(2) 8070 ``` 8071 and its global numbering is 8072 ``` 8073 (3)--0--(4)--1--(5)--2--(6) 8074 ``` 8075 Then the global numbering is provided as 8076 ``` 8077 [0] Number of indices in set 5 8078 [0] 0 0 8079 [0] 1 1 8080 [0] 2 3 8081 [0] 3 4 8082 [0] 4 -6 8083 [1] Number of indices in set 3 8084 [1] 0 2 8085 [1] 1 5 8086 [1] 2 6 8087 ``` 8088 8089 Level: developer 8090 8091 .seealso `DMPlexGetCellNumbering()` 8092 @*/ 8093 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) { 8094 IS nums[4]; 8095 PetscInt depths[4], gdepths[4], starts[4]; 8096 PetscInt depth, d, shift = 0; 8097 PetscBool empty = PETSC_FALSE; 8098 8099 PetscFunctionBegin; 8100 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8101 PetscCall(DMPlexGetDepth(dm, &depth)); 8102 // For unstratified meshes use dim instead of depth 8103 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8104 // If any stratum is empty, we must mark all empty 8105 for (d = 0; d <= depth; ++d) { 8106 PetscInt end; 8107 8108 depths[d] = depth - d; 8109 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8110 if (!(starts[d] - end)) empty = PETSC_TRUE; 8111 } 8112 if (empty) 8113 for (d = 0; d <= depth; ++d) { 8114 depths[d] = -1; 8115 starts[d] = -1; 8116 } 8117 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8118 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8119 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]); 8120 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8121 for (d = 0; d <= depth; ++d) { 8122 PetscInt pStart, pEnd, gsize; 8123 8124 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8125 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8126 shift += gsize; 8127 } 8128 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8129 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8130 PetscFunctionReturn(0); 8131 } 8132 8133 /*@ 8134 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8135 8136 Input Parameter: 8137 . dm - The DMPlex object 8138 8139 Output Parameter: 8140 . ranks - The rank field 8141 8142 Options Database Keys: 8143 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8144 8145 Level: intermediate 8146 8147 .seealso: `DMView()` 8148 @*/ 8149 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) { 8150 DM rdm; 8151 PetscFE fe; 8152 PetscScalar *r; 8153 PetscMPIInt rank; 8154 DMPolytopeType ct; 8155 PetscInt dim, cStart, cEnd, c; 8156 PetscBool simplex; 8157 8158 PetscFunctionBeginUser; 8159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8160 PetscValidPointer(ranks, 2); 8161 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8162 PetscCall(DMClone(dm, &rdm)); 8163 PetscCall(DMGetDimension(rdm, &dim)); 8164 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8165 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8166 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8167 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8168 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8169 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8170 PetscCall(PetscFEDestroy(&fe)); 8171 PetscCall(DMCreateDS(rdm)); 8172 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8173 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8174 PetscCall(VecGetArray(*ranks, &r)); 8175 for (c = cStart; c < cEnd; ++c) { 8176 PetscScalar *lr; 8177 8178 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8179 if (lr) *lr = rank; 8180 } 8181 PetscCall(VecRestoreArray(*ranks, &r)); 8182 PetscCall(DMDestroy(&rdm)); 8183 PetscFunctionReturn(0); 8184 } 8185 8186 /*@ 8187 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8188 8189 Input Parameters: 8190 + dm - The DMPlex 8191 - label - The DMLabel 8192 8193 Output Parameter: 8194 . val - The label value field 8195 8196 Options Database Keys: 8197 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8198 8199 Level: intermediate 8200 8201 .seealso: `DMView()` 8202 @*/ 8203 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) { 8204 DM rdm; 8205 PetscFE fe; 8206 PetscScalar *v; 8207 PetscInt dim, cStart, cEnd, c; 8208 8209 PetscFunctionBeginUser; 8210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8211 PetscValidPointer(label, 2); 8212 PetscValidPointer(val, 3); 8213 PetscCall(DMClone(dm, &rdm)); 8214 PetscCall(DMGetDimension(rdm, &dim)); 8215 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8216 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8217 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8218 PetscCall(PetscFEDestroy(&fe)); 8219 PetscCall(DMCreateDS(rdm)); 8220 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8221 PetscCall(DMCreateGlobalVector(rdm, val)); 8222 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8223 PetscCall(VecGetArray(*val, &v)); 8224 for (c = cStart; c < cEnd; ++c) { 8225 PetscScalar *lv; 8226 PetscInt cval; 8227 8228 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8229 PetscCall(DMLabelGetValue(label, c, &cval)); 8230 *lv = cval; 8231 } 8232 PetscCall(VecRestoreArray(*val, &v)); 8233 PetscCall(DMDestroy(&rdm)); 8234 PetscFunctionReturn(0); 8235 } 8236 8237 /*@ 8238 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8239 8240 Input Parameter: 8241 . dm - The DMPlex object 8242 8243 Notes: 8244 This is a useful diagnostic when creating meshes programmatically. 8245 8246 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8247 8248 Level: developer 8249 8250 .seealso: `DMCreate()`, `DMSetFromOptions()` 8251 @*/ 8252 PetscErrorCode DMPlexCheckSymmetry(DM dm) { 8253 PetscSection coneSection, supportSection; 8254 const PetscInt *cone, *support; 8255 PetscInt coneSize, c, supportSize, s; 8256 PetscInt pStart, pEnd, p, pp, csize, ssize; 8257 PetscBool storagecheck = PETSC_TRUE; 8258 8259 PetscFunctionBegin; 8260 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8261 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8262 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8263 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8264 /* Check that point p is found in the support of its cone points, and vice versa */ 8265 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8266 for (p = pStart; p < pEnd; ++p) { 8267 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8268 PetscCall(DMPlexGetCone(dm, p, &cone)); 8269 for (c = 0; c < coneSize; ++c) { 8270 PetscBool dup = PETSC_FALSE; 8271 PetscInt d; 8272 for (d = c - 1; d >= 0; --d) { 8273 if (cone[c] == cone[d]) { 8274 dup = PETSC_TRUE; 8275 break; 8276 } 8277 } 8278 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8279 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8280 for (s = 0; s < supportSize; ++s) { 8281 if (support[s] == p) break; 8282 } 8283 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8284 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8285 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8286 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8287 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8288 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8289 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8290 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]); 8291 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8292 } 8293 } 8294 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8295 if (p != pp) { 8296 storagecheck = PETSC_FALSE; 8297 continue; 8298 } 8299 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8300 PetscCall(DMPlexGetSupport(dm, p, &support)); 8301 for (s = 0; s < supportSize; ++s) { 8302 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8303 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8304 for (c = 0; c < coneSize; ++c) { 8305 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8306 if (cone[c] != pp) { 8307 c = 0; 8308 break; 8309 } 8310 if (cone[c] == p) break; 8311 } 8312 if (c >= coneSize) { 8313 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8314 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8315 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8316 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8317 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8318 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8319 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8320 } 8321 } 8322 } 8323 if (storagecheck) { 8324 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8325 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8326 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8327 } 8328 PetscFunctionReturn(0); 8329 } 8330 8331 /* 8332 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. 8333 */ 8334 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) { 8335 DMPolytopeType cct; 8336 PetscInt ptpoints[4]; 8337 const PetscInt *cone, *ccone, *ptcone; 8338 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8339 8340 PetscFunctionBegin; 8341 *unsplit = 0; 8342 switch (ct) { 8343 case DM_POLYTOPE_POINT_PRISM_TENSOR: ptpoints[npt++] = c; break; 8344 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8345 PetscCall(DMPlexGetCone(dm, c, &cone)); 8346 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8347 for (cp = 0; cp < coneSize; ++cp) { 8348 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8349 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8350 } 8351 break; 8352 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8353 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8354 PetscCall(DMPlexGetCone(dm, c, &cone)); 8355 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8356 for (cp = 0; cp < coneSize; ++cp) { 8357 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8358 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8359 for (ccp = 0; ccp < cconeSize; ++ccp) { 8360 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8361 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8362 PetscInt p; 8363 for (p = 0; p < npt; ++p) 8364 if (ptpoints[p] == ccone[ccp]) break; 8365 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8366 } 8367 } 8368 } 8369 break; 8370 default: break; 8371 } 8372 for (pt = 0; pt < npt; ++pt) { 8373 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8374 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8375 } 8376 PetscFunctionReturn(0); 8377 } 8378 8379 /*@ 8380 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8381 8382 Input Parameters: 8383 + dm - The DMPlex object 8384 - cellHeight - Normally 0 8385 8386 Notes: 8387 This is a useful diagnostic when creating meshes programmatically. 8388 Currently applicable only to homogeneous simplex or tensor meshes. 8389 8390 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8391 8392 Level: developer 8393 8394 .seealso: `DMCreate()`, `DMSetFromOptions()` 8395 @*/ 8396 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) { 8397 DMPlexInterpolatedFlag interp; 8398 DMPolytopeType ct; 8399 PetscInt vStart, vEnd, cStart, cEnd, c; 8400 8401 PetscFunctionBegin; 8402 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8403 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8404 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8405 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8406 for (c = cStart; c < cEnd; ++c) { 8407 PetscInt *closure = NULL; 8408 PetscInt coneSize, closureSize, cl, Nv = 0; 8409 8410 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8411 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8412 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8413 if (interp == DMPLEX_INTERPOLATED_FULL) { 8414 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8415 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)); 8416 } 8417 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8418 for (cl = 0; cl < closureSize * 2; cl += 2) { 8419 const PetscInt p = closure[cl]; 8420 if ((p >= vStart) && (p < vEnd)) ++Nv; 8421 } 8422 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8423 /* Special Case: Tensor faces with identified vertices */ 8424 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8425 PetscInt unsplit; 8426 8427 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8428 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8429 } 8430 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)); 8431 } 8432 PetscFunctionReturn(0); 8433 } 8434 8435 /*@ 8436 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8437 8438 Collective 8439 8440 Input Parameters: 8441 + dm - The DMPlex object 8442 - cellHeight - Normally 0 8443 8444 Notes: 8445 This is a useful diagnostic when creating meshes programmatically. 8446 This routine is only relevant for meshes that are fully interpolated across all ranks. 8447 It will error out if a partially interpolated mesh is given on some rank. 8448 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8449 8450 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8451 8452 Level: developer 8453 8454 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8455 @*/ 8456 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) { 8457 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8458 DMPlexInterpolatedFlag interpEnum; 8459 8460 PetscFunctionBegin; 8461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8462 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8463 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8464 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8465 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8466 PetscFunctionReturn(0); 8467 } 8468 8469 PetscCall(DMGetDimension(dm, &dim)); 8470 PetscCall(DMPlexGetDepth(dm, &depth)); 8471 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8472 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8473 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8474 for (c = cStart; c < cEnd; ++c) { 8475 const PetscInt *cone, *ornt, *faceSizes, *faces; 8476 const DMPolytopeType *faceTypes; 8477 DMPolytopeType ct; 8478 PetscInt numFaces, coneSize, f; 8479 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8480 8481 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8482 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8483 if (unsplit) continue; 8484 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8485 PetscCall(DMPlexGetCone(dm, c, &cone)); 8486 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8487 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8488 for (cl = 0; cl < closureSize * 2; cl += 2) { 8489 const PetscInt p = closure[cl]; 8490 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8491 } 8492 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8493 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); 8494 for (f = 0; f < numFaces; ++f) { 8495 DMPolytopeType fct; 8496 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8497 8498 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8499 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8500 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8501 const PetscInt p = fclosure[cl]; 8502 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8503 } 8504 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]); 8505 for (v = 0; v < fnumCorners; ++v) { 8506 if (fclosure[v] != faces[fOff + v]) { 8507 PetscInt v1; 8508 8509 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8510 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8511 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8512 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8513 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8514 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]); 8515 } 8516 } 8517 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8518 fOff += faceSizes[f]; 8519 } 8520 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8521 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8522 } 8523 } 8524 PetscFunctionReturn(0); 8525 } 8526 8527 /*@ 8528 DMPlexCheckGeometry - Check the geometry of mesh cells 8529 8530 Input Parameter: 8531 . dm - The DMPlex object 8532 8533 Notes: 8534 This is a useful diagnostic when creating meshes programmatically. 8535 8536 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8537 8538 Level: developer 8539 8540 .seealso: `DMCreate()`, `DMSetFromOptions()` 8541 @*/ 8542 PetscErrorCode DMPlexCheckGeometry(DM dm) { 8543 Vec coordinates; 8544 PetscReal detJ, J[9], refVol = 1.0; 8545 PetscReal vol; 8546 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8547 8548 PetscFunctionBegin; 8549 PetscCall(DMGetDimension(dm, &dim)); 8550 PetscCall(DMGetCoordinateDim(dm, &dE)); 8551 if (dim != dE) PetscFunctionReturn(0); 8552 PetscCall(DMPlexGetDepth(dm, &depth)); 8553 for (d = 0; d < dim; ++d) refVol *= 2.0; 8554 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8555 /* Make sure local coordinates are created, because that step is collective */ 8556 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8557 for (c = cStart; c < cEnd; ++c) { 8558 DMPolytopeType ct; 8559 PetscInt unsplit; 8560 PetscBool ignoreZeroVol = PETSC_FALSE; 8561 8562 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8563 switch (ct) { 8564 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8565 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8566 case DM_POLYTOPE_QUAD_PRISM_TENSOR: ignoreZeroVol = PETSC_TRUE; break; 8567 default: break; 8568 } 8569 switch (ct) { 8570 case DM_POLYTOPE_TRI_PRISM: 8571 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8572 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8573 case DM_POLYTOPE_PYRAMID: continue; 8574 default: break; 8575 } 8576 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8577 if (unsplit) continue; 8578 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8579 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); 8580 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8581 /* This should work with periodicity since DG coordinates should be used */ 8582 if (depth > 1) { 8583 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8584 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); 8585 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8586 } 8587 } 8588 PetscFunctionReturn(0); 8589 } 8590 8591 /*@ 8592 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8593 8594 Collective 8595 8596 Input Parameters: 8597 + dm - The DMPlex object 8598 . pointSF - The Point SF, or NULL for Point SF attached to DM 8599 - allowExtraRoots - Flag to allow extra points not present in the DM 8600 8601 Notes: 8602 This is mainly intended for debugging/testing purposes. 8603 8604 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8605 8606 Extra roots can come from priodic cuts, where additional points appear on the boundary 8607 8608 Level: developer 8609 8610 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8611 @*/ 8612 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) { 8613 PetscInt l, nleaves, nroots, overlap; 8614 const PetscInt *locals; 8615 const PetscSFNode *remotes; 8616 PetscBool distributed; 8617 MPI_Comm comm; 8618 PetscMPIInt rank; 8619 8620 PetscFunctionBegin; 8621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8622 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8623 else pointSF = dm->sf; 8624 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8625 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8626 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8627 { 8628 PetscMPIInt mpiFlag; 8629 8630 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8631 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8632 } 8633 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8634 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8635 if (!distributed) { 8636 PetscCheck(nroots < 0 || nleaves == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Undistributed DMPlex cannot have non-empty PointSF (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8637 PetscFunctionReturn(0); 8638 } 8639 PetscCheck(nroots >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8640 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8641 8642 /* Check SF graph is compatible with DMPlex chart */ 8643 { 8644 PetscInt pStart, pEnd, maxLeaf; 8645 8646 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8647 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8648 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8649 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8650 } 8651 8652 /* Check Point SF has no local points referenced */ 8653 for (l = 0; l < nleaves; l++) { 8654 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 8655 } 8656 8657 /* Check there are no cells in interface */ 8658 if (!overlap) { 8659 PetscInt cellHeight, cStart, cEnd; 8660 8661 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8662 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8663 for (l = 0; l < nleaves; ++l) { 8664 const PetscInt point = locals ? locals[l] : l; 8665 8666 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8667 } 8668 } 8669 8670 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8671 { 8672 const PetscInt *rootdegree; 8673 8674 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8675 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8676 for (l = 0; l < nleaves; ++l) { 8677 const PetscInt point = locals ? locals[l] : l; 8678 const PetscInt *cone; 8679 PetscInt coneSize, c, idx; 8680 8681 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8682 PetscCall(DMPlexGetCone(dm, point, &cone)); 8683 for (c = 0; c < coneSize; ++c) { 8684 if (!rootdegree[cone[c]]) { 8685 if (locals) { 8686 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8687 } else { 8688 idx = (cone[c] < nleaves) ? cone[c] : -1; 8689 } 8690 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8691 } 8692 } 8693 } 8694 } 8695 PetscFunctionReturn(0); 8696 } 8697 8698 /*@ 8699 DMPlexCheck - Perform various checks of Plex sanity 8700 8701 Input Parameter: 8702 . dm - The DMPlex object 8703 8704 Notes: 8705 This is a useful diagnostic when creating meshes programmatically. 8706 8707 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8708 8709 Currently does not include DMPlexCheckCellShape(). 8710 8711 Level: developer 8712 8713 .seealso: DMCreate(), DMSetFromOptions() 8714 @*/ 8715 PetscErrorCode DMPlexCheck(DM dm) { 8716 PetscInt cellHeight; 8717 8718 PetscFunctionBegin; 8719 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8720 PetscCall(DMPlexCheckSymmetry(dm)); 8721 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8722 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8723 PetscCall(DMPlexCheckGeometry(dm)); 8724 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 8725 PetscCall(DMPlexCheckInterfaceCones(dm)); 8726 PetscFunctionReturn(0); 8727 } 8728 8729 typedef struct cell_stats { 8730 PetscReal min, max, sum, squaresum; 8731 PetscInt count; 8732 } cell_stats_t; 8733 8734 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) { 8735 PetscInt i, N = *len; 8736 8737 for (i = 0; i < N; i++) { 8738 cell_stats_t *A = (cell_stats_t *)a; 8739 cell_stats_t *B = (cell_stats_t *)b; 8740 8741 B->min = PetscMin(A->min, B->min); 8742 B->max = PetscMax(A->max, B->max); 8743 B->sum += A->sum; 8744 B->squaresum += A->squaresum; 8745 B->count += A->count; 8746 } 8747 } 8748 8749 /*@ 8750 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8751 8752 Collective on dm 8753 8754 Input Parameters: 8755 + dm - The DMPlex object 8756 . output - If true, statistics will be displayed on stdout 8757 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8758 8759 Notes: 8760 This is mainly intended for debugging/testing purposes. 8761 8762 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8763 8764 Level: developer 8765 8766 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8767 @*/ 8768 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) { 8769 DM dmCoarse; 8770 cell_stats_t stats, globalStats; 8771 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8772 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8773 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8774 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8775 PetscMPIInt rank, size; 8776 8777 PetscFunctionBegin; 8778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8779 stats.min = PETSC_MAX_REAL; 8780 stats.max = PETSC_MIN_REAL; 8781 stats.sum = stats.squaresum = 0.; 8782 stats.count = 0; 8783 8784 PetscCallMPI(MPI_Comm_size(comm, &size)); 8785 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8786 PetscCall(DMGetCoordinateDim(dm, &cdim)); 8787 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8788 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 8789 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8790 for (c = cStart; c < cEnd; c++) { 8791 PetscInt i; 8792 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8793 8794 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 8795 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8796 for (i = 0; i < PetscSqr(cdim); ++i) { 8797 frobJ += J[i] * J[i]; 8798 frobInvJ += invJ[i] * invJ[i]; 8799 } 8800 cond2 = frobJ * frobInvJ; 8801 cond = PetscSqrtReal(cond2); 8802 8803 stats.min = PetscMin(stats.min, cond); 8804 stats.max = PetscMax(stats.max, cond); 8805 stats.sum += cond; 8806 stats.squaresum += cond2; 8807 stats.count++; 8808 if (output && cond > limit) { 8809 PetscSection coordSection; 8810 Vec coordsLocal; 8811 PetscScalar *coords = NULL; 8812 PetscInt Nv, d, clSize, cl, *closure = NULL; 8813 8814 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8815 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8816 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8817 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 8818 for (i = 0; i < Nv / cdim; ++i) { 8819 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8820 for (d = 0; d < cdim; ++d) { 8821 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8822 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 8823 } 8824 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8825 } 8826 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8827 for (cl = 0; cl < clSize * 2; cl += 2) { 8828 const PetscInt edge = closure[cl]; 8829 8830 if ((edge >= eStart) && (edge < eEnd)) { 8831 PetscReal len; 8832 8833 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8834 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 8835 } 8836 } 8837 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8838 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8839 } 8840 } 8841 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8842 8843 if (size > 1) { 8844 PetscMPIInt blockLengths[2] = {4, 1}; 8845 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 8846 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 8847 MPI_Op statReduce; 8848 8849 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 8850 PetscCallMPI(MPI_Type_commit(&statType)); 8851 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8852 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 8853 PetscCallMPI(MPI_Op_free(&statReduce)); 8854 PetscCallMPI(MPI_Type_free(&statType)); 8855 } else { 8856 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 8857 } 8858 if (rank == 0) { 8859 count = globalStats.count; 8860 min = globalStats.min; 8861 max = globalStats.max; 8862 mean = globalStats.sum / globalStats.count; 8863 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 8864 } 8865 8866 if (output) PetscCall(PetscPrintf(comm, "Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double)min, (double)max, (double)mean, (double)stdev)); 8867 PetscCall(PetscFree2(J, invJ)); 8868 8869 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 8870 if (dmCoarse) { 8871 PetscBool isplex; 8872 8873 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 8874 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 8875 } 8876 PetscFunctionReturn(0); 8877 } 8878 8879 /*@ 8880 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8881 orthogonal quality below given tolerance. 8882 8883 Collective on dm 8884 8885 Input Parameters: 8886 + dm - The DMPlex object 8887 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8888 - atol - [0, 1] Absolute tolerance for tagging cells. 8889 8890 Output Parameters: 8891 + OrthQual - Vec containing orthogonal quality per cell 8892 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8893 8894 Options Database Keys: 8895 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8896 supported. 8897 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8898 8899 Notes: 8900 Orthogonal quality is given by the following formula: 8901 8902 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8903 8904 Where A_i is the i'th face-normal vector, f_i is the vector from the cell centroid to the i'th face centroid, and c_i 8905 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8906 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8907 calculating the cosine of the angle between these vectors. 8908 8909 Orthogonal quality ranges from 1 (best) to 0 (worst). 8910 8911 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8912 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8913 8914 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8915 8916 Level: intermediate 8917 8918 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8919 @*/ 8920 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) { 8921 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8922 PetscInt *idx; 8923 PetscScalar *oqVals; 8924 const PetscScalar *cellGeomArr, *faceGeomArr; 8925 PetscReal *ci, *fi, *Ai; 8926 MPI_Comm comm; 8927 Vec cellgeom, facegeom; 8928 DM dmFace, dmCell; 8929 IS glob; 8930 ISLocalToGlobalMapping ltog; 8931 PetscViewer vwr; 8932 8933 PetscFunctionBegin; 8934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8935 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 8936 PetscValidPointer(OrthQual, 4); 8937 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 8938 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8939 PetscCall(DMGetDimension(dm, &nc)); 8940 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8941 { 8942 DMPlexInterpolatedFlag interpFlag; 8943 8944 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8945 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8946 PetscMPIInt rank; 8947 8948 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8949 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8950 } 8951 } 8952 if (OrthQualLabel) { 8953 PetscValidPointer(OrthQualLabel, 5); 8954 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8955 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8956 } else { 8957 *OrthQualLabel = NULL; 8958 } 8959 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8960 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8961 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8962 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8963 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8964 PetscCall(VecCreate(comm, OrthQual)); 8965 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8966 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 8967 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8968 PetscCall(VecSetUp(*OrthQual)); 8969 PetscCall(ISDestroy(&glob)); 8970 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8971 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8972 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8973 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8974 PetscCall(VecGetDM(cellgeom, &dmCell)); 8975 PetscCall(VecGetDM(facegeom, &dmFace)); 8976 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8977 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 8978 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8979 PetscInt cellarr[2], *adj = NULL; 8980 PetscScalar *cArr, *fArr; 8981 PetscReal minvalc = 1.0, minvalf = 1.0; 8982 PetscFVCellGeom *cg; 8983 8984 idx[cellIter] = cell - cStart; 8985 cellarr[0] = cell; 8986 /* Make indexing into cellGeom easier */ 8987 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8988 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8989 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8990 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8991 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 8992 PetscInt i; 8993 const PetscInt neigh = adj[cellneigh]; 8994 PetscReal normci = 0, normfi = 0, normai = 0; 8995 PetscFVCellGeom *cgneigh; 8996 PetscFVFaceGeom *fg; 8997 8998 /* Don't count ourselves in the neighbor list */ 8999 if (neigh == cell) continue; 9000 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9001 cellarr[1] = neigh; 9002 { 9003 PetscInt numcovpts; 9004 const PetscInt *covpts; 9005 9006 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9007 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9008 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9009 } 9010 9011 /* Compute c_i, f_i and their norms */ 9012 for (i = 0; i < nc; i++) { 9013 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9014 fi[i] = fg->centroid[i] - cg->centroid[i]; 9015 Ai[i] = fg->normal[i]; 9016 normci += PetscPowReal(ci[i], 2); 9017 normfi += PetscPowReal(fi[i], 2); 9018 normai += PetscPowReal(Ai[i], 2); 9019 } 9020 normci = PetscSqrtReal(normci); 9021 normfi = PetscSqrtReal(normfi); 9022 normai = PetscSqrtReal(normai); 9023 9024 /* Normalize and compute for each face-cell-normal pair */ 9025 for (i = 0; i < nc; i++) { 9026 ci[i] = ci[i] / normci; 9027 fi[i] = fi[i] / normfi; 9028 Ai[i] = Ai[i] / normai; 9029 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9030 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9031 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9032 } 9033 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9034 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9035 } 9036 PetscCall(PetscFree(adj)); 9037 PetscCall(PetscFree2(cArr, fArr)); 9038 /* Defer to cell if they're equal */ 9039 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9040 if (OrthQualLabel) { 9041 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9042 } 9043 } 9044 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9045 PetscCall(VecAssemblyBegin(*OrthQual)); 9046 PetscCall(VecAssemblyEnd(*OrthQual)); 9047 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9048 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9049 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9050 if (OrthQualLabel) { 9051 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9052 } 9053 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9054 PetscCall(PetscViewerDestroy(&vwr)); 9055 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9056 PetscFunctionReturn(0); 9057 } 9058 9059 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9060 * interpolator construction */ 9061 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) { 9062 PetscSection section, newSection, gsection; 9063 PetscSF sf; 9064 PetscBool hasConstraints, ghasConstraints; 9065 9066 PetscFunctionBegin; 9067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9068 PetscValidPointer(odm, 2); 9069 PetscCall(DMGetLocalSection(dm, §ion)); 9070 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9071 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9072 if (!ghasConstraints) { 9073 PetscCall(PetscObjectReference((PetscObject)dm)); 9074 *odm = dm; 9075 PetscFunctionReturn(0); 9076 } 9077 PetscCall(DMClone(dm, odm)); 9078 PetscCall(DMCopyFields(dm, *odm)); 9079 PetscCall(DMGetLocalSection(*odm, &newSection)); 9080 PetscCall(DMGetPointSF(*odm, &sf)); 9081 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9082 PetscCall(DMSetGlobalSection(*odm, gsection)); 9083 PetscCall(PetscSectionDestroy(&gsection)); 9084 PetscFunctionReturn(0); 9085 } 9086 9087 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) { 9088 DM dmco, dmfo; 9089 Mat interpo; 9090 Vec rscale; 9091 Vec cglobalo, clocal; 9092 Vec fglobal, fglobalo, flocal; 9093 PetscBool regular; 9094 9095 PetscFunctionBegin; 9096 PetscCall(DMGetFullDM(dmc, &dmco)); 9097 PetscCall(DMGetFullDM(dmf, &dmfo)); 9098 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9099 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9100 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9101 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9102 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9103 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9104 PetscCall(VecSet(cglobalo, 0.)); 9105 PetscCall(VecSet(clocal, 0.)); 9106 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9107 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9108 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9109 PetscCall(VecSet(fglobal, 0.)); 9110 PetscCall(VecSet(fglobalo, 0.)); 9111 PetscCall(VecSet(flocal, 0.)); 9112 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9113 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9114 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9115 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9116 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9117 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9118 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9119 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9120 *shift = fglobal; 9121 PetscCall(VecDestroy(&flocal)); 9122 PetscCall(VecDestroy(&fglobalo)); 9123 PetscCall(VecDestroy(&clocal)); 9124 PetscCall(VecDestroy(&cglobalo)); 9125 PetscCall(VecDestroy(&rscale)); 9126 PetscCall(MatDestroy(&interpo)); 9127 PetscCall(DMDestroy(&dmfo)); 9128 PetscCall(DMDestroy(&dmco)); 9129 PetscFunctionReturn(0); 9130 } 9131 9132 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) { 9133 PetscObject shifto; 9134 Vec shift; 9135 9136 PetscFunctionBegin; 9137 if (!interp) { 9138 Vec rscale; 9139 9140 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9141 PetscCall(VecDestroy(&rscale)); 9142 } else { 9143 PetscCall(PetscObjectReference((PetscObject)interp)); 9144 } 9145 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9146 if (!shifto) { 9147 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9148 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9149 shifto = (PetscObject)shift; 9150 PetscCall(VecDestroy(&shift)); 9151 } 9152 shift = (Vec)shifto; 9153 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9154 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9155 PetscCall(MatDestroy(&interp)); 9156 PetscFunctionReturn(0); 9157 } 9158 9159 /* Pointwise interpolation 9160 Just code FEM for now 9161 u^f = I u^c 9162 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9163 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9164 I_{ij} = psi^f_i phi^c_j 9165 */ 9166 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) { 9167 PetscSection gsc, gsf; 9168 PetscInt m, n; 9169 void *ctx; 9170 DM cdm; 9171 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9172 9173 PetscFunctionBegin; 9174 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9175 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9176 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9177 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9178 9179 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9180 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9181 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9182 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9183 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9184 9185 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9186 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9187 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9188 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9189 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9190 if (scaling) { 9191 /* Use naive scaling */ 9192 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9193 } 9194 PetscFunctionReturn(0); 9195 } 9196 9197 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) { 9198 VecScatter ctx; 9199 9200 PetscFunctionBegin; 9201 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9202 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9203 PetscCall(VecScatterDestroy(&ctx)); 9204 PetscFunctionReturn(0); 9205 } 9206 9207 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) { 9208 const PetscInt Nc = uOff[1] - uOff[0]; 9209 PetscInt c; 9210 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9211 } 9212 9213 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) { 9214 DM dmc; 9215 PetscDS ds; 9216 Vec ones, locmass; 9217 IS cellIS; 9218 PetscFormKey key; 9219 PetscInt depth; 9220 9221 PetscFunctionBegin; 9222 PetscCall(DMClone(dm, &dmc)); 9223 PetscCall(DMCopyDisc(dm, dmc)); 9224 PetscCall(DMGetDS(dmc, &ds)); 9225 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9226 PetscCall(DMCreateGlobalVector(dmc, mass)); 9227 PetscCall(DMGetLocalVector(dmc, &ones)); 9228 PetscCall(DMGetLocalVector(dmc, &locmass)); 9229 PetscCall(DMPlexGetDepth(dmc, &depth)); 9230 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9231 PetscCall(VecSet(locmass, 0.0)); 9232 PetscCall(VecSet(ones, 1.0)); 9233 key.label = NULL; 9234 key.value = 0; 9235 key.field = 0; 9236 key.part = 0; 9237 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9238 PetscCall(ISDestroy(&cellIS)); 9239 PetscCall(VecSet(*mass, 0.0)); 9240 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9241 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9242 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9243 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9244 PetscCall(DMDestroy(&dmc)); 9245 PetscFunctionReturn(0); 9246 } 9247 9248 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) { 9249 PetscSection gsc, gsf; 9250 PetscInt m, n; 9251 void *ctx; 9252 DM cdm; 9253 PetscBool regular; 9254 9255 PetscFunctionBegin; 9256 if (dmFine == dmCoarse) { 9257 DM dmc; 9258 PetscDS ds; 9259 PetscWeakForm wf; 9260 Vec u; 9261 IS cellIS; 9262 PetscFormKey key; 9263 PetscInt depth; 9264 9265 PetscCall(DMClone(dmFine, &dmc)); 9266 PetscCall(DMCopyDisc(dmFine, dmc)); 9267 PetscCall(DMGetDS(dmc, &ds)); 9268 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9269 PetscCall(PetscWeakFormClear(wf)); 9270 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9271 PetscCall(DMCreateMatrix(dmc, mass)); 9272 PetscCall(DMGetLocalVector(dmc, &u)); 9273 PetscCall(DMPlexGetDepth(dmc, &depth)); 9274 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9275 PetscCall(MatZeroEntries(*mass)); 9276 key.label = NULL; 9277 key.value = 0; 9278 key.field = 0; 9279 key.part = 0; 9280 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9281 PetscCall(ISDestroy(&cellIS)); 9282 PetscCall(DMRestoreLocalVector(dmc, &u)); 9283 PetscCall(DMDestroy(&dmc)); 9284 } else { 9285 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9286 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9287 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9288 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9289 9290 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9291 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9292 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9293 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9294 9295 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9296 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9297 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9298 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9299 } 9300 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9301 PetscFunctionReturn(0); 9302 } 9303 9304 /*@ 9305 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9306 9307 Input Parameter: 9308 . dm - The DMPlex object 9309 9310 Output Parameter: 9311 . regular - The flag 9312 9313 Level: intermediate 9314 9315 .seealso: `DMPlexSetRegularRefinement()` 9316 @*/ 9317 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) { 9318 PetscFunctionBegin; 9319 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9320 PetscValidBoolPointer(regular, 2); 9321 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9322 PetscFunctionReturn(0); 9323 } 9324 9325 /*@ 9326 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9327 9328 Input Parameters: 9329 + dm - The DMPlex object 9330 - regular - The flag 9331 9332 Level: intermediate 9333 9334 .seealso: `DMPlexGetRegularRefinement()` 9335 @*/ 9336 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) { 9337 PetscFunctionBegin; 9338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9339 ((DM_Plex *)dm->data)->regularRefinement = regular; 9340 PetscFunctionReturn(0); 9341 } 9342 9343 /* anchors */ 9344 /*@ 9345 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9346 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9347 9348 not collective 9349 9350 Input Parameter: 9351 . dm - The DMPlex object 9352 9353 Output Parameters: 9354 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9355 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9356 9357 Level: intermediate 9358 9359 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9360 @*/ 9361 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) { 9362 DM_Plex *plex = (DM_Plex *)dm->data; 9363 9364 PetscFunctionBegin; 9365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9366 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9367 if (anchorSection) *anchorSection = plex->anchorSection; 9368 if (anchorIS) *anchorIS = plex->anchorIS; 9369 PetscFunctionReturn(0); 9370 } 9371 9372 /*@ 9373 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9374 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9375 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9376 9377 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9378 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9379 9380 collective on dm 9381 9382 Input Parameters: 9383 + dm - The DMPlex object 9384 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. Must have a local communicator (PETSC_COMM_SELF or derivative). 9385 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9386 9387 The reference counts of anchorSection and anchorIS are incremented. 9388 9389 Level: intermediate 9390 9391 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9392 @*/ 9393 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) { 9394 DM_Plex *plex = (DM_Plex *)dm->data; 9395 PetscMPIInt result; 9396 9397 PetscFunctionBegin; 9398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9399 if (anchorSection) { 9400 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9401 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9402 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9403 } 9404 if (anchorIS) { 9405 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9406 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9407 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9408 } 9409 9410 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9411 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9412 plex->anchorSection = anchorSection; 9413 9414 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9415 PetscCall(ISDestroy(&plex->anchorIS)); 9416 plex->anchorIS = anchorIS; 9417 9418 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9419 PetscInt size, a, pStart, pEnd; 9420 const PetscInt *anchors; 9421 9422 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9423 PetscCall(ISGetLocalSize(anchorIS, &size)); 9424 PetscCall(ISGetIndices(anchorIS, &anchors)); 9425 for (a = 0; a < size; a++) { 9426 PetscInt p; 9427 9428 p = anchors[a]; 9429 if (p >= pStart && p < pEnd) { 9430 PetscInt dof; 9431 9432 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9433 if (dof) { 9434 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9435 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9436 } 9437 } 9438 } 9439 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9440 } 9441 /* reset the generic constraints */ 9442 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9443 PetscFunctionReturn(0); 9444 } 9445 9446 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) { 9447 PetscSection anchorSection; 9448 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9449 9450 PetscFunctionBegin; 9451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9452 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9453 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9454 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9455 if (numFields) { 9456 PetscInt f; 9457 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9458 9459 for (f = 0; f < numFields; f++) { 9460 PetscInt numComp; 9461 9462 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9463 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9464 } 9465 } 9466 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9467 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9468 pStart = PetscMax(pStart, sStart); 9469 pEnd = PetscMin(pEnd, sEnd); 9470 pEnd = PetscMax(pStart, pEnd); 9471 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9472 for (p = pStart; p < pEnd; p++) { 9473 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9474 if (dof) { 9475 PetscCall(PetscSectionGetDof(section, p, &dof)); 9476 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9477 for (f = 0; f < numFields; f++) { 9478 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9479 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9480 } 9481 } 9482 } 9483 PetscCall(PetscSectionSetUp(*cSec)); 9484 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9485 PetscFunctionReturn(0); 9486 } 9487 9488 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) { 9489 PetscSection aSec; 9490 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9491 const PetscInt *anchors; 9492 PetscInt numFields, f; 9493 IS aIS; 9494 MatType mtype; 9495 PetscBool iscuda, iskokkos; 9496 9497 PetscFunctionBegin; 9498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9499 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9500 PetscCall(PetscSectionGetStorageSize(section, &n)); 9501 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9502 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9503 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9504 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9505 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9506 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9507 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9508 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9509 else mtype = MATSEQAIJ; 9510 PetscCall(MatSetType(*cMat, mtype)); 9511 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9512 PetscCall(ISGetIndices(aIS, &anchors)); 9513 /* cSec will be a subset of aSec and section */ 9514 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9515 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9516 PetscCall(PetscMalloc1(m + 1, &i)); 9517 i[0] = 0; 9518 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9519 for (p = pStart; p < pEnd; p++) { 9520 PetscInt rDof, rOff, r; 9521 9522 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9523 if (!rDof) continue; 9524 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9525 if (numFields) { 9526 for (f = 0; f < numFields; f++) { 9527 annz = 0; 9528 for (r = 0; r < rDof; r++) { 9529 a = anchors[rOff + r]; 9530 if (a < sStart || a >= sEnd) continue; 9531 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9532 annz += aDof; 9533 } 9534 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9535 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9536 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9537 } 9538 } else { 9539 annz = 0; 9540 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9541 for (q = 0; q < dof; q++) { 9542 a = anchors[rOff + q]; 9543 if (a < sStart || a >= sEnd) continue; 9544 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9545 annz += aDof; 9546 } 9547 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9548 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9549 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9550 } 9551 } 9552 nnz = i[m]; 9553 PetscCall(PetscMalloc1(nnz, &j)); 9554 offset = 0; 9555 for (p = pStart; p < pEnd; p++) { 9556 if (numFields) { 9557 for (f = 0; f < numFields; f++) { 9558 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9559 for (q = 0; q < dof; q++) { 9560 PetscInt rDof, rOff, r; 9561 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9562 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9563 for (r = 0; r < rDof; r++) { 9564 PetscInt s; 9565 9566 a = anchors[rOff + r]; 9567 if (a < sStart || a >= sEnd) continue; 9568 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9569 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9570 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9571 } 9572 } 9573 } 9574 } else { 9575 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9576 for (q = 0; q < dof; q++) { 9577 PetscInt rDof, rOff, r; 9578 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9579 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9580 for (r = 0; r < rDof; r++) { 9581 PetscInt s; 9582 9583 a = anchors[rOff + r]; 9584 if (a < sStart || a >= sEnd) continue; 9585 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9586 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9587 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9588 } 9589 } 9590 } 9591 } 9592 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9593 PetscCall(PetscFree(i)); 9594 PetscCall(PetscFree(j)); 9595 PetscCall(ISRestoreIndices(aIS, &anchors)); 9596 PetscFunctionReturn(0); 9597 } 9598 9599 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) { 9600 DM_Plex *plex = (DM_Plex *)dm->data; 9601 PetscSection anchorSection, section, cSec; 9602 Mat cMat; 9603 9604 PetscFunctionBegin; 9605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9606 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9607 if (anchorSection) { 9608 PetscInt Nf; 9609 9610 PetscCall(DMGetLocalSection(dm, §ion)); 9611 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9612 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9613 PetscCall(DMGetNumFields(dm, &Nf)); 9614 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9615 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9616 PetscCall(PetscSectionDestroy(&cSec)); 9617 PetscCall(MatDestroy(&cMat)); 9618 } 9619 PetscFunctionReturn(0); 9620 } 9621 9622 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) { 9623 IS subis; 9624 PetscSection section, subsection; 9625 9626 PetscFunctionBegin; 9627 PetscCall(DMGetLocalSection(dm, §ion)); 9628 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9629 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9630 /* Create subdomain */ 9631 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9632 /* Create submodel */ 9633 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9634 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9635 PetscCall(DMSetLocalSection(*subdm, subsection)); 9636 PetscCall(PetscSectionDestroy(&subsection)); 9637 PetscCall(DMCopyDisc(dm, *subdm)); 9638 /* Create map from submodel to global model */ 9639 if (is) { 9640 PetscSection sectionGlobal, subsectionGlobal; 9641 IS spIS; 9642 const PetscInt *spmap; 9643 PetscInt *subIndices; 9644 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9645 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9646 9647 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9648 PetscCall(ISGetIndices(spIS, &spmap)); 9649 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9650 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9651 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9652 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9653 for (p = pStart; p < pEnd; ++p) { 9654 PetscInt gdof, pSubSize = 0; 9655 9656 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9657 if (gdof > 0) { 9658 for (f = 0; f < Nf; ++f) { 9659 PetscInt fdof, fcdof; 9660 9661 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9662 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9663 pSubSize += fdof - fcdof; 9664 } 9665 subSize += pSubSize; 9666 if (pSubSize) { 9667 if (bs < 0) { 9668 bs = pSubSize; 9669 } else if (bs != pSubSize) { 9670 /* Layout does not admit a pointwise block size */ 9671 bs = 1; 9672 } 9673 } 9674 } 9675 } 9676 /* Must have same blocksize on all procs (some might have no points) */ 9677 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9678 bsLocal[1] = bs; 9679 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9680 if (bsMinMax[0] != bsMinMax[1]) { 9681 bs = 1; 9682 } else { 9683 bs = bsMinMax[0]; 9684 } 9685 PetscCall(PetscMalloc1(subSize, &subIndices)); 9686 for (p = pStart; p < pEnd; ++p) { 9687 PetscInt gdof, goff; 9688 9689 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9690 if (gdof > 0) { 9691 const PetscInt point = spmap[p]; 9692 9693 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9694 for (f = 0; f < Nf; ++f) { 9695 PetscInt fdof, fcdof, fc, f2, poff = 0; 9696 9697 /* Can get rid of this loop by storing field information in the global section */ 9698 for (f2 = 0; f2 < f; ++f2) { 9699 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9700 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9701 poff += fdof - fcdof; 9702 } 9703 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9704 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9705 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 9706 } 9707 } 9708 } 9709 PetscCall(ISRestoreIndices(spIS, &spmap)); 9710 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9711 if (bs > 1) { 9712 /* We need to check that the block size does not come from non-contiguous fields */ 9713 PetscInt i, j, set = 1; 9714 for (i = 0; i < subSize; i += bs) { 9715 for (j = 0; j < bs; ++j) { 9716 if (subIndices[i + j] != subIndices[i] + j) { 9717 set = 0; 9718 break; 9719 } 9720 } 9721 } 9722 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9723 } 9724 /* Attach nullspace */ 9725 for (f = 0; f < Nf; ++f) { 9726 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9727 if ((*subdm)->nullspaceConstructors[f]) break; 9728 } 9729 if (f < Nf) { 9730 MatNullSpace nullSpace; 9731 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9732 9733 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9734 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9735 } 9736 } 9737 PetscFunctionReturn(0); 9738 } 9739 9740 /*@ 9741 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9742 9743 Input Parameter: 9744 - dm - The DM 9745 9746 Level: developer 9747 9748 Options Database Keys: 9749 . -dm_plex_monitor_throughput - Activate the monitor 9750 9751 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9752 @*/ 9753 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) { 9754 #if defined(PETSC_USE_LOG) 9755 PetscStageLog stageLog; 9756 PetscLogEvent event; 9757 PetscLogStage stage; 9758 PetscEventPerfInfo eventInfo; 9759 PetscReal cellRate, flopRate; 9760 PetscInt cStart, cEnd, Nf, N; 9761 const char *name; 9762 #endif 9763 9764 PetscFunctionBegin; 9765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9766 #if defined(PETSC_USE_LOG) 9767 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 9768 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9769 PetscCall(DMGetNumFields(dm, &Nf)); 9770 PetscCall(PetscLogGetStageLog(&stageLog)); 9771 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9772 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9773 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9774 N = (cEnd - cStart) * Nf * eventInfo.count; 9775 flopRate = eventInfo.flops / eventInfo.time; 9776 cellRate = N / eventInfo.time; 9777 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " integrals %d reps\n Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double)cellRate, (double)(flopRate / 1.e6))); 9778 #else 9779 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9780 #endif 9781 PetscFunctionReturn(0); 9782 } 9783