1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) { 35 DMPolytopeType ct; 36 PetscInt cStart, cEnd; 37 38 PetscFunctionBegin; 39 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 40 if (cEnd <= cStart) { 41 *simplex = PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 45 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 46 PetscFunctionReturn(0); 47 } 48 49 /*@ 50 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 51 52 Input Parameters: 53 + dm - The DMPlex object 54 - height - The cell height in the Plex, 0 is the default 55 56 Output Parameters: 57 + cStart - The first "normal" cell 58 - cEnd - The upper bound on "normal"" cells 59 60 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 61 62 Level: developer 63 64 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 65 @*/ 66 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) { 67 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 68 PetscInt cS, cE, c; 69 70 PetscFunctionBegin; 71 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 72 for (c = cS; c < cE; ++c) { 73 DMPolytopeType cct; 74 75 PetscCall(DMPlexGetCellType(dm, c, &cct)); 76 if ((PetscInt)cct < 0) break; 77 switch (cct) { 78 case DM_POLYTOPE_POINT: 79 case DM_POLYTOPE_SEGMENT: 80 case DM_POLYTOPE_TRIANGLE: 81 case DM_POLYTOPE_QUADRILATERAL: 82 case DM_POLYTOPE_TETRAHEDRON: 83 case DM_POLYTOPE_HEXAHEDRON: ct = cct; break; 84 default: break; 85 } 86 if (ct != DM_POLYTOPE_UNKNOWN) break; 87 } 88 if (ct != DM_POLYTOPE_UNKNOWN) { 89 DMLabel ctLabel; 90 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 93 // Reset label for fast lookup 94 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 95 } 96 if (cStart) *cStart = cS; 97 if (cEnd) *cEnd = cE; 98 PetscFunctionReturn(0); 99 } 100 101 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) { 102 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 103 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 104 105 PetscFunctionBegin; 106 *ft = PETSC_VTK_INVALID; 107 PetscCall(DMGetCoordinateDim(dm, &cdim)); 108 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 109 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 110 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 111 if (field >= 0) { 112 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 113 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 114 } else { 115 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 116 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 117 } 118 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 119 if (globalvcdof[0]) { 120 *sStart = vStart; 121 *sEnd = vEnd; 122 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 123 else *ft = PETSC_VTK_POINT_FIELD; 124 } else if (globalvcdof[1]) { 125 *sStart = cStart; 126 *sEnd = cEnd; 127 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 128 else *ft = PETSC_VTK_CELL_FIELD; 129 } else { 130 if (field >= 0) { 131 const char *fieldname; 132 133 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 134 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 135 } else { 136 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 137 } 138 } 139 PetscFunctionReturn(0); 140 } 141 142 /*@ 143 DMPlexVecView1D - Plot many 1D solutions on the same line graph 144 145 Collective on dm 146 147 Input Parameters: 148 + dm - The DMPlex 149 . n - The number of vectors 150 . u - The array of local vectors 151 - viewer - The Draw viewer 152 153 Level: advanced 154 155 .seealso: `VecViewFromOptions()`, `VecView()` 156 @*/ 157 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) { 158 PetscDS ds; 159 PetscDraw draw = NULL; 160 PetscDrawLG lg; 161 Vec coordinates; 162 const PetscScalar *coords, **sol; 163 PetscReal *vals; 164 PetscInt *Nc; 165 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 166 char **names; 167 168 PetscFunctionBegin; 169 PetscCall(DMGetDS(dm, &ds)); 170 PetscCall(PetscDSGetNumFields(ds, &Nf)); 171 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 172 PetscCall(PetscDSGetComponents(ds, &Nc)); 173 174 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 175 if (!draw) PetscFunctionReturn(0); 176 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 177 178 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 179 for (i = 0, l = 0; i < n; ++i) { 180 const char *vname; 181 182 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 183 for (f = 0; f < Nf; ++f) { 184 PetscObject disc; 185 const char *fname; 186 char tmpname[PETSC_MAX_PATH_LEN]; 187 188 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 189 /* TODO Create names for components */ 190 for (c = 0; c < Nc[f]; ++c, ++l) { 191 PetscCall(PetscObjectGetName(disc, &fname)); 192 PetscCall(PetscStrcpy(tmpname, vname)); 193 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 195 PetscCall(PetscStrallocpy(tmpname, &names[l])); 196 } 197 } 198 } 199 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 200 /* Just add P_1 support for now */ 201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 202 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 203 PetscCall(VecGetArrayRead(coordinates, &coords)); 204 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 205 for (v = vStart; v < vEnd; ++v) { 206 PetscScalar *x, *svals; 207 208 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 209 for (i = 0; i < n; ++i) { 210 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 211 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 212 } 213 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 214 } 215 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 216 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 217 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 218 PetscCall(PetscFree3(sol, names, vals)); 219 220 PetscCall(PetscDrawLGDraw(lg)); 221 PetscCall(PetscDrawLGDestroy(&lg)); 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) { 235 DM dm; 236 PetscSection s; 237 PetscDraw draw, popup; 238 DM cdm; 239 PetscSection coordSection; 240 Vec coordinates; 241 const PetscScalar *coords, *array; 242 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 243 PetscReal vbound[2], time; 244 PetscBool flg; 245 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 246 const char *name; 247 char title[PETSC_MAX_PATH_LEN]; 248 249 PetscFunctionBegin; 250 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 251 PetscCall(VecGetDM(v, &dm)); 252 PetscCall(DMGetCoordinateDim(dm, &dim)); 253 PetscCall(DMGetLocalSection(dm, &s)); 254 PetscCall(PetscSectionGetNumFields(s, &Nf)); 255 PetscCall(DMGetCoarsenLevel(dm, &level)); 256 PetscCall(DMGetCoordinateDM(dm, &cdm)); 257 PetscCall(DMGetLocalSection(cdm, &coordSection)); 258 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 259 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 260 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 261 262 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 263 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 264 265 PetscCall(VecGetLocalSize(coordinates, &N)); 266 PetscCall(VecGetArrayRead(coordinates, &coords)); 267 for (c = 0; c < N; c += dim) { 268 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 269 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 271 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 272 } 273 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 274 PetscCall(PetscDrawClear(draw)); 275 276 /* Could implement something like DMDASelectFields() */ 277 for (f = 0; f < Nf; ++f) { 278 DM fdm = dm; 279 Vec fv = v; 280 IS fis; 281 char prefix[PETSC_MAX_PATH_LEN]; 282 const char *fname; 283 284 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 285 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 286 287 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 288 else prefix[0] = '\0'; 289 if (Nf > 1) { 290 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 291 PetscCall(VecGetSubVector(v, fis, &fv)); 292 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 293 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 294 } 295 for (comp = 0; comp < Nc; ++comp, ++w) { 296 PetscInt nmax = 2; 297 298 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 299 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 300 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 301 PetscCall(PetscDrawSetTitle(draw, title)); 302 303 /* TODO Get max and min only for this component */ 304 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 305 if (!flg) { 306 PetscCall(VecMin(fv, NULL, &vbound[0])); 307 PetscCall(VecMax(fv, NULL, &vbound[1])); 308 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 309 } 310 PetscCall(PetscDrawGetPopup(draw, &popup)); 311 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 312 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 313 314 PetscCall(VecGetArrayRead(fv, &array)); 315 for (c = cStart; c < cEnd; ++c) { 316 PetscScalar *coords = NULL, *a = NULL; 317 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 318 319 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 320 if (a) { 321 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 322 color[1] = color[2] = color[3] = color[0]; 323 } else { 324 PetscScalar *vals = NULL; 325 PetscInt numVals, va; 326 327 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 328 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 329 switch (numVals / Nc) { 330 case 3: /* P1 Triangle */ 331 case 4: /* P1 Quadrangle */ 332 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 333 break; 334 case 6: /* P2 Triangle */ 335 case 8: /* P2 Quadrangle */ 336 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 337 break; 338 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 339 } 340 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 341 } 342 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 343 switch (numCoords) { 344 case 6: 345 case 12: /* Localized triangle */ 346 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 347 break; 348 case 8: 349 case 16: /* Localized quadrilateral */ 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 351 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 352 break; 353 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 354 } 355 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 356 } 357 PetscCall(VecRestoreArrayRead(fv, &array)); 358 PetscCall(PetscDrawFlush(draw)); 359 PetscCall(PetscDrawPause(draw)); 360 PetscCall(PetscDrawSave(draw)); 361 } 362 if (Nf > 1) { 363 PetscCall(VecRestoreSubVector(v, fis, &fv)); 364 PetscCall(ISDestroy(&fis)); 365 PetscCall(DMDestroy(&fdm)); 366 } 367 } 368 PetscFunctionReturn(0); 369 } 370 371 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); break; 387 default: SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) { 393 DM dm; 394 Vec locv; 395 const char *name; 396 PetscSection section; 397 PetscInt pStart, pEnd; 398 PetscInt numFields; 399 PetscViewerVTKFieldType ft; 400 401 PetscFunctionBegin; 402 PetscCall(VecGetDM(v, &dm)); 403 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 404 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 405 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 406 PetscCall(VecCopy(v, locv)); 407 PetscCall(DMGetLocalSection(dm, §ion)); 408 PetscCall(PetscSectionGetNumFields(section, &numFields)); 409 if (!numFields) { 410 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 411 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 412 } else { 413 PetscInt f; 414 415 for (f = 0; f < numFields; f++) { 416 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 417 if (ft == PETSC_VTK_INVALID) continue; 418 PetscCall(PetscObjectReference((PetscObject)locv)); 419 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 420 } 421 PetscCall(VecDestroy(&locv)); 422 } 423 PetscFunctionReturn(0); 424 } 425 426 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) { 427 DM dm; 428 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 429 430 PetscFunctionBegin; 431 PetscCall(VecGetDM(v, &dm)); 432 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 433 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 434 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 437 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 438 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 439 PetscInt i, numFields; 440 PetscObject fe; 441 PetscBool fem = PETSC_FALSE; 442 Vec locv = v; 443 const char *name; 444 PetscInt step; 445 PetscReal time; 446 447 PetscCall(DMGetNumFields(dm, &numFields)); 448 for (i = 0; i < numFields; i++) { 449 PetscCall(DMGetField(dm, i, NULL, &fe)); 450 if (fe->classid == PETSCFE_CLASSID) { 451 fem = PETSC_TRUE; 452 break; 453 } 454 } 455 if (fem) { 456 PetscObject isZero; 457 458 PetscCall(DMGetLocalVector(dm, &locv)); 459 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 460 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 461 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 462 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 463 PetscCall(VecCopy(v, locv)); 464 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 465 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 466 } 467 if (isvtk) { 468 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 469 } else if (ishdf5) { 470 #if defined(PETSC_HAVE_HDF5) 471 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 472 #else 473 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 474 #endif 475 } else if (isdraw) { 476 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 477 } else if (isglvis) { 478 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 479 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 480 PetscCall(VecView_GLVis(locv, viewer)); 481 } else if (iscgns) { 482 #if defined(PETSC_HAVE_CGNS) 483 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 484 #else 485 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 486 #endif 487 } 488 if (fem) { 489 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 490 PetscCall(DMRestoreLocalVector(dm, &locv)); 491 } 492 } else { 493 PetscBool isseq; 494 495 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 496 if (isseq) PetscCall(VecView_Seq(v, viewer)); 497 else PetscCall(VecView_MPI(v, viewer)); 498 } 499 PetscFunctionReturn(0); 500 } 501 502 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) { 503 DM dm; 504 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 505 506 PetscFunctionBegin; 507 PetscCall(VecGetDM(v, &dm)); 508 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 509 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 510 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 511 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 512 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 513 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 514 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 515 if (isvtk || isdraw || isglvis || iscgns) { 516 Vec locv; 517 PetscObject isZero; 518 const char *name; 519 520 PetscCall(DMGetLocalVector(dm, &locv)); 521 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 522 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 523 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 524 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 525 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 526 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 527 PetscCall(VecView_Plex_Local(locv, viewer)); 528 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 529 PetscCall(DMRestoreLocalVector(dm, &locv)); 530 } else if (ishdf5) { 531 #if defined(PETSC_HAVE_HDF5) 532 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 533 #else 534 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 535 #endif 536 } else if (isexodusii) { 537 #if defined(PETSC_HAVE_EXODUSII) 538 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 539 #else 540 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 541 #endif 542 } else { 543 PetscBool isseq; 544 545 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 546 if (isseq) PetscCall(VecView_Seq(v, viewer)); 547 else PetscCall(VecView_MPI(v, viewer)); 548 } 549 PetscFunctionReturn(0); 550 } 551 552 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) { 553 DM dm; 554 MPI_Comm comm; 555 PetscViewerFormat format; 556 Vec v; 557 PetscBool isvtk, ishdf5; 558 559 PetscFunctionBegin; 560 PetscCall(VecGetDM(originalv, &dm)); 561 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 562 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 563 PetscCall(PetscViewerGetFormat(viewer, &format)); 564 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 565 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 566 if (format == PETSC_VIEWER_NATIVE) { 567 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 568 /* this need a better fix */ 569 if (dm->useNatural) { 570 if (dm->sfNatural) { 571 const char *vecname; 572 PetscInt n, nroots; 573 574 PetscCall(VecGetLocalSize(originalv, &n)); 575 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 576 if (n == nroots) { 577 PetscCall(DMGetGlobalVector(dm, &v)); 578 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 579 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 580 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 581 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 582 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 583 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 584 } else v = originalv; 585 } else v = originalv; 586 587 if (ishdf5) { 588 #if defined(PETSC_HAVE_HDF5) 589 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 590 #else 591 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 592 #endif 593 } else if (isvtk) { 594 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 595 } else { 596 PetscBool isseq; 597 598 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 599 if (isseq) PetscCall(VecView_Seq(v, viewer)); 600 else PetscCall(VecView_MPI(v, viewer)); 601 } 602 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 603 PetscFunctionReturn(0); 604 } 605 606 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) { 607 DM dm; 608 PetscBool ishdf5; 609 610 PetscFunctionBegin; 611 PetscCall(VecGetDM(v, &dm)); 612 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 613 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 614 if (ishdf5) { 615 DM dmBC; 616 Vec gv; 617 const char *name; 618 619 PetscCall(DMGetOutputDM(dm, &dmBC)); 620 PetscCall(DMGetGlobalVector(dmBC, &gv)); 621 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 622 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 623 PetscCall(VecLoad_Default(gv, viewer)); 624 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 625 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 626 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 627 } else PetscCall(VecLoad_Default(v, viewer)); 628 PetscFunctionReturn(0); 629 } 630 631 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) { 632 DM dm; 633 PetscBool ishdf5, isexodusii; 634 635 PetscFunctionBegin; 636 PetscCall(VecGetDM(v, &dm)); 637 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (ishdf5) { 641 #if defined(PETSC_HAVE_HDF5) 642 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 643 #else 644 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 645 #endif 646 } else if (isexodusii) { 647 #if defined(PETSC_HAVE_EXODUSII) 648 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 649 #else 650 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 651 #endif 652 } else PetscCall(VecLoad_Default(v, viewer)); 653 PetscFunctionReturn(0); 654 } 655 656 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else PetscCall(VecLoad_Default(originalv, viewer)); 687 } 688 PetscFunctionReturn(0); 689 } 690 691 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) { 692 PetscSection coordSection; 693 Vec coordinates; 694 DMLabel depthLabel, celltypeLabel; 695 const char *name[4]; 696 const PetscScalar *a; 697 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 698 699 PetscFunctionBegin; 700 PetscCall(DMGetDimension(dm, &dim)); 701 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 702 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 703 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 704 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 705 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 706 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 707 PetscCall(VecGetArrayRead(coordinates, &a)); 708 name[0] = "vertex"; 709 name[1] = "edge"; 710 name[dim - 1] = "face"; 711 name[dim] = "cell"; 712 for (c = cStart; c < cEnd; ++c) { 713 PetscInt *closure = NULL; 714 PetscInt closureSize, cl, ct; 715 716 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 717 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 718 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 719 PetscCall(PetscViewerASCIIPushTab(viewer)); 720 for (cl = 0; cl < closureSize * 2; cl += 2) { 721 PetscInt point = closure[cl], depth, dof, off, d, p; 722 723 if ((point < pStart) || (point >= pEnd)) continue; 724 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 725 if (!dof) continue; 726 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 727 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 728 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 729 for (p = 0; p < dof / dim; ++p) { 730 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 731 for (d = 0; d < dim; ++d) { 732 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 733 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 734 } 735 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 736 } 737 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 738 } 739 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 740 PetscCall(PetscViewerASCIIPopTab(viewer)); 741 } 742 PetscCall(VecRestoreArrayRead(coordinates, &a)); 743 PetscFunctionReturn(0); 744 } 745 746 typedef enum { 747 CS_CARTESIAN, 748 CS_POLAR, 749 CS_CYLINDRICAL, 750 CS_SPHERICAL 751 } CoordSystem; 752 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 753 754 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) { 755 PetscInt i; 756 757 PetscFunctionBegin; 758 if (dim > 3) { 759 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 760 } else { 761 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 762 763 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 764 switch (cs) { 765 case CS_CARTESIAN: 766 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 767 break; 768 case CS_POLAR: 769 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 770 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 771 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 772 break; 773 case CS_CYLINDRICAL: 774 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 775 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 776 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 777 trcoords[2] = coords[2]; 778 break; 779 case CS_SPHERICAL: 780 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 781 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 782 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 783 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 784 break; 785 } 786 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 787 } 788 PetscFunctionReturn(0); 789 } 790 791 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) { 792 DM_Plex *mesh = (DM_Plex *)dm->data; 793 DM cdm, cdmCell; 794 PetscSection coordSection, coordSectionCell; 795 Vec coordinates, coordinatesCell; 796 PetscViewerFormat format; 797 798 PetscFunctionBegin; 799 PetscCall(DMGetCoordinateDM(dm, &cdm)); 800 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 801 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 802 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 803 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 804 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 805 PetscCall(PetscViewerGetFormat(viewer, &format)); 806 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 807 const char *name; 808 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 809 PetscInt pStart, pEnd, p, numLabels, l; 810 PetscMPIInt rank, size; 811 812 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 813 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 814 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 815 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 816 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 817 PetscCall(DMGetDimension(dm, &dim)); 818 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 819 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 820 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 821 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 822 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 823 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 824 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 825 for (p = pStart; p < pEnd; ++p) { 826 PetscInt dof, off, s; 827 828 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 829 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 830 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 831 } 832 PetscCall(PetscViewerFlush(viewer)); 833 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 834 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 835 for (p = pStart; p < pEnd; ++p) { 836 PetscInt dof, off, c; 837 838 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 839 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 840 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 841 } 842 PetscCall(PetscViewerFlush(viewer)); 843 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 844 if (coordSection && coordinates) { 845 CoordSystem cs = CS_CARTESIAN; 846 const PetscScalar *array, *arrayCell = NULL; 847 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 848 PetscMPIInt rank; 849 const char *name; 850 851 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 852 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 853 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 854 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 855 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 856 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 857 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 858 pStart = PetscMin(pvStart, pcStart); 859 pEnd = PetscMax(pvEnd, pcEnd); 860 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 863 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 864 865 PetscCall(VecGetArrayRead(coordinates, &array)); 866 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 867 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 868 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 869 for (p = pStart; p < pEnd; ++p) { 870 PetscInt dof, off; 871 872 if (p >= pvStart && p < pvEnd) { 873 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 874 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 875 if (dof) { 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 877 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 878 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 879 } 880 } 881 if (cdmCell && p >= pcStart && p < pcEnd) { 882 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 883 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 884 if (dof) { 885 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 886 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 887 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 888 } 889 } 890 } 891 PetscCall(PetscViewerFlush(viewer)); 892 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 893 PetscCall(VecRestoreArrayRead(coordinates, &array)); 894 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 895 } 896 PetscCall(DMGetNumLabels(dm, &numLabels)); 897 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 898 for (l = 0; l < numLabels; ++l) { 899 DMLabel label; 900 PetscBool isdepth; 901 const char *name; 902 903 PetscCall(DMGetLabelName(dm, l, &name)); 904 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 905 if (isdepth) continue; 906 PetscCall(DMGetLabel(dm, name, &label)); 907 PetscCall(DMLabelView(label, viewer)); 908 } 909 if (size > 1) { 910 PetscSF sf; 911 912 PetscCall(DMGetPointSF(dm, &sf)); 913 PetscCall(PetscSFView(sf, viewer)); 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 917 const char *name, *color; 918 const char *defcolors[3] = {"gray", "orange", "green"}; 919 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 920 char lname[PETSC_MAX_PATH_LEN]; 921 PetscReal scale = 2.0; 922 PetscReal tikzscale = 1.0; 923 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 924 double tcoords[3]; 925 PetscScalar *coords; 926 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 927 PetscMPIInt rank, size; 928 char **names, **colors, **lcolors; 929 PetscBool flg, lflg; 930 PetscBT wp = NULL; 931 PetscInt pEnd, pStart; 932 933 PetscCall(DMGetDimension(dm, &dim)); 934 PetscCall(DMPlexGetDepth(dm, &depth)); 935 PetscCall(DMGetNumLabels(dm, &numLabels)); 936 numLabels = PetscMax(numLabels, 10); 937 numColors = 10; 938 numLColors = 10; 939 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 940 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 941 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 942 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 943 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 944 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 945 n = 4; 946 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 947 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 948 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 949 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 950 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 951 if (!useLabels) numLabels = 0; 952 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 953 if (!useColors) { 954 numColors = 3; 955 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 956 } 957 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 958 if (!useColors) { 959 numLColors = 4; 960 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 961 } 962 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 963 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 964 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 965 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 966 if (depth < dim) plotEdges = PETSC_FALSE; 967 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 968 969 /* filter points with labelvalue != labeldefaultvalue */ 970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 971 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 972 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 973 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 974 if (lflg) { 975 DMLabel lbl; 976 977 PetscCall(DMGetLabel(dm, lname, &lbl)); 978 if (lbl) { 979 PetscInt val, defval; 980 981 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 982 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 983 for (c = pStart; c < pEnd; c++) { 984 PetscInt *closure = NULL; 985 PetscInt closureSize; 986 987 PetscCall(DMLabelGetValue(lbl, c, &val)); 988 if (val == defval) continue; 989 990 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 992 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 993 } 994 } 995 } 996 997 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 998 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 999 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1001 \\documentclass[tikz]{standalone}\n\n\ 1002 \\usepackage{pgflibraryshapes}\n\ 1003 \\usetikzlibrary{backgrounds}\n\ 1004 \\usetikzlibrary{arrows}\n\ 1005 \\begin{document}\n")); 1006 if (size > 1) { 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1008 for (p = 0; p < size; ++p) { 1009 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1011 } 1012 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1013 } 1014 if (drawHasse) { 1015 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1016 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1018 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1029 } 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1031 1032 /* Plot vertices */ 1033 PetscCall(VecGetArray(coordinates, &coords)); 1034 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1035 for (v = vStart; v < vEnd; ++v) { 1036 PetscInt off, dof, d; 1037 PetscBool isLabeled = PETSC_FALSE; 1038 1039 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1040 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1041 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1042 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1043 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1044 for (d = 0; d < dof; ++d) { 1045 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1046 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1047 } 1048 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1049 if (dim == 3) { 1050 PetscReal tmp = tcoords[1]; 1051 tcoords[1] = tcoords[2]; 1052 tcoords[2] = -tmp; 1053 } 1054 for (d = 0; d < dof; ++d) { 1055 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1056 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1057 } 1058 if (drawHasse) color = colors[0 % numColors]; 1059 else color = colors[rank % numColors]; 1060 for (l = 0; l < numLabels; ++l) { 1061 PetscInt val; 1062 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1063 if (val >= 0) { 1064 color = lcolors[l % numLColors]; 1065 isLabeled = PETSC_TRUE; 1066 break; 1067 } 1068 } 1069 if (drawNumbers[0]) { 1070 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1071 } else if (drawColors[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1073 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1074 } 1075 PetscCall(VecRestoreArray(coordinates, &coords)); 1076 PetscCall(PetscViewerFlush(viewer)); 1077 /* Plot edges */ 1078 if (plotEdges) { 1079 PetscCall(VecGetArray(coordinates, &coords)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1081 for (e = eStart; e < eEnd; ++e) { 1082 const PetscInt *cone; 1083 PetscInt coneSize, offA, offB, dof, d; 1084 1085 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1086 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1087 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1088 PetscCall(DMPlexGetCone(dm, e, &cone)); 1089 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1090 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1091 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1093 for (d = 0; d < dof; ++d) { 1094 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1095 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1096 } 1097 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1098 if (dim == 3) { 1099 PetscReal tmp = tcoords[1]; 1100 tcoords[1] = tcoords[2]; 1101 tcoords[2] = -tmp; 1102 } 1103 for (d = 0; d < dof; ++d) { 1104 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1106 } 1107 if (drawHasse) color = colors[1 % numColors]; 1108 else color = colors[rank % numColors]; 1109 for (l = 0; l < numLabels; ++l) { 1110 PetscInt val; 1111 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1112 if (val >= 0) { 1113 color = lcolors[l % numLColors]; 1114 break; 1115 } 1116 } 1117 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1118 } 1119 PetscCall(VecRestoreArray(coordinates, &coords)); 1120 PetscCall(PetscViewerFlush(viewer)); 1121 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1122 } 1123 /* Plot cells */ 1124 if (dim == 3 || !drawNumbers[1]) { 1125 for (e = eStart; e < eEnd; ++e) { 1126 const PetscInt *cone; 1127 1128 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1129 color = colors[rank % numColors]; 1130 for (l = 0; l < numLabels; ++l) { 1131 PetscInt val; 1132 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1133 if (val >= 0) { 1134 color = lcolors[l % numLColors]; 1135 break; 1136 } 1137 } 1138 PetscCall(DMPlexGetCone(dm, e, &cone)); 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1140 } 1141 } else { 1142 DMPolytopeType ct; 1143 1144 /* Drawing a 2D polygon */ 1145 for (c = cStart; c < cEnd; ++c) { 1146 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1147 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1148 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1149 const PetscInt *cone; 1150 PetscInt coneSize, e; 1151 1152 PetscCall(DMPlexGetCone(dm, c, &cone)); 1153 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1154 for (e = 0; e < coneSize; ++e) { 1155 const PetscInt *econe; 1156 1157 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1158 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1159 } 1160 } else { 1161 PetscInt *closure = NULL; 1162 PetscInt closureSize, Nv = 0, v; 1163 1164 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1165 for (p = 0; p < closureSize * 2; p += 2) { 1166 const PetscInt point = closure[p]; 1167 1168 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1169 } 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1171 for (v = 0; v <= Nv; ++v) { 1172 const PetscInt vertex = closure[v % Nv]; 1173 1174 if (v > 0) { 1175 if (plotEdges) { 1176 const PetscInt *edge; 1177 PetscInt endpoints[2], ne; 1178 1179 endpoints[0] = closure[v - 1]; 1180 endpoints[1] = vertex; 1181 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1182 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1183 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1184 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1185 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1186 } 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1188 } 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1190 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1191 } 1192 } 1193 } 1194 for (c = cStart; c < cEnd; ++c) { 1195 double ccoords[3] = {0.0, 0.0, 0.0}; 1196 PetscBool isLabeled = PETSC_FALSE; 1197 PetscScalar *cellCoords = NULL; 1198 const PetscScalar *array; 1199 PetscInt numCoords, cdim, d; 1200 PetscBool isDG; 1201 1202 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1203 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1204 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1205 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1207 for (p = 0; p < numCoords / cdim; ++p) { 1208 for (d = 0; d < cdim; ++d) { 1209 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1210 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1211 } 1212 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1213 if (cdim == 3) { 1214 PetscReal tmp = tcoords[1]; 1215 tcoords[1] = tcoords[2]; 1216 tcoords[2] = -tmp; 1217 } 1218 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1219 } 1220 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1221 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1222 for (d = 0; d < cdim; ++d) { 1223 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1224 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1225 } 1226 if (drawHasse) color = colors[depth % numColors]; 1227 else color = colors[rank % numColors]; 1228 for (l = 0; l < numLabels; ++l) { 1229 PetscInt val; 1230 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1231 if (val >= 0) { 1232 color = lcolors[l % numLColors]; 1233 isLabeled = PETSC_TRUE; 1234 break; 1235 } 1236 } 1237 if (drawNumbers[dim]) { 1238 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1239 } else if (drawColors[dim]) { 1240 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1241 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1242 } 1243 if (drawHasse) { 1244 color = colors[depth % numColors]; 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1250 1251 color = colors[1 % numColors]; 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1257 1258 color = colors[0 % numColors]; 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1264 1265 for (p = pStart; p < pEnd; ++p) { 1266 const PetscInt *cone; 1267 PetscInt coneSize, cp; 1268 1269 PetscCall(DMPlexGetCone(dm, p, &cone)); 1270 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1271 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1272 } 1273 } 1274 PetscCall(PetscViewerFlush(viewer)); 1275 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1278 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1279 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1280 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1281 PetscCall(PetscFree3(names, colors, lcolors)); 1282 PetscCall(PetscBTDestroy(&wp)); 1283 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1284 Vec cown, acown; 1285 VecScatter sct; 1286 ISLocalToGlobalMapping g2l; 1287 IS gid, acis; 1288 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1289 MPI_Group ggroup, ngroup; 1290 PetscScalar *array, nid; 1291 const PetscInt *idxs; 1292 PetscInt *idxs2, *start, *adjacency, *work; 1293 PetscInt64 lm[3], gm[3]; 1294 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1295 PetscMPIInt d1, d2, rank; 1296 1297 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1298 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1299 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1300 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1301 #endif 1302 if (ncomm != MPI_COMM_NULL) { 1303 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1304 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1305 d1 = 0; 1306 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1307 nid = d2; 1308 PetscCallMPI(MPI_Group_free(&ggroup)); 1309 PetscCallMPI(MPI_Group_free(&ngroup)); 1310 PetscCallMPI(MPI_Comm_free(&ncomm)); 1311 } else nid = 0.0; 1312 1313 /* Get connectivity */ 1314 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1315 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1316 1317 /* filter overlapped local cells */ 1318 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1319 PetscCall(ISGetIndices(gid, &idxs)); 1320 PetscCall(ISGetLocalSize(gid, &cum)); 1321 PetscCall(PetscMalloc1(cum, &idxs2)); 1322 for (c = cStart, cum = 0; c < cEnd; c++) { 1323 if (idxs[c - cStart] < 0) continue; 1324 idxs2[cum++] = idxs[c - cStart]; 1325 } 1326 PetscCall(ISRestoreIndices(gid, &idxs)); 1327 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1328 PetscCall(ISDestroy(&gid)); 1329 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1330 1331 /* support for node-aware cell locality */ 1332 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1333 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1334 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1335 PetscCall(VecGetArray(cown, &array)); 1336 for (c = 0; c < numVertices; c++) array[c] = nid; 1337 PetscCall(VecRestoreArray(cown, &array)); 1338 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1339 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1340 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1341 PetscCall(ISDestroy(&acis)); 1342 PetscCall(VecScatterDestroy(&sct)); 1343 PetscCall(VecDestroy(&cown)); 1344 1345 /* compute edgeCut */ 1346 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1347 PetscCall(PetscMalloc1(cum, &work)); 1348 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1349 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1350 PetscCall(ISDestroy(&gid)); 1351 PetscCall(VecGetArray(acown, &array)); 1352 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1353 PetscInt totl; 1354 1355 totl = start[c + 1] - start[c]; 1356 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1357 for (i = 0; i < totl; i++) { 1358 if (work[i] < 0) { 1359 ect += 1; 1360 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1361 } 1362 } 1363 } 1364 PetscCall(PetscFree(work)); 1365 PetscCall(VecRestoreArray(acown, &array)); 1366 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1367 lm[1] = -numVertices; 1368 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1369 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1370 lm[0] = ect; /* edgeCut */ 1371 lm[1] = ectn; /* node-aware edgeCut */ 1372 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1373 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1374 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1375 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1376 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1377 #else 1378 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1379 #endif 1380 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1381 PetscCall(PetscFree(start)); 1382 PetscCall(PetscFree(adjacency)); 1383 PetscCall(VecDestroy(&acown)); 1384 } else { 1385 const char *name; 1386 PetscInt *sizes, *hybsizes, *ghostsizes; 1387 PetscInt locDepth, depth, cellHeight, dim, d; 1388 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1389 PetscInt numLabels, l, maxSize = 17; 1390 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1391 MPI_Comm comm; 1392 PetscMPIInt size, rank; 1393 1394 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1395 PetscCallMPI(MPI_Comm_size(comm, &size)); 1396 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1397 PetscCall(DMGetDimension(dm, &dim)); 1398 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1399 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1400 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1401 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1402 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1403 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1404 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1405 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1406 gcNum = gcEnd - gcStart; 1407 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1408 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1409 for (d = 0; d <= depth; d++) { 1410 PetscInt Nc[2] = {0, 0}, ict; 1411 1412 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1413 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1414 ict = ct0; 1415 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1416 ct0 = (DMPolytopeType)ict; 1417 for (p = pStart; p < pEnd; ++p) { 1418 DMPolytopeType ct; 1419 1420 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1421 if (ct == ct0) ++Nc[0]; 1422 else ++Nc[1]; 1423 } 1424 if (size < maxSize) { 1425 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1426 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1427 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1429 for (p = 0; p < size; ++p) { 1430 if (rank == 0) { 1431 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1432 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1433 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1434 } 1435 } 1436 } else { 1437 PetscInt locMinMax[2]; 1438 1439 locMinMax[0] = Nc[0] + Nc[1]; 1440 locMinMax[1] = Nc[0] + Nc[1]; 1441 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1442 locMinMax[0] = Nc[1]; 1443 locMinMax[1] = Nc[1]; 1444 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1445 if (d == depth) { 1446 locMinMax[0] = gcNum; 1447 locMinMax[1] = gcNum; 1448 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1449 } 1450 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1451 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1452 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1453 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1454 } 1455 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1456 } 1457 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1458 { 1459 const PetscReal *maxCell; 1460 const PetscReal *L; 1461 PetscBool localized; 1462 1463 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1464 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1465 if (L || localized) { 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1467 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1468 if (L) { 1469 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1470 for (d = 0; d < dim; ++d) { 1471 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1473 } 1474 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1475 } 1476 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1477 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1478 } 1479 } 1480 PetscCall(DMGetNumLabels(dm, &numLabels)); 1481 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1482 for (l = 0; l < numLabels; ++l) { 1483 DMLabel label; 1484 const char *name; 1485 IS valueIS; 1486 const PetscInt *values; 1487 PetscInt numValues, v; 1488 1489 PetscCall(DMGetLabelName(dm, l, &name)); 1490 PetscCall(DMGetLabel(dm, name, &label)); 1491 PetscCall(DMLabelGetNumValues(label, &numValues)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1493 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1494 PetscCall(ISGetIndices(valueIS, &values)); 1495 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1496 for (v = 0; v < numValues; ++v) { 1497 PetscInt size; 1498 1499 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1500 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1502 } 1503 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1504 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1505 PetscCall(ISRestoreIndices(valueIS, &values)); 1506 PetscCall(ISDestroy(&valueIS)); 1507 } 1508 { 1509 char **labelNames; 1510 PetscInt Nl = numLabels; 1511 PetscBool flg; 1512 1513 PetscCall(PetscMalloc1(Nl, &labelNames)); 1514 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1515 for (l = 0; l < Nl; ++l) { 1516 DMLabel label; 1517 1518 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1519 if (flg) { 1520 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1521 PetscCall(DMLabelView(label, viewer)); 1522 } 1523 PetscCall(PetscFree(labelNames[l])); 1524 } 1525 PetscCall(PetscFree(labelNames)); 1526 } 1527 /* If no fields are specified, people do not want to see adjacency */ 1528 if (dm->Nf) { 1529 PetscInt f; 1530 1531 for (f = 0; f < dm->Nf; ++f) { 1532 const char *name; 1533 1534 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1535 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1536 PetscCall(PetscViewerASCIIPushTab(viewer)); 1537 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1538 if (dm->fields[f].adjacency[0]) { 1539 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1541 } else { 1542 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1543 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1544 } 1545 PetscCall(PetscViewerASCIIPopTab(viewer)); 1546 } 1547 } 1548 PetscCall(DMGetCoarseDM(dm, &cdm)); 1549 if (cdm) { 1550 PetscCall(PetscViewerASCIIPushTab(viewer)); 1551 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1552 PetscCall(PetscViewerASCIIPopTab(viewer)); 1553 } 1554 } 1555 PetscFunctionReturn(0); 1556 } 1557 1558 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) { 1559 DMPolytopeType ct; 1560 PetscMPIInt rank; 1561 PetscInt cdim; 1562 1563 PetscFunctionBegin; 1564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1565 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1566 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1567 switch (ct) { 1568 case DM_POLYTOPE_SEGMENT: 1569 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1570 switch (cdim) { 1571 case 1: { 1572 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1573 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1574 1575 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1576 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1577 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1578 } break; 1579 case 2: { 1580 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1581 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1582 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1583 1584 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1585 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1586 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1587 } break; 1588 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1589 } 1590 break; 1591 case DM_POLYTOPE_TRIANGLE: 1592 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1594 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1595 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1596 break; 1597 case DM_POLYTOPE_QUADRILATERAL: 1598 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1599 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1600 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1601 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1602 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1603 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1604 break; 1605 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1606 } 1607 PetscFunctionReturn(0); 1608 } 1609 1610 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) { 1611 DMPolytopeType ct; 1612 PetscReal centroid[2] = {0., 0.}; 1613 PetscMPIInt rank; 1614 PetscInt fillColor, v, e, d; 1615 1616 PetscFunctionBegin; 1617 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1618 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1619 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1620 switch (ct) { 1621 case DM_POLYTOPE_TRIANGLE: { 1622 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1623 1624 for (v = 0; v < 3; ++v) { 1625 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1626 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1627 } 1628 for (e = 0; e < 3; ++e) { 1629 refCoords[0] = refVertices[e * 2 + 0]; 1630 refCoords[1] = refVertices[e * 2 + 1]; 1631 for (d = 1; d <= edgeDiv; ++d) { 1632 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1633 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1634 } 1635 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1636 for (d = 0; d < edgeDiv; ++d) { 1637 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1638 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1639 } 1640 } 1641 } break; 1642 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1643 } 1644 PetscFunctionReturn(0); 1645 } 1646 1647 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) { 1648 PetscDraw draw; 1649 DM cdm; 1650 PetscSection coordSection; 1651 Vec coordinates; 1652 const PetscScalar *coords; 1653 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1654 PetscReal *refCoords, *edgeCoords; 1655 PetscBool isnull, drawAffine = PETSC_TRUE; 1656 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1657 1658 PetscFunctionBegin; 1659 PetscCall(DMGetCoordinateDim(dm, &dim)); 1660 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1661 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1662 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1663 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1664 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1665 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1666 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1667 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1668 1669 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1670 PetscCall(PetscDrawIsNull(draw, &isnull)); 1671 if (isnull) PetscFunctionReturn(0); 1672 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1673 1674 PetscCall(VecGetLocalSize(coordinates, &N)); 1675 PetscCall(VecGetArrayRead(coordinates, &coords)); 1676 for (c = 0; c < N; c += dim) { 1677 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1678 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1679 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1680 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1681 } 1682 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1683 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1684 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1685 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1686 PetscCall(PetscDrawClear(draw)); 1687 1688 for (c = cStart; c < cEnd; ++c) { 1689 PetscScalar *coords = NULL; 1690 PetscInt numCoords; 1691 1692 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1693 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1694 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1695 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1696 } 1697 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1698 PetscCall(PetscDrawFlush(draw)); 1699 PetscCall(PetscDrawPause(draw)); 1700 PetscCall(PetscDrawSave(draw)); 1701 PetscFunctionReturn(0); 1702 } 1703 1704 #if defined(PETSC_HAVE_EXODUSII) 1705 #include <exodusII.h> 1706 #include <petscviewerexodusii.h> 1707 #endif 1708 1709 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) { 1710 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1711 char name[PETSC_MAX_PATH_LEN]; 1712 1713 PetscFunctionBegin; 1714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1715 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1716 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1723 if (iascii) { 1724 PetscViewerFormat format; 1725 PetscCall(PetscViewerGetFormat(viewer, &format)); 1726 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1727 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1728 } else if (ishdf5) { 1729 #if defined(PETSC_HAVE_HDF5) 1730 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1731 #else 1732 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1733 #endif 1734 } else if (isvtk) { 1735 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1736 } else if (isdraw) { 1737 PetscCall(DMPlexView_Draw(dm, viewer)); 1738 } else if (isglvis) { 1739 PetscCall(DMPlexView_GLVis(dm, viewer)); 1740 #if defined(PETSC_HAVE_EXODUSII) 1741 } else if (isexodus) { 1742 /* 1743 exodusII requires that all sets be part of exactly one cell set. 1744 If the dm does not have a "Cell Sets" label defined, we create one 1745 with ID 1, containig all cells. 1746 Note that if the Cell Sets label is defined but does not cover all cells, 1747 we may still have a problem. This should probably be checked here or in the viewer; 1748 */ 1749 PetscInt numCS; 1750 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1751 if (!numCS) { 1752 PetscInt cStart, cEnd, c; 1753 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1754 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1755 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1756 } 1757 PetscCall(DMView_PlexExodusII(dm, viewer)); 1758 #endif 1759 #if defined(PETSC_HAVE_CGNS) 1760 } else if (iscgns) { 1761 PetscCall(DMView_PlexCGNS(dm, viewer)); 1762 #endif 1763 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1764 /* Optionally view the partition */ 1765 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1766 if (flg) { 1767 Vec ranks; 1768 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1769 PetscCall(VecView(ranks, viewer)); 1770 PetscCall(VecDestroy(&ranks)); 1771 } 1772 /* Optionally view a label */ 1773 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1774 if (flg) { 1775 DMLabel label; 1776 Vec val; 1777 1778 PetscCall(DMGetLabel(dm, name, &label)); 1779 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1780 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1781 PetscCall(VecView(val, viewer)); 1782 PetscCall(VecDestroy(&val)); 1783 } 1784 PetscFunctionReturn(0); 1785 } 1786 1787 /*@ 1788 DMPlexTopologyView - Saves a DMPlex topology into a file 1789 1790 Collective on DM 1791 1792 Input Parameters: 1793 + dm - The DM whose topology is to be saved 1794 - viewer - The PetscViewer for saving 1795 1796 Level: advanced 1797 1798 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1799 @*/ 1800 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) { 1801 PetscBool ishdf5; 1802 1803 PetscFunctionBegin; 1804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1805 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1806 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1807 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1808 if (ishdf5) { 1809 #if defined(PETSC_HAVE_HDF5) 1810 PetscViewerFormat format; 1811 PetscCall(PetscViewerGetFormat(viewer, &format)); 1812 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1813 IS globalPointNumbering; 1814 1815 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1816 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1817 PetscCall(ISDestroy(&globalPointNumbering)); 1818 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1819 #else 1820 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1821 #endif 1822 } 1823 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1824 PetscFunctionReturn(0); 1825 } 1826 1827 /*@ 1828 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1829 1830 Collective on DM 1831 1832 Input Parameters: 1833 + dm - The DM whose coordinates are to be saved 1834 - viewer - The PetscViewer for saving 1835 1836 Level: advanced 1837 1838 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1839 @*/ 1840 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) { 1841 PetscBool ishdf5; 1842 1843 PetscFunctionBegin; 1844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1845 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1846 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1847 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1848 if (ishdf5) { 1849 #if defined(PETSC_HAVE_HDF5) 1850 PetscViewerFormat format; 1851 PetscCall(PetscViewerGetFormat(viewer, &format)); 1852 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1853 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1854 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1855 #else 1856 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1857 #endif 1858 } 1859 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1860 PetscFunctionReturn(0); 1861 } 1862 1863 /*@ 1864 DMPlexLabelsView - Saves DMPlex labels into a file 1865 1866 Collective on DM 1867 1868 Input Parameters: 1869 + dm - The DM whose labels are to be saved 1870 - viewer - The PetscViewer for saving 1871 1872 Level: advanced 1873 1874 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1875 @*/ 1876 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) { 1877 PetscBool ishdf5; 1878 1879 PetscFunctionBegin; 1880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1881 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1882 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1883 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1884 if (ishdf5) { 1885 #if defined(PETSC_HAVE_HDF5) 1886 IS globalPointNumbering; 1887 PetscViewerFormat format; 1888 1889 PetscCall(PetscViewerGetFormat(viewer, &format)); 1890 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1891 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1892 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1893 PetscCall(ISDestroy(&globalPointNumbering)); 1894 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1895 #else 1896 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1897 #endif 1898 } 1899 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1900 PetscFunctionReturn(0); 1901 } 1902 1903 /*@ 1904 DMPlexSectionView - Saves a section associated with a DMPlex 1905 1906 Collective on DM 1907 1908 Input Parameters: 1909 + dm - The DM that contains the topology on which the section to be saved is defined 1910 . viewer - The PetscViewer for saving 1911 - sectiondm - The DM that contains the section to be saved 1912 1913 Level: advanced 1914 1915 Notes: 1916 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1917 1918 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1919 1920 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1921 @*/ 1922 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) { 1923 PetscBool ishdf5; 1924 1925 PetscFunctionBegin; 1926 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1927 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1928 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1930 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1931 if (ishdf5) { 1932 #if defined(PETSC_HAVE_HDF5) 1933 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1934 #else 1935 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1936 #endif 1937 } 1938 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1939 PetscFunctionReturn(0); 1940 } 1941 1942 /*@ 1943 DMPlexGlobalVectorView - Saves a global vector 1944 1945 Collective on DM 1946 1947 Input Parameters: 1948 + dm - The DM that represents the topology 1949 . viewer - The PetscViewer to save data with 1950 . sectiondm - The DM that contains the global section on which vec is defined 1951 - vec - The global vector to be saved 1952 1953 Level: advanced 1954 1955 Notes: 1956 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1957 1958 Typical calling sequence 1959 $ DMCreate(PETSC_COMM_WORLD, &dm); 1960 $ DMSetType(dm, DMPLEX); 1961 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1962 $ DMClone(dm, §iondm); 1963 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1964 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1965 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1966 $ PetscSectionSetChart(section, pStart, pEnd); 1967 $ PetscSectionSetUp(section); 1968 $ DMSetLocalSection(sectiondm, section); 1969 $ PetscSectionDestroy(§ion); 1970 $ DMGetGlobalVector(sectiondm, &vec); 1971 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1972 $ DMPlexTopologyView(dm, viewer); 1973 $ DMPlexSectionView(dm, viewer, sectiondm); 1974 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1975 $ DMRestoreGlobalVector(sectiondm, &vec); 1976 $ DMDestroy(§iondm); 1977 $ DMDestroy(&dm); 1978 1979 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1980 @*/ 1981 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 1982 PetscBool ishdf5; 1983 1984 PetscFunctionBegin; 1985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1986 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1987 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1988 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1989 /* Check consistency */ 1990 { 1991 PetscSection section; 1992 PetscBool includesConstraints; 1993 PetscInt m, m1; 1994 1995 PetscCall(VecGetLocalSize(vec, &m1)); 1996 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1997 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1998 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1999 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2000 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2001 } 2002 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2003 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2004 if (ishdf5) { 2005 #if defined(PETSC_HAVE_HDF5) 2006 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2007 #else 2008 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2009 #endif 2010 } 2011 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2012 PetscFunctionReturn(0); 2013 } 2014 2015 /*@ 2016 DMPlexLocalVectorView - Saves a local vector 2017 2018 Collective on DM 2019 2020 Input Parameters: 2021 + dm - The DM that represents the topology 2022 . viewer - The PetscViewer to save data with 2023 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2024 - vec - The local vector to be saved 2025 2026 Level: advanced 2027 2028 Notes: 2029 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2030 2031 Typical calling sequence 2032 $ DMCreate(PETSC_COMM_WORLD, &dm); 2033 $ DMSetType(dm, DMPLEX); 2034 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2035 $ DMClone(dm, §iondm); 2036 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2037 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2038 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2039 $ PetscSectionSetChart(section, pStart, pEnd); 2040 $ PetscSectionSetUp(section); 2041 $ DMSetLocalSection(sectiondm, section); 2042 $ DMGetLocalVector(sectiondm, &vec); 2043 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2044 $ DMPlexTopologyView(dm, viewer); 2045 $ DMPlexSectionView(dm, viewer, sectiondm); 2046 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2047 $ DMRestoreLocalVector(sectiondm, &vec); 2048 $ DMDestroy(§iondm); 2049 $ DMDestroy(&dm); 2050 2051 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2052 @*/ 2053 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 2054 PetscBool ishdf5; 2055 2056 PetscFunctionBegin; 2057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2058 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2059 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2060 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2061 /* Check consistency */ 2062 { 2063 PetscSection section; 2064 PetscBool includesConstraints; 2065 PetscInt m, m1; 2066 2067 PetscCall(VecGetLocalSize(vec, &m1)); 2068 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2069 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2070 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2071 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2072 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2073 } 2074 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2075 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2076 if (ishdf5) { 2077 #if defined(PETSC_HAVE_HDF5) 2078 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2079 #else 2080 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2081 #endif 2082 } 2083 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2084 PetscFunctionReturn(0); 2085 } 2086 2087 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) { 2088 PetscBool ishdf5; 2089 2090 PetscFunctionBegin; 2091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2092 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2093 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2094 if (ishdf5) { 2095 #if defined(PETSC_HAVE_HDF5) 2096 PetscViewerFormat format; 2097 PetscCall(PetscViewerGetFormat(viewer, &format)); 2098 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2099 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2100 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2101 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2102 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2103 PetscFunctionReturn(0); 2104 #else 2105 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2106 #endif 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2108 } 2109 2110 /*@ 2111 DMPlexTopologyLoad - Loads a topology into a DMPlex 2112 2113 Collective on DM 2114 2115 Input Parameters: 2116 + dm - The DM into which the topology is loaded 2117 - viewer - The PetscViewer for the saved topology 2118 2119 Output Parameters: 2120 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2121 2122 Level: advanced 2123 2124 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2125 @*/ 2126 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) { 2127 PetscBool ishdf5; 2128 2129 PetscFunctionBegin; 2130 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2131 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2132 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2133 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2134 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2135 if (ishdf5) { 2136 #if defined(PETSC_HAVE_HDF5) 2137 PetscViewerFormat format; 2138 PetscCall(PetscViewerGetFormat(viewer, &format)); 2139 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2140 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2141 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2142 #else 2143 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2144 #endif 2145 } 2146 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2147 PetscFunctionReturn(0); 2148 } 2149 2150 /*@ 2151 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2152 2153 Collective on DM 2154 2155 Input Parameters: 2156 + dm - The DM into which the coordinates are loaded 2157 . viewer - The PetscViewer for the saved coordinates 2158 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2159 2160 Level: advanced 2161 2162 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2163 @*/ 2164 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2165 PetscBool ishdf5; 2166 2167 PetscFunctionBegin; 2168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2169 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2170 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2171 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2172 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2173 if (ishdf5) { 2174 #if defined(PETSC_HAVE_HDF5) 2175 PetscViewerFormat format; 2176 PetscCall(PetscViewerGetFormat(viewer, &format)); 2177 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2178 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2179 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2180 #else 2181 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2182 #endif 2183 } 2184 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2185 PetscFunctionReturn(0); 2186 } 2187 2188 /*@ 2189 DMPlexLabelsLoad - Loads labels into a DMPlex 2190 2191 Collective on DM 2192 2193 Input Parameters: 2194 + dm - The DM into which the labels are loaded 2195 . viewer - The PetscViewer for the saved labels 2196 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2197 2198 Level: advanced 2199 2200 Notes: 2201 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2202 2203 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2204 @*/ 2205 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2206 PetscBool ishdf5; 2207 2208 PetscFunctionBegin; 2209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2210 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2211 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2212 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2213 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2214 if (ishdf5) { 2215 #if defined(PETSC_HAVE_HDF5) 2216 PetscViewerFormat format; 2217 2218 PetscCall(PetscViewerGetFormat(viewer, &format)); 2219 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2220 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2221 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2222 #else 2223 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2224 #endif 2225 } 2226 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2227 PetscFunctionReturn(0); 2228 } 2229 2230 /*@ 2231 DMPlexSectionLoad - Loads section into a DMPlex 2232 2233 Collective on DM 2234 2235 Input Parameters: 2236 + dm - The DM that represents the topology 2237 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2238 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2239 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2240 2241 Output Parameters 2242 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2243 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2244 2245 Level: advanced 2246 2247 Notes: 2248 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2249 2250 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2251 2252 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2253 2254 Example using 2 processes: 2255 $ NX (number of points on dm): 4 2256 $ sectionA : the on-disk section 2257 $ vecA : a vector associated with sectionA 2258 $ sectionB : sectiondm's local section constructed in this function 2259 $ vecB (local) : a vector associated with sectiondm's local section 2260 $ vecB (global) : a vector associated with sectiondm's global section 2261 $ 2262 $ rank 0 rank 1 2263 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2264 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2265 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2266 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2267 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2268 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2269 $ sectionB->atlasDof : 1 0 1 | 1 3 2270 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2271 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2272 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2273 $ 2274 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2275 2276 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2277 @*/ 2278 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) { 2279 PetscBool ishdf5; 2280 2281 PetscFunctionBegin; 2282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2283 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2284 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2285 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2286 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2287 if (localDofSF) PetscValidPointer(localDofSF, 6); 2288 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2289 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2290 if (ishdf5) { 2291 #if defined(PETSC_HAVE_HDF5) 2292 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2293 #else 2294 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2295 #endif 2296 } 2297 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2298 PetscFunctionReturn(0); 2299 } 2300 2301 /*@ 2302 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2303 2304 Collective on DM 2305 2306 Input Parameters: 2307 + dm - The DM that represents the topology 2308 . viewer - The PetscViewer that represents the on-disk vector data 2309 . sectiondm - The DM that contains the global section on which vec is defined 2310 . sf - The SF that migrates the on-disk vector data into vec 2311 - vec - The global vector to set values of 2312 2313 Level: advanced 2314 2315 Notes: 2316 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2317 2318 Typical calling sequence 2319 $ DMCreate(PETSC_COMM_WORLD, &dm); 2320 $ DMSetType(dm, DMPLEX); 2321 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2322 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2323 $ DMClone(dm, §iondm); 2324 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2325 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2326 $ DMGetGlobalVector(sectiondm, &vec); 2327 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2328 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2329 $ DMRestoreGlobalVector(sectiondm, &vec); 2330 $ PetscSFDestroy(&gsf); 2331 $ PetscSFDestroy(&sfX); 2332 $ DMDestroy(§iondm); 2333 $ DMDestroy(&dm); 2334 2335 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2336 @*/ 2337 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2344 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2345 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2346 /* Check consistency */ 2347 { 2348 PetscSection section; 2349 PetscBool includesConstraints; 2350 PetscInt m, m1; 2351 2352 PetscCall(VecGetLocalSize(vec, &m1)); 2353 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2354 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2355 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2356 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2357 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2358 } 2359 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2360 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2361 if (ishdf5) { 2362 #if defined(PETSC_HAVE_HDF5) 2363 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2364 #else 2365 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2366 #endif 2367 } 2368 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2369 PetscFunctionReturn(0); 2370 } 2371 2372 /*@ 2373 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2374 2375 Collective on DM 2376 2377 Input Parameters: 2378 + dm - The DM that represents the topology 2379 . viewer - The PetscViewer that represents the on-disk vector data 2380 . sectiondm - The DM that contains the local section on which vec is defined 2381 . sf - The SF that migrates the on-disk vector data into vec 2382 - vec - The local vector to set values of 2383 2384 Level: advanced 2385 2386 Notes: 2387 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2388 2389 Typical calling sequence 2390 $ DMCreate(PETSC_COMM_WORLD, &dm); 2391 $ DMSetType(dm, DMPLEX); 2392 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2393 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2394 $ DMClone(dm, §iondm); 2395 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2396 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2397 $ DMGetLocalVector(sectiondm, &vec); 2398 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2399 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2400 $ DMRestoreLocalVector(sectiondm, &vec); 2401 $ PetscSFDestroy(&lsf); 2402 $ PetscSFDestroy(&sfX); 2403 $ DMDestroy(§iondm); 2404 $ DMDestroy(&dm); 2405 2406 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2407 @*/ 2408 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2409 PetscBool ishdf5; 2410 2411 PetscFunctionBegin; 2412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2413 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2414 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2415 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2416 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2417 /* Check consistency */ 2418 { 2419 PetscSection section; 2420 PetscBool includesConstraints; 2421 PetscInt m, m1; 2422 2423 PetscCall(VecGetLocalSize(vec, &m1)); 2424 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2425 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2426 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2427 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2428 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2429 } 2430 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2431 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2432 if (ishdf5) { 2433 #if defined(PETSC_HAVE_HDF5) 2434 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2435 #else 2436 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2437 #endif 2438 } 2439 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2440 PetscFunctionReturn(0); 2441 } 2442 2443 PetscErrorCode DMDestroy_Plex(DM dm) { 2444 DM_Plex *mesh = (DM_Plex *)dm->data; 2445 2446 PetscFunctionBegin; 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2460 if (--mesh->refct > 0) PetscFunctionReturn(0); 2461 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2462 PetscCall(PetscFree(mesh->cones)); 2463 PetscCall(PetscFree(mesh->coneOrientations)); 2464 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2465 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2466 PetscCall(PetscFree(mesh->supports)); 2467 PetscCall(PetscFree(mesh->facesTmp)); 2468 PetscCall(PetscFree(mesh->tetgenOpts)); 2469 PetscCall(PetscFree(mesh->triangleOpts)); 2470 PetscCall(PetscFree(mesh->transformType)); 2471 PetscCall(PetscFree(mesh->distributionName)); 2472 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2473 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2474 PetscCall(ISDestroy(&mesh->subpointIS)); 2475 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2476 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2477 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2478 PetscCall(ISDestroy(&mesh->anchorIS)); 2479 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2480 PetscCall(PetscFree(mesh->parents)); 2481 PetscCall(PetscFree(mesh->childIDs)); 2482 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2483 PetscCall(PetscFree(mesh->children)); 2484 PetscCall(DMDestroy(&mesh->referenceTree)); 2485 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2486 PetscCall(PetscFree(mesh->neighbors)); 2487 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2488 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2489 PetscCall(PetscFree(mesh)); 2490 PetscFunctionReturn(0); 2491 } 2492 2493 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) { 2494 PetscSection sectionGlobal; 2495 PetscInt bs = -1, mbs; 2496 PetscInt localSize, localStart = 0; 2497 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2498 MatType mtype; 2499 ISLocalToGlobalMapping ltog; 2500 2501 PetscFunctionBegin; 2502 PetscCall(MatInitializePackage()); 2503 mtype = dm->mattype; 2504 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2505 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2506 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2507 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2508 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2509 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2510 PetscCall(MatSetType(*J, mtype)); 2511 PetscCall(MatSetFromOptions(*J)); 2512 PetscCall(MatGetBlockSize(*J, &mbs)); 2513 if (mbs > 1) bs = mbs; 2514 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2515 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2516 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2517 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2522 if (!isShell) { 2523 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2524 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2525 PetscInt pStart, pEnd, p, dof, cdof; 2526 2527 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2528 2529 PetscCall(PetscCalloc1(localSize, &pblocks)); 2530 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2531 for (p = pStart; p < pEnd; ++p) { 2532 PetscInt bdof, offset; 2533 2534 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2535 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2536 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2537 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2538 dof = dof < 0 ? -(dof + 1) : dof; 2539 bdof = cdof && (dof - cdof) ? 1 : dof; 2540 if (dof) { 2541 if (bs < 0) { 2542 bs = bdof; 2543 } else if (bs != bdof) { 2544 bs = 1; 2545 } 2546 } 2547 } 2548 /* Must have same blocksize on all procs (some might have no points) */ 2549 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2550 bsLocal[1] = bs; 2551 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2552 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2553 else bs = bsMinMax[0]; 2554 bs = PetscMax(1, bs); 2555 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2556 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2557 PetscCall(MatSetBlockSize(*J, bs)); 2558 PetscCall(MatSetUp(*J)); 2559 } else { 2560 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2561 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2562 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2563 } 2564 { // Consolidate blocks 2565 PetscInt nblocks = 0; 2566 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2567 if (pblocks[i] == 0) continue; 2568 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2569 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2570 } 2571 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2572 } 2573 PetscCall(PetscFree(pblocks)); 2574 } 2575 PetscCall(MatSetDM(*J, dm)); 2576 PetscFunctionReturn(0); 2577 } 2578 2579 /*@ 2580 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2581 2582 Not collective 2583 2584 Input Parameter: 2585 . mesh - The DMPlex 2586 2587 Output Parameters: 2588 . subsection - The subdomain section 2589 2590 Level: developer 2591 2592 .seealso: 2593 @*/ 2594 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) { 2595 DM_Plex *mesh = (DM_Plex *)dm->data; 2596 2597 PetscFunctionBegin; 2598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2599 if (!mesh->subdomainSection) { 2600 PetscSection section; 2601 PetscSF sf; 2602 2603 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2604 PetscCall(DMGetLocalSection(dm, §ion)); 2605 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2606 PetscCall(PetscSFDestroy(&sf)); 2607 } 2608 *subsection = mesh->subdomainSection; 2609 PetscFunctionReturn(0); 2610 } 2611 2612 /*@ 2613 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2614 2615 Not collective 2616 2617 Input Parameter: 2618 . mesh - The DMPlex 2619 2620 Output Parameters: 2621 + pStart - The first mesh point 2622 - pEnd - The upper bound for mesh points 2623 2624 Level: beginner 2625 2626 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2627 @*/ 2628 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) { 2629 DM_Plex *mesh = (DM_Plex *)dm->data; 2630 2631 PetscFunctionBegin; 2632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2633 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2634 PetscFunctionReturn(0); 2635 } 2636 2637 /*@ 2638 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2639 2640 Not collective 2641 2642 Input Parameters: 2643 + mesh - The DMPlex 2644 . pStart - The first mesh point 2645 - pEnd - The upper bound for mesh points 2646 2647 Output Parameters: 2648 2649 Level: beginner 2650 2651 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2652 @*/ 2653 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) { 2654 DM_Plex *mesh = (DM_Plex *)dm->data; 2655 2656 PetscFunctionBegin; 2657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2658 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2659 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2660 PetscFunctionReturn(0); 2661 } 2662 2663 /*@ 2664 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2665 2666 Not collective 2667 2668 Input Parameters: 2669 + mesh - The DMPlex 2670 - p - The point, which must lie in the chart set with DMPlexSetChart() 2671 2672 Output Parameter: 2673 . size - The cone size for point p 2674 2675 Level: beginner 2676 2677 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2678 @*/ 2679 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) { 2680 DM_Plex *mesh = (DM_Plex *)dm->data; 2681 2682 PetscFunctionBegin; 2683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2684 PetscValidIntPointer(size, 3); 2685 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2686 PetscFunctionReturn(0); 2687 } 2688 2689 /*@ 2690 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2691 2692 Not collective 2693 2694 Input Parameters: 2695 + mesh - The DMPlex 2696 . p - The point, which must lie in the chart set with DMPlexSetChart() 2697 - size - The cone size for point p 2698 2699 Output Parameter: 2700 2701 Note: 2702 This should be called after DMPlexSetChart(). 2703 2704 Level: beginner 2705 2706 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2707 @*/ 2708 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) { 2709 DM_Plex *mesh = (DM_Plex *)dm->data; 2710 2711 PetscFunctionBegin; 2712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2713 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2714 PetscFunctionReturn(0); 2715 } 2716 2717 /*@ 2718 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2719 2720 Not collective 2721 2722 Input Parameters: 2723 + mesh - The DMPlex 2724 . p - The point, which must lie in the chart set with DMPlexSetChart() 2725 - size - The additional cone size for point p 2726 2727 Output Parameter: 2728 2729 Note: 2730 This should be called after DMPlexSetChart(). 2731 2732 Level: beginner 2733 2734 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2735 @*/ 2736 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) { 2737 DM_Plex *mesh = (DM_Plex *)dm->data; 2738 PetscFunctionBegin; 2739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2740 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2741 PetscFunctionReturn(0); 2742 } 2743 2744 /*@C 2745 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2746 2747 Not collective 2748 2749 Input Parameters: 2750 + dm - The DMPlex 2751 - p - The point, which must lie in the chart set with DMPlexSetChart() 2752 2753 Output Parameter: 2754 . cone - An array of points which are on the in-edges for point p 2755 2756 Level: beginner 2757 2758 Fortran Notes: 2759 Since it returns an array, this routine is only available in Fortran 90, and you must 2760 include petsc.h90 in your code. 2761 You must also call DMPlexRestoreCone() after you finish using the returned array. 2762 DMPlexRestoreCone() is not needed/available in C. 2763 2764 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2765 @*/ 2766 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) { 2767 DM_Plex *mesh = (DM_Plex *)dm->data; 2768 PetscInt off; 2769 2770 PetscFunctionBegin; 2771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2772 PetscValidPointer(cone, 3); 2773 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2774 *cone = &mesh->cones[off]; 2775 PetscFunctionReturn(0); 2776 } 2777 2778 /*@C 2779 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2780 2781 Not collective 2782 2783 Input Parameters: 2784 + dm - The DMPlex 2785 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2786 2787 Output Parameters: 2788 + pConesSection - PetscSection describing the layout of pCones 2789 - pCones - An array of points which are on the in-edges for the point set p 2790 2791 Level: intermediate 2792 2793 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2794 @*/ 2795 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) { 2796 PetscSection cs, newcs; 2797 PetscInt *cones; 2798 PetscInt *newarr = NULL; 2799 PetscInt n; 2800 2801 PetscFunctionBegin; 2802 PetscCall(DMPlexGetCones(dm, &cones)); 2803 PetscCall(DMPlexGetConeSection(dm, &cs)); 2804 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2805 if (pConesSection) *pConesSection = newcs; 2806 if (pCones) { 2807 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2808 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2809 } 2810 PetscFunctionReturn(0); 2811 } 2812 2813 /*@ 2814 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2815 2816 Not collective 2817 2818 Input Parameters: 2819 + dm - The DMPlex 2820 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2821 2822 Output Parameter: 2823 . expandedPoints - An array of vertices recursively expanded from input points 2824 2825 Level: advanced 2826 2827 Notes: 2828 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2829 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2830 2831 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2832 @*/ 2833 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) { 2834 IS *expandedPointsAll; 2835 PetscInt depth; 2836 2837 PetscFunctionBegin; 2838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2839 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2840 PetscValidPointer(expandedPoints, 3); 2841 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2842 *expandedPoints = expandedPointsAll[0]; 2843 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2844 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2845 PetscFunctionReturn(0); 2846 } 2847 2848 /*@ 2849 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 2850 2851 Not collective 2852 2853 Input Parameters: 2854 + dm - The DMPlex 2855 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2856 2857 Output Parameters: 2858 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2859 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2860 - sections - (optional) An array of sections which describe mappings from points to their cone points 2861 2862 Level: advanced 2863 2864 Notes: 2865 Like DMPlexGetConeTuple() but recursive. 2866 2867 Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 2868 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2869 2870 Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows: 2871 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2872 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2873 2874 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2875 @*/ 2876 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2877 const PetscInt *arr0 = NULL, *cone = NULL; 2878 PetscInt *arr = NULL, *newarr = NULL; 2879 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2880 IS *expandedPoints_; 2881 PetscSection *sections_; 2882 2883 PetscFunctionBegin; 2884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2885 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2886 if (depth) PetscValidIntPointer(depth, 3); 2887 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2888 if (sections) PetscValidPointer(sections, 5); 2889 PetscCall(ISGetLocalSize(points, &n)); 2890 PetscCall(ISGetIndices(points, &arr0)); 2891 PetscCall(DMPlexGetDepth(dm, &depth_)); 2892 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2893 PetscCall(PetscCalloc1(depth_, §ions_)); 2894 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2895 for (d = depth_ - 1; d >= 0; d--) { 2896 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2897 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2898 for (i = 0; i < n; i++) { 2899 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2900 if (arr[i] >= start && arr[i] < end) { 2901 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2902 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2903 } else { 2904 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2905 } 2906 } 2907 PetscCall(PetscSectionSetUp(sections_[d])); 2908 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2909 PetscCall(PetscMalloc1(newn, &newarr)); 2910 for (i = 0; i < n; i++) { 2911 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2912 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2913 if (cn > 1) { 2914 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2915 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2916 } else { 2917 newarr[co] = arr[i]; 2918 } 2919 } 2920 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2921 arr = newarr; 2922 n = newn; 2923 } 2924 PetscCall(ISRestoreIndices(points, &arr0)); 2925 *depth = depth_; 2926 if (expandedPoints) *expandedPoints = expandedPoints_; 2927 else { 2928 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2929 PetscCall(PetscFree(expandedPoints_)); 2930 } 2931 if (sections) *sections = sections_; 2932 else { 2933 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2934 PetscCall(PetscFree(sections_)); 2935 } 2936 PetscFunctionReturn(0); 2937 } 2938 2939 /*@ 2940 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2941 2942 Not collective 2943 2944 Input Parameters: 2945 + dm - The DMPlex 2946 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2947 2948 Output Parameters: 2949 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2950 . expandedPoints - (optional) An array of recursively expanded cones 2951 - sections - (optional) An array of sections which describe mappings from points to their cone points 2952 2953 Level: advanced 2954 2955 Notes: 2956 See DMPlexGetConeRecursive() for details. 2957 2958 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2959 @*/ 2960 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2961 PetscInt d, depth_; 2962 2963 PetscFunctionBegin; 2964 PetscCall(DMPlexGetDepth(dm, &depth_)); 2965 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2966 if (depth) *depth = 0; 2967 if (expandedPoints) { 2968 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2969 PetscCall(PetscFree(*expandedPoints)); 2970 } 2971 if (sections) { 2972 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2973 PetscCall(PetscFree(*sections)); 2974 } 2975 PetscFunctionReturn(0); 2976 } 2977 2978 /*@ 2979 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 2980 2981 Not collective 2982 2983 Input Parameters: 2984 + mesh - The DMPlex 2985 . p - The point, which must lie in the chart set with DMPlexSetChart() 2986 - cone - An array of points which are on the in-edges for point p 2987 2988 Output Parameter: 2989 2990 Note: 2991 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2992 2993 Level: beginner 2994 2995 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2996 @*/ 2997 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) { 2998 DM_Plex *mesh = (DM_Plex *)dm->data; 2999 PetscInt pStart, pEnd; 3000 PetscInt dof, off, c; 3001 3002 PetscFunctionBegin; 3003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3004 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3005 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3006 if (dof) PetscValidIntPointer(cone, 3); 3007 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3008 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3009 for (c = 0; c < dof; ++c) { 3010 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3011 mesh->cones[off + c] = cone[c]; 3012 } 3013 PetscFunctionReturn(0); 3014 } 3015 3016 /*@C 3017 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3018 3019 Not collective 3020 3021 Input Parameters: 3022 + mesh - The DMPlex 3023 - p - The point, which must lie in the chart set with DMPlexSetChart() 3024 3025 Output Parameter: 3026 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3027 integer giving the prescription for cone traversal. 3028 3029 Level: beginner 3030 3031 Notes: 3032 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3033 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3034 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3035 with the identity. 3036 3037 Fortran Notes: 3038 Since it returns an array, this routine is only available in Fortran 90, and you must 3039 include petsc.h90 in your code. 3040 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3041 DMPlexRestoreConeOrientation() is not needed/available in C. 3042 3043 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3044 @*/ 3045 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) { 3046 DM_Plex *mesh = (DM_Plex *)dm->data; 3047 PetscInt off; 3048 3049 PetscFunctionBegin; 3050 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3051 if (PetscDefined(USE_DEBUG)) { 3052 PetscInt dof; 3053 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3054 if (dof) PetscValidPointer(coneOrientation, 3); 3055 } 3056 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3057 3058 *coneOrientation = &mesh->coneOrientations[off]; 3059 PetscFunctionReturn(0); 3060 } 3061 3062 /*@ 3063 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3064 3065 Not collective 3066 3067 Input Parameters: 3068 + mesh - The DMPlex 3069 . p - The point, which must lie in the chart set with DMPlexSetChart() 3070 - coneOrientation - An array of orientations 3071 Output Parameter: 3072 3073 Notes: 3074 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3075 3076 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3077 3078 Level: beginner 3079 3080 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3081 @*/ 3082 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) { 3083 DM_Plex *mesh = (DM_Plex *)dm->data; 3084 PetscInt pStart, pEnd; 3085 PetscInt dof, off, c; 3086 3087 PetscFunctionBegin; 3088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3089 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3090 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3091 if (dof) PetscValidIntPointer(coneOrientation, 3); 3092 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3093 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3094 for (c = 0; c < dof; ++c) { 3095 PetscInt cdof, o = coneOrientation[c]; 3096 3097 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3098 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3099 mesh->coneOrientations[off + c] = o; 3100 } 3101 PetscFunctionReturn(0); 3102 } 3103 3104 /*@ 3105 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3106 3107 Not collective 3108 3109 Input Parameters: 3110 + mesh - The DMPlex 3111 . p - The point, which must lie in the chart set with DMPlexSetChart() 3112 . conePos - The local index in the cone where the point should be put 3113 - conePoint - The mesh point to insert 3114 3115 Level: beginner 3116 3117 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3118 @*/ 3119 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) { 3120 DM_Plex *mesh = (DM_Plex *)dm->data; 3121 PetscInt pStart, pEnd; 3122 PetscInt dof, off; 3123 3124 PetscFunctionBegin; 3125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3126 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3127 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3128 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3129 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3130 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3131 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3132 mesh->cones[off + conePos] = conePoint; 3133 PetscFunctionReturn(0); 3134 } 3135 3136 /*@ 3137 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3138 3139 Not collective 3140 3141 Input Parameters: 3142 + mesh - The DMPlex 3143 . p - The point, which must lie in the chart set with DMPlexSetChart() 3144 . conePos - The local index in the cone where the point should be put 3145 - coneOrientation - The point orientation to insert 3146 3147 Level: beginner 3148 3149 Notes: 3150 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3151 3152 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3153 @*/ 3154 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) { 3155 DM_Plex *mesh = (DM_Plex *)dm->data; 3156 PetscInt pStart, pEnd; 3157 PetscInt dof, off; 3158 3159 PetscFunctionBegin; 3160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3161 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3162 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3163 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3164 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3165 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3166 mesh->coneOrientations[off + conePos] = coneOrientation; 3167 PetscFunctionReturn(0); 3168 } 3169 3170 /*@ 3171 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3172 3173 Not collective 3174 3175 Input Parameters: 3176 + mesh - The DMPlex 3177 - p - The point, which must lie in the chart set with DMPlexSetChart() 3178 3179 Output Parameter: 3180 . size - The support size for point p 3181 3182 Level: beginner 3183 3184 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3185 @*/ 3186 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) { 3187 DM_Plex *mesh = (DM_Plex *)dm->data; 3188 3189 PetscFunctionBegin; 3190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3191 PetscValidIntPointer(size, 3); 3192 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3193 PetscFunctionReturn(0); 3194 } 3195 3196 /*@ 3197 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3198 3199 Not collective 3200 3201 Input Parameters: 3202 + mesh - The DMPlex 3203 . p - The point, which must lie in the chart set with DMPlexSetChart() 3204 - size - The support size for point p 3205 3206 Output Parameter: 3207 3208 Note: 3209 This should be called after DMPlexSetChart(). 3210 3211 Level: beginner 3212 3213 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3214 @*/ 3215 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) { 3216 DM_Plex *mesh = (DM_Plex *)dm->data; 3217 3218 PetscFunctionBegin; 3219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3220 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3221 PetscFunctionReturn(0); 3222 } 3223 3224 /*@C 3225 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3226 3227 Not collective 3228 3229 Input Parameters: 3230 + mesh - The DMPlex 3231 - p - The point, which must lie in the chart set with DMPlexSetChart() 3232 3233 Output Parameter: 3234 . support - An array of points which are on the out-edges for point p 3235 3236 Level: beginner 3237 3238 Fortran Notes: 3239 Since it returns an array, this routine is only available in Fortran 90, and you must 3240 include petsc.h90 in your code. 3241 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3242 DMPlexRestoreSupport() is not needed/available in C. 3243 3244 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3245 @*/ 3246 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) { 3247 DM_Plex *mesh = (DM_Plex *)dm->data; 3248 PetscInt off; 3249 3250 PetscFunctionBegin; 3251 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3252 PetscValidPointer(support, 3); 3253 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3254 *support = &mesh->supports[off]; 3255 PetscFunctionReturn(0); 3256 } 3257 3258 /*@ 3259 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3260 3261 Not collective 3262 3263 Input Parameters: 3264 + mesh - The DMPlex 3265 . p - The point, which must lie in the chart set with DMPlexSetChart() 3266 - support - An array of points which are on the out-edges for point p 3267 3268 Output Parameter: 3269 3270 Note: 3271 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3272 3273 Level: beginner 3274 3275 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3276 @*/ 3277 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) { 3278 DM_Plex *mesh = (DM_Plex *)dm->data; 3279 PetscInt pStart, pEnd; 3280 PetscInt dof, off, c; 3281 3282 PetscFunctionBegin; 3283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3284 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3285 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3286 if (dof) PetscValidIntPointer(support, 3); 3287 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3288 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3289 for (c = 0; c < dof; ++c) { 3290 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3291 mesh->supports[off + c] = support[c]; 3292 } 3293 PetscFunctionReturn(0); 3294 } 3295 3296 /*@ 3297 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3298 3299 Not collective 3300 3301 Input Parameters: 3302 + mesh - The DMPlex 3303 . p - The point, which must lie in the chart set with DMPlexSetChart() 3304 . supportPos - The local index in the cone where the point should be put 3305 - supportPoint - The mesh point to insert 3306 3307 Level: beginner 3308 3309 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3310 @*/ 3311 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) { 3312 DM_Plex *mesh = (DM_Plex *)dm->data; 3313 PetscInt pStart, pEnd; 3314 PetscInt dof, off; 3315 3316 PetscFunctionBegin; 3317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3318 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3319 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3320 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3321 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3322 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3323 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3324 mesh->supports[off + supportPos] = supportPoint; 3325 PetscFunctionReturn(0); 3326 } 3327 3328 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3329 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3330 switch (ct) { 3331 case DM_POLYTOPE_SEGMENT: 3332 if (o == -1) return -2; 3333 break; 3334 case DM_POLYTOPE_TRIANGLE: 3335 if (o == -3) return -1; 3336 if (o == -2) return -3; 3337 if (o == -1) return -2; 3338 break; 3339 case DM_POLYTOPE_QUADRILATERAL: 3340 if (o == -4) return -2; 3341 if (o == -3) return -1; 3342 if (o == -2) return -4; 3343 if (o == -1) return -3; 3344 break; 3345 default: return o; 3346 } 3347 return o; 3348 } 3349 3350 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3351 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3352 switch (ct) { 3353 case DM_POLYTOPE_SEGMENT: 3354 if ((o == -2) || (o == 1)) return -1; 3355 if (o == -1) return 0; 3356 break; 3357 case DM_POLYTOPE_TRIANGLE: 3358 if (o == -3) return -2; 3359 if (o == -2) return -1; 3360 if (o == -1) return -3; 3361 break; 3362 case DM_POLYTOPE_QUADRILATERAL: 3363 if (o == -4) return -2; 3364 if (o == -3) return -1; 3365 if (o == -2) return -4; 3366 if (o == -1) return -3; 3367 break; 3368 default: return o; 3369 } 3370 return o; 3371 } 3372 3373 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3374 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) { 3375 PetscInt pStart, pEnd, p; 3376 3377 PetscFunctionBegin; 3378 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3379 for (p = pStart; p < pEnd; ++p) { 3380 const PetscInt *cone, *ornt; 3381 PetscInt coneSize, c; 3382 3383 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3384 PetscCall(DMPlexGetCone(dm, p, &cone)); 3385 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3386 for (c = 0; c < coneSize; ++c) { 3387 DMPolytopeType ct; 3388 const PetscInt o = ornt[c]; 3389 3390 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3391 switch (ct) { 3392 case DM_POLYTOPE_SEGMENT: 3393 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3394 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3395 break; 3396 case DM_POLYTOPE_TRIANGLE: 3397 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3398 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3399 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3400 break; 3401 case DM_POLYTOPE_QUADRILATERAL: 3402 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3403 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3404 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3405 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3406 break; 3407 default: break; 3408 } 3409 } 3410 } 3411 PetscFunctionReturn(0); 3412 } 3413 3414 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3415 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3416 PetscInt *closure; 3417 const PetscInt *tmp = NULL, *tmpO = NULL; 3418 PetscInt off = 0, tmpSize, t; 3419 3420 PetscFunctionBeginHot; 3421 if (ornt) { 3422 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3423 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3424 } 3425 if (*points) { 3426 closure = *points; 3427 } else { 3428 PetscInt maxConeSize, maxSupportSize; 3429 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3430 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3431 } 3432 if (useCone) { 3433 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3434 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3435 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3436 } else { 3437 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3438 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3439 } 3440 if (ct == DM_POLYTOPE_UNKNOWN) { 3441 closure[off++] = p; 3442 closure[off++] = 0; 3443 for (t = 0; t < tmpSize; ++t) { 3444 closure[off++] = tmp[t]; 3445 closure[off++] = tmpO ? tmpO[t] : 0; 3446 } 3447 } else { 3448 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3449 3450 /* We assume that cells with a valid type have faces with a valid type */ 3451 closure[off++] = p; 3452 closure[off++] = ornt; 3453 for (t = 0; t < tmpSize; ++t) { 3454 DMPolytopeType ft; 3455 3456 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3457 closure[off++] = tmp[arr[t]]; 3458 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3459 } 3460 } 3461 if (numPoints) *numPoints = tmpSize + 1; 3462 if (points) *points = closure; 3463 PetscFunctionReturn(0); 3464 } 3465 3466 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3467 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) { 3468 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3469 const PetscInt *cone, *ornt; 3470 PetscInt *pts, *closure = NULL; 3471 DMPolytopeType ft; 3472 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3473 PetscInt dim, coneSize, c, d, clSize, cl; 3474 3475 PetscFunctionBeginHot; 3476 PetscCall(DMGetDimension(dm, &dim)); 3477 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3478 PetscCall(DMPlexGetCone(dm, point, &cone)); 3479 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3480 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3481 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3482 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3483 maxSize = PetscMax(coneSeries, supportSeries); 3484 if (*points) { 3485 pts = *points; 3486 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3487 c = 0; 3488 pts[c++] = point; 3489 pts[c++] = o; 3490 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3491 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3492 for (cl = 0; cl < clSize * 2; cl += 2) { 3493 pts[c++] = closure[cl]; 3494 pts[c++] = closure[cl + 1]; 3495 } 3496 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3497 for (cl = 0; cl < clSize * 2; cl += 2) { 3498 pts[c++] = closure[cl]; 3499 pts[c++] = closure[cl + 1]; 3500 } 3501 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3502 for (d = 2; d < coneSize; ++d) { 3503 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3504 pts[c++] = cone[arr[d * 2 + 0]]; 3505 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3506 } 3507 if (dim >= 3) { 3508 for (d = 2; d < coneSize; ++d) { 3509 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3510 const PetscInt *fcone, *fornt; 3511 PetscInt fconeSize, fc, i; 3512 3513 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3514 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3515 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3516 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3517 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3518 for (fc = 0; fc < fconeSize; ++fc) { 3519 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3520 const PetscInt co = farr[fc * 2 + 1]; 3521 3522 for (i = 0; i < c; i += 2) 3523 if (pts[i] == cp) break; 3524 if (i == c) { 3525 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3526 pts[c++] = cp; 3527 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3528 } 3529 } 3530 } 3531 } 3532 *numPoints = c / 2; 3533 *points = pts; 3534 PetscFunctionReturn(0); 3535 } 3536 3537 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3538 DMPolytopeType ct; 3539 PetscInt *closure, *fifo; 3540 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3541 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3542 PetscInt depth, maxSize; 3543 3544 PetscFunctionBeginHot; 3545 PetscCall(DMPlexGetDepth(dm, &depth)); 3546 if (depth == 1) { 3547 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3548 PetscFunctionReturn(0); 3549 } 3550 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3551 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3552 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3553 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3554 PetscFunctionReturn(0); 3555 } 3556 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3557 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3558 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3559 maxSize = PetscMax(coneSeries, supportSeries); 3560 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3561 if (*points) { 3562 closure = *points; 3563 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3564 closure[closureSize++] = p; 3565 closure[closureSize++] = ornt; 3566 fifo[fifoSize++] = p; 3567 fifo[fifoSize++] = ornt; 3568 fifo[fifoSize++] = ct; 3569 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3570 while (fifoSize - fifoStart) { 3571 const PetscInt q = fifo[fifoStart++]; 3572 const PetscInt o = fifo[fifoStart++]; 3573 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3574 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3575 const PetscInt *tmp, *tmpO; 3576 PetscInt tmpSize, t; 3577 3578 if (PetscDefined(USE_DEBUG)) { 3579 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3580 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3581 } 3582 if (useCone) { 3583 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3584 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3585 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3586 } else { 3587 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3588 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3589 tmpO = NULL; 3590 } 3591 for (t = 0; t < tmpSize; ++t) { 3592 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3593 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3594 const PetscInt cp = tmp[ip]; 3595 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3596 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3597 PetscInt c; 3598 3599 /* Check for duplicate */ 3600 for (c = 0; c < closureSize; c += 2) { 3601 if (closure[c] == cp) break; 3602 } 3603 if (c == closureSize) { 3604 closure[closureSize++] = cp; 3605 closure[closureSize++] = co; 3606 fifo[fifoSize++] = cp; 3607 fifo[fifoSize++] = co; 3608 fifo[fifoSize++] = ct; 3609 } 3610 } 3611 } 3612 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3613 if (numPoints) *numPoints = closureSize / 2; 3614 if (points) *points = closure; 3615 PetscFunctionReturn(0); 3616 } 3617 3618 /*@C 3619 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3620 3621 Not collective 3622 3623 Input Parameters: 3624 + dm - The DMPlex 3625 . p - The mesh point 3626 - useCone - PETSC_TRUE for the closure, otherwise return the star 3627 3628 Input/Output Parameter: 3629 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3630 if NULL on input, internal storage will be returned, otherwise the provided array is used 3631 3632 Output Parameter: 3633 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3634 3635 Note: 3636 If using internal storage (points is NULL on input), each call overwrites the last output. 3637 3638 Fortran Note: 3639 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3640 3641 Level: beginner 3642 3643 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3644 @*/ 3645 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3646 PetscFunctionBeginHot; 3647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3648 if (numPoints) PetscValidIntPointer(numPoints, 4); 3649 if (points) PetscValidPointer(points, 5); 3650 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3651 PetscFunctionReturn(0); 3652 } 3653 3654 /*@C 3655 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3656 3657 Not collective 3658 3659 Input Parameters: 3660 + dm - The DMPlex 3661 . p - The mesh point 3662 . useCone - PETSC_TRUE for the closure, otherwise return the star 3663 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3664 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3665 3666 Note: 3667 If not using internal storage (points is not NULL on input), this call is unnecessary 3668 3669 Level: beginner 3670 3671 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3672 @*/ 3673 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3674 PetscFunctionBeginHot; 3675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3676 if (numPoints) *numPoints = 0; 3677 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3678 PetscFunctionReturn(0); 3679 } 3680 3681 /*@ 3682 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3683 3684 Not collective 3685 3686 Input Parameter: 3687 . mesh - The DMPlex 3688 3689 Output Parameters: 3690 + maxConeSize - The maximum number of in-edges 3691 - maxSupportSize - The maximum number of out-edges 3692 3693 Level: beginner 3694 3695 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3696 @*/ 3697 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) { 3698 DM_Plex *mesh = (DM_Plex *)dm->data; 3699 3700 PetscFunctionBegin; 3701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3702 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3703 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3704 PetscFunctionReturn(0); 3705 } 3706 3707 PetscErrorCode DMSetUp_Plex(DM dm) { 3708 DM_Plex *mesh = (DM_Plex *)dm->data; 3709 PetscInt size, maxSupportSize; 3710 3711 PetscFunctionBegin; 3712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3713 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3714 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3715 PetscCall(PetscMalloc1(size, &mesh->cones)); 3716 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3717 PetscCall(PetscLogObjectMemory((PetscObject)dm, size * 2 * sizeof(PetscInt))); 3718 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3719 if (maxSupportSize) { 3720 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3721 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3722 PetscCall(PetscMalloc1(size, &mesh->supports)); 3723 PetscCall(PetscLogObjectMemory((PetscObject)dm, size * sizeof(PetscInt))); 3724 } 3725 PetscFunctionReturn(0); 3726 } 3727 3728 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) { 3729 PetscFunctionBegin; 3730 if (subdm) PetscCall(DMClone(dm, subdm)); 3731 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3732 if (subdm) (*subdm)->useNatural = dm->useNatural; 3733 if (dm->useNatural && dm->sfMigration) { 3734 PetscSF sfNatural; 3735 3736 (*subdm)->sfMigration = dm->sfMigration; 3737 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3738 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3739 (*subdm)->sfNatural = sfNatural; 3740 } 3741 PetscFunctionReturn(0); 3742 } 3743 3744 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) { 3745 PetscInt i = 0; 3746 3747 PetscFunctionBegin; 3748 PetscCall(DMClone(dms[0], superdm)); 3749 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3750 (*superdm)->useNatural = PETSC_FALSE; 3751 for (i = 0; i < len; i++) { 3752 if (dms[i]->useNatural && dms[i]->sfMigration) { 3753 PetscSF sfNatural; 3754 3755 (*superdm)->sfMigration = dms[i]->sfMigration; 3756 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3757 (*superdm)->useNatural = PETSC_TRUE; 3758 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3759 (*superdm)->sfNatural = sfNatural; 3760 break; 3761 } 3762 } 3763 PetscFunctionReturn(0); 3764 } 3765 3766 /*@ 3767 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3768 3769 Not collective 3770 3771 Input Parameter: 3772 . mesh - The DMPlex 3773 3774 Output Parameter: 3775 3776 Note: 3777 This should be called after all calls to DMPlexSetCone() 3778 3779 Level: beginner 3780 3781 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3782 @*/ 3783 PetscErrorCode DMPlexSymmetrize(DM dm) { 3784 DM_Plex *mesh = (DM_Plex *)dm->data; 3785 PetscInt *offsets; 3786 PetscInt supportSize; 3787 PetscInt pStart, pEnd, p; 3788 3789 PetscFunctionBegin; 3790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3791 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3792 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3793 /* Calculate support sizes */ 3794 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3795 for (p = pStart; p < pEnd; ++p) { 3796 PetscInt dof, off, c; 3797 3798 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3799 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3800 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3801 } 3802 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3803 /* Calculate supports */ 3804 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3805 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3806 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3807 for (p = pStart; p < pEnd; ++p) { 3808 PetscInt dof, off, c; 3809 3810 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3811 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3812 for (c = off; c < off + dof; ++c) { 3813 const PetscInt q = mesh->cones[c]; 3814 PetscInt offS; 3815 3816 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3817 3818 mesh->supports[offS + offsets[q]] = p; 3819 ++offsets[q]; 3820 } 3821 } 3822 PetscCall(PetscFree(offsets)); 3823 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3824 PetscFunctionReturn(0); 3825 } 3826 3827 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) { 3828 IS stratumIS; 3829 3830 PetscFunctionBegin; 3831 if (pStart >= pEnd) PetscFunctionReturn(0); 3832 if (PetscDefined(USE_DEBUG)) { 3833 PetscInt qStart, qEnd, numLevels, level; 3834 PetscBool overlap = PETSC_FALSE; 3835 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3836 for (level = 0; level < numLevels; level++) { 3837 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3838 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 3839 overlap = PETSC_TRUE; 3840 break; 3841 } 3842 } 3843 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 3844 } 3845 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 3846 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3847 PetscCall(ISDestroy(&stratumIS)); 3848 PetscFunctionReturn(0); 3849 } 3850 3851 /*@ 3852 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3853 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3854 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3855 the DAG. 3856 3857 Collective on dm 3858 3859 Input Parameter: 3860 . mesh - The DMPlex 3861 3862 Output Parameter: 3863 3864 Notes: 3865 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3866 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3867 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3868 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3869 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3870 3871 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3872 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3873 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 3874 to interpolate only that one (e0), so that 3875 $ cone(c0) = {e0, v2} 3876 $ cone(e0) = {v0, v1} 3877 If DMPlexStratify() is run on this mesh, it will give depths 3878 $ depth 0 = {v0, v1, v2} 3879 $ depth 1 = {e0, c0} 3880 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3881 3882 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3883 3884 Level: beginner 3885 3886 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3887 @*/ 3888 PetscErrorCode DMPlexStratify(DM dm) { 3889 DM_Plex *mesh = (DM_Plex *)dm->data; 3890 DMLabel label; 3891 PetscInt pStart, pEnd, p; 3892 PetscInt numRoots = 0, numLeaves = 0; 3893 3894 PetscFunctionBegin; 3895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3896 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 3897 3898 /* Create depth label */ 3899 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3900 PetscCall(DMCreateLabel(dm, "depth")); 3901 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3902 3903 { 3904 /* Initialize roots and count leaves */ 3905 PetscInt sMin = PETSC_MAX_INT; 3906 PetscInt sMax = PETSC_MIN_INT; 3907 PetscInt coneSize, supportSize; 3908 3909 for (p = pStart; p < pEnd; ++p) { 3910 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3911 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3912 if (!coneSize && supportSize) { 3913 sMin = PetscMin(p, sMin); 3914 sMax = PetscMax(p, sMax); 3915 ++numRoots; 3916 } else if (!supportSize && coneSize) { 3917 ++numLeaves; 3918 } else if (!supportSize && !coneSize) { 3919 /* Isolated points */ 3920 sMin = PetscMin(p, sMin); 3921 sMax = PetscMax(p, sMax); 3922 } 3923 } 3924 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 3925 } 3926 3927 if (numRoots + numLeaves == (pEnd - pStart)) { 3928 PetscInt sMin = PETSC_MAX_INT; 3929 PetscInt sMax = PETSC_MIN_INT; 3930 PetscInt coneSize, supportSize; 3931 3932 for (p = pStart; p < pEnd; ++p) { 3933 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3934 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3935 if (!supportSize && coneSize) { 3936 sMin = PetscMin(p, sMin); 3937 sMax = PetscMax(p, sMax); 3938 } 3939 } 3940 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 3941 } else { 3942 PetscInt level = 0; 3943 PetscInt qStart, qEnd, q; 3944 3945 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3946 while (qEnd > qStart) { 3947 PetscInt sMin = PETSC_MAX_INT; 3948 PetscInt sMax = PETSC_MIN_INT; 3949 3950 for (q = qStart; q < qEnd; ++q) { 3951 const PetscInt *support; 3952 PetscInt supportSize, s; 3953 3954 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3955 PetscCall(DMPlexGetSupport(dm, q, &support)); 3956 for (s = 0; s < supportSize; ++s) { 3957 sMin = PetscMin(support[s], sMin); 3958 sMax = PetscMax(support[s], sMax); 3959 } 3960 } 3961 PetscCall(DMLabelGetNumValues(label, &level)); 3962 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 3963 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3964 } 3965 } 3966 { /* just in case there is an empty process */ 3967 PetscInt numValues, maxValues = 0, v; 3968 3969 PetscCall(DMLabelGetNumValues(label, &numValues)); 3970 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 3971 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 3972 } 3973 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 3974 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 3975 PetscFunctionReturn(0); 3976 } 3977 3978 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) { 3979 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3980 PetscInt dim, depth, pheight, coneSize; 3981 3982 PetscFunctionBeginHot; 3983 PetscCall(DMGetDimension(dm, &dim)); 3984 PetscCall(DMPlexGetDepth(dm, &depth)); 3985 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3986 pheight = depth - pdepth; 3987 if (depth <= 1) { 3988 switch (pdepth) { 3989 case 0: ct = DM_POLYTOPE_POINT; break; 3990 case 1: 3991 switch (coneSize) { 3992 case 2: ct = DM_POLYTOPE_SEGMENT; break; 3993 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 3994 case 4: 3995 switch (dim) { 3996 case 2: ct = DM_POLYTOPE_QUADRILATERAL; break; 3997 case 3: ct = DM_POLYTOPE_TETRAHEDRON; break; 3998 default: break; 3999 } 4000 break; 4001 case 5: ct = DM_POLYTOPE_PYRAMID; break; 4002 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4003 case 8: ct = DM_POLYTOPE_HEXAHEDRON; break; 4004 default: break; 4005 } 4006 } 4007 } else { 4008 if (pdepth == 0) { 4009 ct = DM_POLYTOPE_POINT; 4010 } else if (pheight == 0) { 4011 switch (dim) { 4012 case 1: 4013 switch (coneSize) { 4014 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4015 default: break; 4016 } 4017 break; 4018 case 2: 4019 switch (coneSize) { 4020 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4021 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4022 default: break; 4023 } 4024 break; 4025 case 3: 4026 switch (coneSize) { 4027 case 4: ct = DM_POLYTOPE_TETRAHEDRON; break; 4028 case 5: { 4029 const PetscInt *cone; 4030 PetscInt faceConeSize; 4031 4032 PetscCall(DMPlexGetCone(dm, p, &cone)); 4033 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4034 switch (faceConeSize) { 4035 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4036 case 4: ct = DM_POLYTOPE_PYRAMID; break; 4037 } 4038 } break; 4039 case 6: ct = DM_POLYTOPE_HEXAHEDRON; break; 4040 default: break; 4041 } 4042 break; 4043 default: break; 4044 } 4045 } else if (pheight > 0) { 4046 switch (coneSize) { 4047 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4048 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4049 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4050 default: break; 4051 } 4052 } 4053 } 4054 *pt = ct; 4055 PetscFunctionReturn(0); 4056 } 4057 4058 /*@ 4059 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4060 4061 Collective on dm 4062 4063 Input Parameter: 4064 . mesh - The DMPlex 4065 4066 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4067 4068 Level: developer 4069 4070 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4071 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4072 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4073 4074 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4075 @*/ 4076 PetscErrorCode DMPlexComputeCellTypes(DM dm) { 4077 DM_Plex *mesh; 4078 DMLabel ctLabel; 4079 PetscInt pStart, pEnd, p; 4080 4081 PetscFunctionBegin; 4082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4083 mesh = (DM_Plex *)dm->data; 4084 PetscCall(DMCreateLabel(dm, "celltype")); 4085 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4086 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4087 for (p = pStart; p < pEnd; ++p) { 4088 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4089 PetscInt pdepth; 4090 4091 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4092 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4093 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4094 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4095 } 4096 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4097 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4098 PetscFunctionReturn(0); 4099 } 4100 4101 /*@C 4102 DMPlexGetJoin - Get an array for the join of the set of points 4103 4104 Not Collective 4105 4106 Input Parameters: 4107 + dm - The DMPlex object 4108 . numPoints - The number of input points for the join 4109 - points - The input points 4110 4111 Output Parameters: 4112 + numCoveredPoints - The number of points in the join 4113 - coveredPoints - The points in the join 4114 4115 Level: intermediate 4116 4117 Note: Currently, this is restricted to a single level join 4118 4119 Fortran Notes: 4120 Since it returns an array, this routine is only available in Fortran 90, and you must 4121 include petsc.h90 in your code. 4122 4123 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4124 4125 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4126 @*/ 4127 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4128 DM_Plex *mesh = (DM_Plex *)dm->data; 4129 PetscInt *join[2]; 4130 PetscInt joinSize, i = 0; 4131 PetscInt dof, off, p, c, m; 4132 PetscInt maxSupportSize; 4133 4134 PetscFunctionBegin; 4135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4136 PetscValidIntPointer(points, 3); 4137 PetscValidIntPointer(numCoveredPoints, 4); 4138 PetscValidPointer(coveredPoints, 5); 4139 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4140 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4141 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4142 /* Copy in support of first point */ 4143 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4144 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4145 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4146 /* Check each successive support */ 4147 for (p = 1; p < numPoints; ++p) { 4148 PetscInt newJoinSize = 0; 4149 4150 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4151 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4152 for (c = 0; c < dof; ++c) { 4153 const PetscInt point = mesh->supports[off + c]; 4154 4155 for (m = 0; m < joinSize; ++m) { 4156 if (point == join[i][m]) { 4157 join[1 - i][newJoinSize++] = point; 4158 break; 4159 } 4160 } 4161 } 4162 joinSize = newJoinSize; 4163 i = 1 - i; 4164 } 4165 *numCoveredPoints = joinSize; 4166 *coveredPoints = join[i]; 4167 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4168 PetscFunctionReturn(0); 4169 } 4170 4171 /*@C 4172 DMPlexRestoreJoin - Restore an array for the join of the set of points 4173 4174 Not Collective 4175 4176 Input Parameters: 4177 + dm - The DMPlex object 4178 . numPoints - The number of input points for the join 4179 - points - The input points 4180 4181 Output Parameters: 4182 + numCoveredPoints - The number of points in the join 4183 - coveredPoints - The points in the join 4184 4185 Fortran Notes: 4186 Since it returns an array, this routine is only available in Fortran 90, and you must 4187 include petsc.h90 in your code. 4188 4189 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4190 4191 Level: intermediate 4192 4193 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4194 @*/ 4195 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4196 PetscFunctionBegin; 4197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4198 if (points) PetscValidIntPointer(points, 3); 4199 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4200 PetscValidPointer(coveredPoints, 5); 4201 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4202 if (numCoveredPoints) *numCoveredPoints = 0; 4203 PetscFunctionReturn(0); 4204 } 4205 4206 /*@C 4207 DMPlexGetFullJoin - Get an array for the join of the set of points 4208 4209 Not Collective 4210 4211 Input Parameters: 4212 + dm - The DMPlex object 4213 . numPoints - The number of input points for the join 4214 - points - The input points 4215 4216 Output Parameters: 4217 + numCoveredPoints - The number of points in the join 4218 - coveredPoints - The points in the join 4219 4220 Fortran Notes: 4221 Since it returns an array, this routine is only available in Fortran 90, and you must 4222 include petsc.h90 in your code. 4223 4224 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4225 4226 Level: intermediate 4227 4228 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4229 @*/ 4230 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4231 PetscInt *offsets, **closures; 4232 PetscInt *join[2]; 4233 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4234 PetscInt p, d, c, m, ms; 4235 4236 PetscFunctionBegin; 4237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4238 PetscValidIntPointer(points, 3); 4239 PetscValidIntPointer(numCoveredPoints, 4); 4240 PetscValidPointer(coveredPoints, 5); 4241 4242 PetscCall(DMPlexGetDepth(dm, &depth)); 4243 PetscCall(PetscCalloc1(numPoints, &closures)); 4244 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4245 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4246 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4247 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4248 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4249 4250 for (p = 0; p < numPoints; ++p) { 4251 PetscInt closureSize; 4252 4253 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4254 4255 offsets[p * (depth + 2) + 0] = 0; 4256 for (d = 0; d < depth + 1; ++d) { 4257 PetscInt pStart, pEnd, i; 4258 4259 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4260 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4261 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4262 offsets[p * (depth + 2) + d + 1] = i; 4263 break; 4264 } 4265 } 4266 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4267 } 4268 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4269 } 4270 for (d = 0; d < depth + 1; ++d) { 4271 PetscInt dof; 4272 4273 /* Copy in support of first point */ 4274 dof = offsets[d + 1] - offsets[d]; 4275 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4276 /* Check each successive cone */ 4277 for (p = 1; p < numPoints && joinSize; ++p) { 4278 PetscInt newJoinSize = 0; 4279 4280 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4281 for (c = 0; c < dof; ++c) { 4282 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4283 4284 for (m = 0; m < joinSize; ++m) { 4285 if (point == join[i][m]) { 4286 join[1 - i][newJoinSize++] = point; 4287 break; 4288 } 4289 } 4290 } 4291 joinSize = newJoinSize; 4292 i = 1 - i; 4293 } 4294 if (joinSize) break; 4295 } 4296 *numCoveredPoints = joinSize; 4297 *coveredPoints = join[i]; 4298 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4299 PetscCall(PetscFree(closures)); 4300 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4301 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4302 PetscFunctionReturn(0); 4303 } 4304 4305 /*@C 4306 DMPlexGetMeet - Get an array for the meet of the set of points 4307 4308 Not Collective 4309 4310 Input Parameters: 4311 + dm - The DMPlex object 4312 . numPoints - The number of input points for the meet 4313 - points - The input points 4314 4315 Output Parameters: 4316 + numCoveredPoints - The number of points in the meet 4317 - coveredPoints - The points in the meet 4318 4319 Level: intermediate 4320 4321 Note: Currently, this is restricted to a single level meet 4322 4323 Fortran Notes: 4324 Since it returns an array, this routine is only available in Fortran 90, and you must 4325 include petsc.h90 in your code. 4326 4327 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4328 4329 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4330 @*/ 4331 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) { 4332 DM_Plex *mesh = (DM_Plex *)dm->data; 4333 PetscInt *meet[2]; 4334 PetscInt meetSize, i = 0; 4335 PetscInt dof, off, p, c, m; 4336 PetscInt maxConeSize; 4337 4338 PetscFunctionBegin; 4339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4340 PetscValidIntPointer(points, 3); 4341 PetscValidIntPointer(numCoveringPoints, 4); 4342 PetscValidPointer(coveringPoints, 5); 4343 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4344 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4345 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4346 /* Copy in cone of first point */ 4347 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4348 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4349 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4350 /* Check each successive cone */ 4351 for (p = 1; p < numPoints; ++p) { 4352 PetscInt newMeetSize = 0; 4353 4354 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4355 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4356 for (c = 0; c < dof; ++c) { 4357 const PetscInt point = mesh->cones[off + c]; 4358 4359 for (m = 0; m < meetSize; ++m) { 4360 if (point == meet[i][m]) { 4361 meet[1 - i][newMeetSize++] = point; 4362 break; 4363 } 4364 } 4365 } 4366 meetSize = newMeetSize; 4367 i = 1 - i; 4368 } 4369 *numCoveringPoints = meetSize; 4370 *coveringPoints = meet[i]; 4371 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4372 PetscFunctionReturn(0); 4373 } 4374 4375 /*@C 4376 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4377 4378 Not Collective 4379 4380 Input Parameters: 4381 + dm - The DMPlex object 4382 . numPoints - The number of input points for the meet 4383 - points - The input points 4384 4385 Output Parameters: 4386 + numCoveredPoints - The number of points in the meet 4387 - coveredPoints - The points in the meet 4388 4389 Level: intermediate 4390 4391 Fortran Notes: 4392 Since it returns an array, this routine is only available in Fortran 90, and you must 4393 include petsc.h90 in your code. 4394 4395 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4396 4397 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4398 @*/ 4399 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4400 PetscFunctionBegin; 4401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4402 if (points) PetscValidIntPointer(points, 3); 4403 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4404 PetscValidPointer(coveredPoints, 5); 4405 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4406 if (numCoveredPoints) *numCoveredPoints = 0; 4407 PetscFunctionReturn(0); 4408 } 4409 4410 /*@C 4411 DMPlexGetFullMeet - Get an array for the meet of the set of points 4412 4413 Not Collective 4414 4415 Input Parameters: 4416 + dm - The DMPlex object 4417 . numPoints - The number of input points for the meet 4418 - points - The input points 4419 4420 Output Parameters: 4421 + numCoveredPoints - The number of points in the meet 4422 - coveredPoints - The points in the meet 4423 4424 Level: intermediate 4425 4426 Fortran Notes: 4427 Since it returns an array, this routine is only available in Fortran 90, and you must 4428 include petsc.h90 in your code. 4429 4430 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4431 4432 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4433 @*/ 4434 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4435 PetscInt *offsets, **closures; 4436 PetscInt *meet[2]; 4437 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4438 PetscInt p, h, c, m, mc; 4439 4440 PetscFunctionBegin; 4441 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4442 PetscValidIntPointer(points, 3); 4443 PetscValidIntPointer(numCoveredPoints, 4); 4444 PetscValidPointer(coveredPoints, 5); 4445 4446 PetscCall(DMPlexGetDepth(dm, &height)); 4447 PetscCall(PetscMalloc1(numPoints, &closures)); 4448 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4449 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4450 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4451 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4452 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4453 4454 for (p = 0; p < numPoints; ++p) { 4455 PetscInt closureSize; 4456 4457 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4458 4459 offsets[p * (height + 2) + 0] = 0; 4460 for (h = 0; h < height + 1; ++h) { 4461 PetscInt pStart, pEnd, i; 4462 4463 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4464 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4465 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4466 offsets[p * (height + 2) + h + 1] = i; 4467 break; 4468 } 4469 } 4470 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4471 } 4472 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 4473 } 4474 for (h = 0; h < height + 1; ++h) { 4475 PetscInt dof; 4476 4477 /* Copy in cone of first point */ 4478 dof = offsets[h + 1] - offsets[h]; 4479 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4480 /* Check each successive cone */ 4481 for (p = 1; p < numPoints && meetSize; ++p) { 4482 PetscInt newMeetSize = 0; 4483 4484 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4485 for (c = 0; c < dof; ++c) { 4486 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4487 4488 for (m = 0; m < meetSize; ++m) { 4489 if (point == meet[i][m]) { 4490 meet[1 - i][newMeetSize++] = point; 4491 break; 4492 } 4493 } 4494 } 4495 meetSize = newMeetSize; 4496 i = 1 - i; 4497 } 4498 if (meetSize) break; 4499 } 4500 *numCoveredPoints = meetSize; 4501 *coveredPoints = meet[i]; 4502 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4503 PetscCall(PetscFree(closures)); 4504 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4505 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4506 PetscFunctionReturn(0); 4507 } 4508 4509 /*@C 4510 DMPlexEqual - Determine if two DMs have the same topology 4511 4512 Not Collective 4513 4514 Input Parameters: 4515 + dmA - A DMPlex object 4516 - dmB - A DMPlex object 4517 4518 Output Parameters: 4519 . equal - PETSC_TRUE if the topologies are identical 4520 4521 Level: intermediate 4522 4523 Notes: 4524 We are not solving graph isomorphism, so we do not permutation. 4525 4526 .seealso: `DMPlexGetCone()` 4527 @*/ 4528 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) { 4529 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4530 4531 PetscFunctionBegin; 4532 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4533 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4534 PetscValidBoolPointer(equal, 3); 4535 4536 *equal = PETSC_FALSE; 4537 PetscCall(DMPlexGetDepth(dmA, &depth)); 4538 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4539 if (depth != depthB) PetscFunctionReturn(0); 4540 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4541 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4542 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4543 for (p = pStart; p < pEnd; ++p) { 4544 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4545 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4546 4547 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4548 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4549 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4550 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4551 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4552 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4553 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4554 for (c = 0; c < coneSize; ++c) { 4555 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4556 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4557 } 4558 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4559 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4560 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4561 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4562 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4563 for (s = 0; s < supportSize; ++s) { 4564 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4565 } 4566 } 4567 *equal = PETSC_TRUE; 4568 PetscFunctionReturn(0); 4569 } 4570 4571 /*@C 4572 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4573 4574 Not Collective 4575 4576 Input Parameters: 4577 + dm - The DMPlex 4578 . cellDim - The cell dimension 4579 - numCorners - The number of vertices on a cell 4580 4581 Output Parameters: 4582 . numFaceVertices - The number of vertices on a face 4583 4584 Level: developer 4585 4586 Notes: 4587 Of course this can only work for a restricted set of symmetric shapes 4588 4589 .seealso: `DMPlexGetCone()` 4590 @*/ 4591 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) { 4592 MPI_Comm comm; 4593 4594 PetscFunctionBegin; 4595 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4596 PetscValidIntPointer(numFaceVertices, 4); 4597 switch (cellDim) { 4598 case 0: *numFaceVertices = 0; break; 4599 case 1: *numFaceVertices = 1; break; 4600 case 2: 4601 switch (numCorners) { 4602 case 3: /* triangle */ 4603 *numFaceVertices = 2; /* Edge has 2 vertices */ 4604 break; 4605 case 4: /* quadrilateral */ 4606 *numFaceVertices = 2; /* Edge has 2 vertices */ 4607 break; 4608 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4609 *numFaceVertices = 3; /* Edge has 3 vertices */ 4610 break; 4611 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4612 *numFaceVertices = 3; /* Edge has 3 vertices */ 4613 break; 4614 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4615 } 4616 break; 4617 case 3: 4618 switch (numCorners) { 4619 case 4: /* tetradehdron */ 4620 *numFaceVertices = 3; /* Face has 3 vertices */ 4621 break; 4622 case 6: /* tet cohesive cells */ 4623 *numFaceVertices = 4; /* Face has 4 vertices */ 4624 break; 4625 case 8: /* hexahedron */ 4626 *numFaceVertices = 4; /* Face has 4 vertices */ 4627 break; 4628 case 9: /* tet cohesive Lagrange cells */ 4629 *numFaceVertices = 6; /* Face has 6 vertices */ 4630 break; 4631 case 10: /* quadratic tetrahedron */ 4632 *numFaceVertices = 6; /* Face has 6 vertices */ 4633 break; 4634 case 12: /* hex cohesive Lagrange cells */ 4635 *numFaceVertices = 6; /* Face has 6 vertices */ 4636 break; 4637 case 18: /* quadratic tet cohesive Lagrange cells */ 4638 *numFaceVertices = 6; /* Face has 6 vertices */ 4639 break; 4640 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4641 *numFaceVertices = 9; /* Face has 9 vertices */ 4642 break; 4643 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4644 } 4645 break; 4646 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4647 } 4648 PetscFunctionReturn(0); 4649 } 4650 4651 /*@ 4652 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4653 4654 Not Collective 4655 4656 Input Parameter: 4657 . dm - The DMPlex object 4658 4659 Output Parameter: 4660 . depthLabel - The DMLabel recording point depth 4661 4662 Level: developer 4663 4664 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4665 @*/ 4666 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) { 4667 PetscFunctionBegin; 4668 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4669 PetscValidPointer(depthLabel, 2); 4670 *depthLabel = dm->depthLabel; 4671 PetscFunctionReturn(0); 4672 } 4673 4674 /*@ 4675 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4676 4677 Not Collective 4678 4679 Input Parameter: 4680 . dm - The DMPlex object 4681 4682 Output Parameter: 4683 . depth - The number of strata (breadth first levels) in the DAG 4684 4685 Level: developer 4686 4687 Notes: 4688 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4689 The point depth is described more in detail in DMPlexGetDepthStratum(). 4690 An empty mesh gives -1. 4691 4692 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4693 @*/ 4694 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) { 4695 DMLabel label; 4696 PetscInt d = 0; 4697 4698 PetscFunctionBegin; 4699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4700 PetscValidIntPointer(depth, 2); 4701 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4702 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4703 *depth = d - 1; 4704 PetscFunctionReturn(0); 4705 } 4706 4707 /*@ 4708 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4709 4710 Not Collective 4711 4712 Input Parameters: 4713 + dm - The DMPlex object 4714 - depth - The requested depth 4715 4716 Output Parameters: 4717 + start - The first point at this depth 4718 - end - One beyond the last point at this depth 4719 4720 Notes: 4721 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4722 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4723 higher dimension, e.g., "edges". 4724 4725 Level: developer 4726 4727 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4728 @*/ 4729 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) { 4730 DMLabel label; 4731 PetscInt pStart, pEnd; 4732 4733 PetscFunctionBegin; 4734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4735 if (start) { 4736 PetscValidIntPointer(start, 3); 4737 *start = 0; 4738 } 4739 if (end) { 4740 PetscValidIntPointer(end, 4); 4741 *end = 0; 4742 } 4743 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4744 if (pStart == pEnd) PetscFunctionReturn(0); 4745 if (depth < 0) { 4746 if (start) *start = pStart; 4747 if (end) *end = pEnd; 4748 PetscFunctionReturn(0); 4749 } 4750 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4751 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4752 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4753 PetscFunctionReturn(0); 4754 } 4755 4756 /*@ 4757 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4758 4759 Not Collective 4760 4761 Input Parameters: 4762 + dm - The DMPlex object 4763 - height - The requested height 4764 4765 Output Parameters: 4766 + start - The first point at this height 4767 - end - One beyond the last point at this height 4768 4769 Notes: 4770 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4771 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4772 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4773 4774 Level: developer 4775 4776 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4777 @*/ 4778 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) { 4779 DMLabel label; 4780 PetscInt depth, pStart, pEnd; 4781 4782 PetscFunctionBegin; 4783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4784 if (start) { 4785 PetscValidIntPointer(start, 3); 4786 *start = 0; 4787 } 4788 if (end) { 4789 PetscValidIntPointer(end, 4); 4790 *end = 0; 4791 } 4792 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4793 if (pStart == pEnd) PetscFunctionReturn(0); 4794 if (height < 0) { 4795 if (start) *start = pStart; 4796 if (end) *end = pEnd; 4797 PetscFunctionReturn(0); 4798 } 4799 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4800 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4801 PetscCall(DMLabelGetNumValues(label, &depth)); 4802 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 4803 PetscFunctionReturn(0); 4804 } 4805 4806 /*@ 4807 DMPlexGetPointDepth - Get the depth of a given point 4808 4809 Not Collective 4810 4811 Input Parameters: 4812 + dm - The DMPlex object 4813 - point - The point 4814 4815 Output Parameter: 4816 . depth - The depth of the point 4817 4818 Level: intermediate 4819 4820 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4821 @*/ 4822 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) { 4823 PetscFunctionBegin; 4824 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4825 PetscValidIntPointer(depth, 3); 4826 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4827 PetscFunctionReturn(0); 4828 } 4829 4830 /*@ 4831 DMPlexGetPointHeight - Get the height of a given point 4832 4833 Not Collective 4834 4835 Input Parameters: 4836 + dm - The DMPlex object 4837 - point - The point 4838 4839 Output Parameter: 4840 . height - The height of the point 4841 4842 Level: intermediate 4843 4844 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4845 @*/ 4846 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) { 4847 PetscInt n, pDepth; 4848 4849 PetscFunctionBegin; 4850 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4851 PetscValidIntPointer(height, 3); 4852 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4853 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4854 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4855 PetscFunctionReturn(0); 4856 } 4857 4858 /*@ 4859 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4860 4861 Not Collective 4862 4863 Input Parameter: 4864 . dm - The DMPlex object 4865 4866 Output Parameter: 4867 . celltypeLabel - The DMLabel recording cell polytope type 4868 4869 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4870 DMCreateLabel(dm, "celltype") beforehand. 4871 4872 Level: developer 4873 4874 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4875 @*/ 4876 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) { 4877 PetscFunctionBegin; 4878 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4879 PetscValidPointer(celltypeLabel, 2); 4880 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4881 *celltypeLabel = dm->celltypeLabel; 4882 PetscFunctionReturn(0); 4883 } 4884 4885 /*@ 4886 DMPlexGetCellType - Get the polytope type of a given cell 4887 4888 Not Collective 4889 4890 Input Parameters: 4891 + dm - The DMPlex object 4892 - cell - The cell 4893 4894 Output Parameter: 4895 . celltype - The polytope type of the cell 4896 4897 Level: intermediate 4898 4899 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4900 @*/ 4901 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) { 4902 DMLabel label; 4903 PetscInt ct; 4904 4905 PetscFunctionBegin; 4906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4907 PetscValidPointer(celltype, 3); 4908 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4909 PetscCall(DMLabelGetValue(label, cell, &ct)); 4910 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4911 *celltype = (DMPolytopeType)ct; 4912 PetscFunctionReturn(0); 4913 } 4914 4915 /*@ 4916 DMPlexSetCellType - Set the polytope type of a given cell 4917 4918 Not Collective 4919 4920 Input Parameters: 4921 + dm - The DMPlex object 4922 . cell - The cell 4923 - celltype - The polytope type of the cell 4924 4925 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4926 is executed. This function will override the computed type. However, if automatic classification will not succeed 4927 and a user wants to manually specify all types, the classification must be disabled by calling 4928 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4929 4930 Level: advanced 4931 4932 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 4933 @*/ 4934 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) { 4935 DMLabel label; 4936 4937 PetscFunctionBegin; 4938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4939 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4940 PetscCall(DMLabelSetValue(label, cell, celltype)); 4941 PetscFunctionReturn(0); 4942 } 4943 4944 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) { 4945 PetscSection section, s; 4946 Mat m; 4947 PetscInt maxHeight; 4948 4949 PetscFunctionBegin; 4950 PetscCall(DMClone(dm, cdm)); 4951 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 4952 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 4953 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 4954 PetscCall(DMSetLocalSection(*cdm, section)); 4955 PetscCall(PetscSectionDestroy(§ion)); 4956 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 4957 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 4958 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 4959 PetscCall(PetscSectionDestroy(&s)); 4960 PetscCall(MatDestroy(&m)); 4961 4962 PetscCall(DMSetNumFields(*cdm, 1)); 4963 PetscCall(DMCreateDS(*cdm)); 4964 PetscFunctionReturn(0); 4965 } 4966 4967 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) { 4968 Vec coordsLocal, cellCoordsLocal; 4969 DM coordsDM, cellCoordsDM; 4970 4971 PetscFunctionBegin; 4972 *field = NULL; 4973 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 4974 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 4975 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 4976 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 4977 if (coordsLocal && coordsDM) { 4978 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 4979 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 4980 } 4981 PetscFunctionReturn(0); 4982 } 4983 4984 /*@C 4985 DMPlexGetConeSection - Return a section which describes the layout of cone data 4986 4987 Not Collective 4988 4989 Input Parameters: 4990 . dm - The DMPlex object 4991 4992 Output Parameter: 4993 . section - The PetscSection object 4994 4995 Level: developer 4996 4997 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 4998 @*/ 4999 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) { 5000 DM_Plex *mesh = (DM_Plex *)dm->data; 5001 5002 PetscFunctionBegin; 5003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5004 if (section) *section = mesh->coneSection; 5005 PetscFunctionReturn(0); 5006 } 5007 5008 /*@C 5009 DMPlexGetSupportSection - Return a section which describes the layout of support data 5010 5011 Not Collective 5012 5013 Input Parameters: 5014 . dm - The DMPlex object 5015 5016 Output Parameter: 5017 . section - The PetscSection object 5018 5019 Level: developer 5020 5021 .seealso: `DMPlexGetConeSection()` 5022 @*/ 5023 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) { 5024 DM_Plex *mesh = (DM_Plex *)dm->data; 5025 5026 PetscFunctionBegin; 5027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5028 if (section) *section = mesh->supportSection; 5029 PetscFunctionReturn(0); 5030 } 5031 5032 /*@C 5033 DMPlexGetCones - Return cone data 5034 5035 Not Collective 5036 5037 Input Parameters: 5038 . dm - The DMPlex object 5039 5040 Output Parameter: 5041 . cones - The cone for each point 5042 5043 Level: developer 5044 5045 .seealso: `DMPlexGetConeSection()` 5046 @*/ 5047 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) { 5048 DM_Plex *mesh = (DM_Plex *)dm->data; 5049 5050 PetscFunctionBegin; 5051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5052 if (cones) *cones = mesh->cones; 5053 PetscFunctionReturn(0); 5054 } 5055 5056 /*@C 5057 DMPlexGetConeOrientations - Return cone orientation data 5058 5059 Not Collective 5060 5061 Input Parameters: 5062 . dm - The DMPlex object 5063 5064 Output Parameter: 5065 . coneOrientations - The array of cone orientations for all points 5066 5067 Level: developer 5068 5069 Notes: 5070 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5071 5072 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5073 5074 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5075 @*/ 5076 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) { 5077 DM_Plex *mesh = (DM_Plex *)dm->data; 5078 5079 PetscFunctionBegin; 5080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5081 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5082 PetscFunctionReturn(0); 5083 } 5084 5085 /******************************** FEM Support **********************************/ 5086 5087 /* 5088 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5089 representing a line in the section. 5090 */ 5091 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) { 5092 PetscFunctionBeginHot; 5093 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5094 if (line < 0) { 5095 *k = 0; 5096 *Nc = 0; 5097 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5098 *k = 1; 5099 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5100 /* An order k SEM disc has k-1 dofs on an edge */ 5101 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5102 *k = *k / *Nc + 1; 5103 } 5104 PetscFunctionReturn(0); 5105 } 5106 5107 /*@ 5108 5109 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5110 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5111 section provided (or the section of the DM). 5112 5113 Input Parameters: 5114 + dm - The DM 5115 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5116 - section - The PetscSection to reorder, or NULL for the default section 5117 5118 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5119 degree of the basis. 5120 5121 Example: 5122 A typical interpolated single-quad mesh might order points as 5123 .vb 5124 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5125 5126 v4 -- e6 -- v3 5127 | | 5128 e7 c0 e8 5129 | | 5130 v1 -- e5 -- v2 5131 .ve 5132 5133 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5134 dofs in the order of points, e.g., 5135 .vb 5136 c0 -> [0,1,2,3] 5137 v1 -> [4] 5138 ... 5139 e5 -> [8, 9] 5140 .ve 5141 5142 which corresponds to the dofs 5143 .vb 5144 6 10 11 7 5145 13 2 3 15 5146 12 0 1 14 5147 4 8 9 5 5148 .ve 5149 5150 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5151 .vb 5152 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5153 .ve 5154 5155 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5156 .vb 5157 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5158 .ve 5159 5160 Level: developer 5161 5162 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5163 @*/ 5164 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) { 5165 DMLabel label; 5166 PetscInt dim, depth = -1, eStart = -1, Nf; 5167 PetscBool vertexchart; 5168 5169 PetscFunctionBegin; 5170 PetscCall(DMGetDimension(dm, &dim)); 5171 if (dim < 1) PetscFunctionReturn(0); 5172 if (point < 0) { 5173 PetscInt sStart, sEnd; 5174 5175 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5176 point = sEnd - sStart ? sStart : point; 5177 } 5178 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5179 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5180 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5181 if (depth == 1) { 5182 eStart = point; 5183 } else if (depth == dim) { 5184 const PetscInt *cone; 5185 5186 PetscCall(DMPlexGetCone(dm, point, &cone)); 5187 if (dim == 2) eStart = cone[0]; 5188 else if (dim == 3) { 5189 const PetscInt *cone2; 5190 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5191 eStart = cone2[0]; 5192 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5193 } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5194 { /* Determine whether the chart covers all points or just vertices. */ 5195 PetscInt pStart, pEnd, cStart, cEnd; 5196 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5197 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5198 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5199 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5200 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5201 } 5202 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5203 for (PetscInt d = 1; d <= dim; d++) { 5204 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5205 PetscInt *perm; 5206 5207 for (f = 0; f < Nf; ++f) { 5208 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5209 size += PetscPowInt(k + 1, d) * Nc; 5210 } 5211 PetscCall(PetscMalloc1(size, &perm)); 5212 for (f = 0; f < Nf; ++f) { 5213 switch (d) { 5214 case 1: 5215 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5216 /* 5217 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5218 We want [ vtx0; edge of length k-1; vtx1 ] 5219 */ 5220 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5221 for (i = 0; i < k - 1; i++) 5222 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5223 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5224 foffset = offset; 5225 break; 5226 case 2: 5227 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5228 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5229 /* The SEM order is 5230 5231 v_lb, {e_b}, v_rb, 5232 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5233 v_lt, reverse {e_t}, v_rt 5234 */ 5235 { 5236 const PetscInt of = 0; 5237 const PetscInt oeb = of + PetscSqr(k - 1); 5238 const PetscInt oer = oeb + (k - 1); 5239 const PetscInt oet = oer + (k - 1); 5240 const PetscInt oel = oet + (k - 1); 5241 const PetscInt ovlb = oel + (k - 1); 5242 const PetscInt ovrb = ovlb + 1; 5243 const PetscInt ovrt = ovrb + 1; 5244 const PetscInt ovlt = ovrt + 1; 5245 PetscInt o; 5246 5247 /* bottom */ 5248 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5249 for (o = oeb; o < oer; ++o) 5250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5251 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5252 /* middle */ 5253 for (i = 0; i < k - 1; ++i) { 5254 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5255 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5256 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5257 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5258 } 5259 /* top */ 5260 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5261 for (o = oel - 1; o >= oet; --o) 5262 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5263 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5264 foffset = offset; 5265 } 5266 break; 5267 case 3: 5268 /* The original hex closure is 5269 5270 {c, 5271 f_b, f_t, f_f, f_b, f_r, f_l, 5272 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5273 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5274 */ 5275 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5276 /* The SEM order is 5277 Bottom Slice 5278 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5279 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5280 v_blb, {e_bb}, v_brb, 5281 5282 Middle Slice (j) 5283 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5284 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5285 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5286 5287 Top Slice 5288 v_tlf, {e_tf}, v_trf, 5289 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5290 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5291 */ 5292 { 5293 const PetscInt oc = 0; 5294 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5295 const PetscInt oft = ofb + PetscSqr(k - 1); 5296 const PetscInt off = oft + PetscSqr(k - 1); 5297 const PetscInt ofk = off + PetscSqr(k - 1); 5298 const PetscInt ofr = ofk + PetscSqr(k - 1); 5299 const PetscInt ofl = ofr + PetscSqr(k - 1); 5300 const PetscInt oebl = ofl + PetscSqr(k - 1); 5301 const PetscInt oebb = oebl + (k - 1); 5302 const PetscInt oebr = oebb + (k - 1); 5303 const PetscInt oebf = oebr + (k - 1); 5304 const PetscInt oetf = oebf + (k - 1); 5305 const PetscInt oetr = oetf + (k - 1); 5306 const PetscInt oetb = oetr + (k - 1); 5307 const PetscInt oetl = oetb + (k - 1); 5308 const PetscInt oerf = oetl + (k - 1); 5309 const PetscInt oelf = oerf + (k - 1); 5310 const PetscInt oelb = oelf + (k - 1); 5311 const PetscInt oerb = oelb + (k - 1); 5312 const PetscInt ovblf = oerb + (k - 1); 5313 const PetscInt ovblb = ovblf + 1; 5314 const PetscInt ovbrb = ovblb + 1; 5315 const PetscInt ovbrf = ovbrb + 1; 5316 const PetscInt ovtlf = ovbrf + 1; 5317 const PetscInt ovtrf = ovtlf + 1; 5318 const PetscInt ovtrb = ovtrf + 1; 5319 const PetscInt ovtlb = ovtrb + 1; 5320 PetscInt o, n; 5321 5322 /* Bottom Slice */ 5323 /* bottom */ 5324 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5325 for (o = oetf - 1; o >= oebf; --o) 5326 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5327 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5328 /* middle */ 5329 for (i = 0; i < k - 1; ++i) { 5330 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5331 for (n = 0; n < k - 1; ++n) { 5332 o = ofb + n * (k - 1) + i; 5333 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5334 } 5335 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5336 } 5337 /* top */ 5338 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5339 for (o = oebb; o < oebr; ++o) 5340 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5341 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5342 5343 /* Middle Slice */ 5344 for (j = 0; j < k - 1; ++j) { 5345 /* bottom */ 5346 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5347 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5348 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5349 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5350 /* middle */ 5351 for (i = 0; i < k - 1; ++i) { 5352 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5353 for (n = 0; n < k - 1; ++n) 5354 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5355 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5356 } 5357 /* top */ 5358 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5359 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5360 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5361 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5362 } 5363 5364 /* Top Slice */ 5365 /* bottom */ 5366 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5367 for (o = oetf; o < oetr; ++o) 5368 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5369 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5370 /* middle */ 5371 for (i = 0; i < k - 1; ++i) { 5372 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5373 for (n = 0; n < k - 1; ++n) 5374 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5375 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5376 } 5377 /* top */ 5378 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5379 for (o = oetl - 1; o >= oetb; --o) 5380 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5381 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5382 5383 foffset = offset; 5384 } 5385 break; 5386 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5387 } 5388 } 5389 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5390 /* Check permutation */ 5391 { 5392 PetscInt *check; 5393 5394 PetscCall(PetscMalloc1(size, &check)); 5395 for (i = 0; i < size; ++i) { 5396 check[i] = -1; 5397 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5398 } 5399 for (i = 0; i < size; ++i) check[perm[i]] = i; 5400 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5401 PetscCall(PetscFree(check)); 5402 } 5403 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5404 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5405 PetscInt *loc_perm; 5406 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5407 for (PetscInt i = 0; i < size; i++) { 5408 loc_perm[i] = perm[i]; 5409 loc_perm[size + i] = size + perm[i]; 5410 } 5411 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5412 } 5413 } 5414 PetscFunctionReturn(0); 5415 } 5416 5417 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) { 5418 PetscDS prob; 5419 PetscInt depth, Nf, h; 5420 DMLabel label; 5421 5422 PetscFunctionBeginHot; 5423 PetscCall(DMGetDS(dm, &prob)); 5424 Nf = prob->Nf; 5425 label = dm->depthLabel; 5426 *dspace = NULL; 5427 if (field < Nf) { 5428 PetscObject disc = prob->disc[field]; 5429 5430 if (disc->classid == PETSCFE_CLASSID) { 5431 PetscDualSpace dsp; 5432 5433 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5434 PetscCall(DMLabelGetNumValues(label, &depth)); 5435 PetscCall(DMLabelGetValue(label, point, &h)); 5436 h = depth - 1 - h; 5437 if (h) { 5438 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5439 } else { 5440 *dspace = dsp; 5441 } 5442 } 5443 } 5444 PetscFunctionReturn(0); 5445 } 5446 5447 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5448 PetscScalar *array; 5449 const PetscScalar *vArray; 5450 const PetscInt *cone, *coneO; 5451 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5452 5453 PetscFunctionBeginHot; 5454 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5455 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5456 PetscCall(DMPlexGetCone(dm, point, &cone)); 5457 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5458 if (!values || !*values) { 5459 if ((point >= pStart) && (point < pEnd)) { 5460 PetscInt dof; 5461 5462 PetscCall(PetscSectionGetDof(section, point, &dof)); 5463 size += dof; 5464 } 5465 for (p = 0; p < numPoints; ++p) { 5466 const PetscInt cp = cone[p]; 5467 PetscInt dof; 5468 5469 if ((cp < pStart) || (cp >= pEnd)) continue; 5470 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5471 size += dof; 5472 } 5473 if (!values) { 5474 if (csize) *csize = size; 5475 PetscFunctionReturn(0); 5476 } 5477 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5478 } else { 5479 array = *values; 5480 } 5481 size = 0; 5482 PetscCall(VecGetArrayRead(v, &vArray)); 5483 if ((point >= pStart) && (point < pEnd)) { 5484 PetscInt dof, off, d; 5485 const PetscScalar *varr; 5486 5487 PetscCall(PetscSectionGetDof(section, point, &dof)); 5488 PetscCall(PetscSectionGetOffset(section, point, &off)); 5489 varr = &vArray[off]; 5490 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5491 size += dof; 5492 } 5493 for (p = 0; p < numPoints; ++p) { 5494 const PetscInt cp = cone[p]; 5495 PetscInt o = coneO[p]; 5496 PetscInt dof, off, d; 5497 const PetscScalar *varr; 5498 5499 if ((cp < pStart) || (cp >= pEnd)) continue; 5500 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5501 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5502 varr = &vArray[off]; 5503 if (o >= 0) { 5504 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5505 } else { 5506 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5507 } 5508 size += dof; 5509 } 5510 PetscCall(VecRestoreArrayRead(v, &vArray)); 5511 if (!*values) { 5512 if (csize) *csize = size; 5513 *values = array; 5514 } else { 5515 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5516 *csize = size; 5517 } 5518 PetscFunctionReturn(0); 5519 } 5520 5521 /* Compress out points not in the section */ 5522 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) { 5523 const PetscInt np = *numPoints; 5524 PetscInt pStart, pEnd, p, q; 5525 5526 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5527 for (p = 0, q = 0; p < np; ++p) { 5528 const PetscInt r = points[p * 2]; 5529 if ((r >= pStart) && (r < pEnd)) { 5530 points[q * 2] = r; 5531 points[q * 2 + 1] = points[p * 2 + 1]; 5532 ++q; 5533 } 5534 } 5535 *numPoints = q; 5536 return 0; 5537 } 5538 5539 /* Compressed closure does not apply closure permutation */ 5540 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5541 const PetscInt *cla = NULL; 5542 PetscInt np, *pts = NULL; 5543 5544 PetscFunctionBeginHot; 5545 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5546 if (*clPoints) { 5547 PetscInt dof, off; 5548 5549 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5550 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5551 PetscCall(ISGetIndices(*clPoints, &cla)); 5552 np = dof / 2; 5553 pts = (PetscInt *)&cla[off]; 5554 } else { 5555 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5556 PetscCall(CompressPoints_Private(section, &np, pts)); 5557 } 5558 *numPoints = np; 5559 *points = pts; 5560 *clp = cla; 5561 PetscFunctionReturn(0); 5562 } 5563 5564 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5565 PetscFunctionBeginHot; 5566 if (!*clPoints) { 5567 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5568 } else { 5569 PetscCall(ISRestoreIndices(*clPoints, clp)); 5570 } 5571 *numPoints = 0; 5572 *points = NULL; 5573 *clSec = NULL; 5574 *clPoints = NULL; 5575 *clp = NULL; 5576 PetscFunctionReturn(0); 5577 } 5578 5579 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) { 5580 PetscInt offset = 0, p; 5581 const PetscInt **perms = NULL; 5582 const PetscScalar **flips = NULL; 5583 5584 PetscFunctionBeginHot; 5585 *size = 0; 5586 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5587 for (p = 0; p < numPoints; p++) { 5588 const PetscInt point = points[2 * p]; 5589 const PetscInt *perm = perms ? perms[p] : NULL; 5590 const PetscScalar *flip = flips ? flips[p] : NULL; 5591 PetscInt dof, off, d; 5592 const PetscScalar *varr; 5593 5594 PetscCall(PetscSectionGetDof(section, point, &dof)); 5595 PetscCall(PetscSectionGetOffset(section, point, &off)); 5596 varr = &vArray[off]; 5597 if (clperm) { 5598 if (perm) { 5599 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5600 } else { 5601 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5602 } 5603 if (flip) { 5604 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5605 } 5606 } else { 5607 if (perm) { 5608 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5609 } else { 5610 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5611 } 5612 if (flip) { 5613 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5614 } 5615 } 5616 offset += dof; 5617 } 5618 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5619 *size = offset; 5620 PetscFunctionReturn(0); 5621 } 5622 5623 static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) { 5624 PetscInt offset = 0, f; 5625 5626 PetscFunctionBeginHot; 5627 *size = 0; 5628 for (f = 0; f < numFields; ++f) { 5629 PetscInt p; 5630 const PetscInt **perms = NULL; 5631 const PetscScalar **flips = NULL; 5632 5633 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5634 for (p = 0; p < numPoints; p++) { 5635 const PetscInt point = points[2 * p]; 5636 PetscInt fdof, foff, b; 5637 const PetscScalar *varr; 5638 const PetscInt *perm = perms ? perms[p] : NULL; 5639 const PetscScalar *flip = flips ? flips[p] : NULL; 5640 5641 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5642 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5643 varr = &vArray[foff]; 5644 if (clperm) { 5645 if (perm) { 5646 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5647 } else { 5648 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5649 } 5650 if (flip) { 5651 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5652 } 5653 } else { 5654 if (perm) { 5655 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5656 } else { 5657 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5658 } 5659 if (flip) { 5660 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5661 } 5662 } 5663 offset += fdof; 5664 } 5665 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5666 } 5667 *size = offset; 5668 PetscFunctionReturn(0); 5669 } 5670 5671 /*@C 5672 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5673 5674 Not collective 5675 5676 Input Parameters: 5677 + dm - The DM 5678 . section - The section describing the layout in v, or NULL to use the default section 5679 . v - The local vector 5680 - point - The point in the DM 5681 5682 Input/Output Parameters: 5683 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5684 - values - An array to use for the values, or NULL to have it allocated automatically; 5685 if the user provided NULL, it is a borrowed array and should not be freed 5686 5687 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5688 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5689 $ assembly function, and a user may already have allocated storage for this operation. 5690 $ 5691 $ A typical use could be 5692 $ 5693 $ values = NULL; 5694 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5695 $ for (cl = 0; cl < clSize; ++cl) { 5696 $ <Compute on closure> 5697 $ } 5698 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5699 $ 5700 $ or 5701 $ 5702 $ PetscMalloc1(clMaxSize, &values); 5703 $ for (p = pStart; p < pEnd; ++p) { 5704 $ clSize = clMaxSize; 5705 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5706 $ for (cl = 0; cl < clSize; ++cl) { 5707 $ <Compute on closure> 5708 $ } 5709 $ } 5710 $ PetscFree(values); 5711 5712 Fortran Notes: 5713 Since it returns an array, this routine is only available in Fortran 90, and you must 5714 include petsc.h90 in your code. 5715 5716 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5717 5718 Level: intermediate 5719 5720 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5721 @*/ 5722 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5723 PetscSection clSection; 5724 IS clPoints; 5725 PetscInt *points = NULL; 5726 const PetscInt *clp, *perm; 5727 PetscInt depth, numFields, numPoints, asize; 5728 5729 PetscFunctionBeginHot; 5730 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5731 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5732 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5733 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5734 PetscCall(DMPlexGetDepth(dm, &depth)); 5735 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5736 if (depth == 1 && numFields < 2) { 5737 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5738 PetscFunctionReturn(0); 5739 } 5740 /* Get points */ 5741 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5742 /* Get sizes */ 5743 asize = 0; 5744 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5745 PetscInt dof; 5746 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5747 asize += dof; 5748 } 5749 if (values) { 5750 const PetscScalar *vArray; 5751 PetscInt size; 5752 5753 if (*values) { 5754 PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 5755 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5756 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5757 PetscCall(VecGetArrayRead(v, &vArray)); 5758 /* Get values */ 5759 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5760 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5761 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5762 /* Cleanup array */ 5763 PetscCall(VecRestoreArrayRead(v, &vArray)); 5764 } 5765 if (csize) *csize = asize; 5766 /* Cleanup points */ 5767 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5768 PetscFunctionReturn(0); 5769 } 5770 5771 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) { 5772 DMLabel depthLabel; 5773 PetscSection clSection; 5774 IS clPoints; 5775 PetscScalar *array; 5776 const PetscScalar *vArray; 5777 PetscInt *points = NULL; 5778 const PetscInt *clp, *perm = NULL; 5779 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5780 5781 PetscFunctionBeginHot; 5782 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5783 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5784 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5785 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5786 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5787 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5788 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5789 if (mdepth == 1 && numFields < 2) { 5790 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5791 PetscFunctionReturn(0); 5792 } 5793 /* Get points */ 5794 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5795 for (clsize = 0, p = 0; p < Np; p++) { 5796 PetscInt dof; 5797 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 5798 clsize += dof; 5799 } 5800 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 5801 /* Filter points */ 5802 for (p = 0; p < numPoints * 2; p += 2) { 5803 PetscInt dep; 5804 5805 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5806 if (dep != depth) continue; 5807 points[Np * 2 + 0] = points[p]; 5808 points[Np * 2 + 1] = points[p + 1]; 5809 ++Np; 5810 } 5811 /* Get array */ 5812 if (!values || !*values) { 5813 PetscInt asize = 0, dof; 5814 5815 for (p = 0; p < Np * 2; p += 2) { 5816 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5817 asize += dof; 5818 } 5819 if (!values) { 5820 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5821 if (csize) *csize = asize; 5822 PetscFunctionReturn(0); 5823 } 5824 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5825 } else { 5826 array = *values; 5827 } 5828 PetscCall(VecGetArrayRead(v, &vArray)); 5829 /* Get values */ 5830 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5831 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5832 /* Cleanup points */ 5833 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5834 /* Cleanup array */ 5835 PetscCall(VecRestoreArrayRead(v, &vArray)); 5836 if (!*values) { 5837 if (csize) *csize = size; 5838 *values = array; 5839 } else { 5840 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5841 *csize = size; 5842 } 5843 PetscFunctionReturn(0); 5844 } 5845 5846 /*@C 5847 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5848 5849 Not collective 5850 5851 Input Parameters: 5852 + dm - The DM 5853 . section - The section describing the layout in v, or NULL to use the default section 5854 . v - The local vector 5855 . point - The point in the DM 5856 . csize - The number of values in the closure, or NULL 5857 - values - The array of values, which is a borrowed array and should not be freed 5858 5859 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5860 5861 Fortran Notes: 5862 Since it returns an array, this routine is only available in Fortran 90, and you must 5863 include petsc.h90 in your code. 5864 5865 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5866 5867 Level: intermediate 5868 5869 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5870 @*/ 5871 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5872 PetscInt size = 0; 5873 5874 PetscFunctionBegin; 5875 /* Should work without recalculating size */ 5876 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 5877 *values = NULL; 5878 PetscFunctionReturn(0); 5879 } 5880 5881 static inline void add(PetscScalar *x, PetscScalar y) { 5882 *x += y; 5883 } 5884 static inline void insert(PetscScalar *x, PetscScalar y) { 5885 *x = y; 5886 } 5887 5888 static inline PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) { 5889 PetscInt cdof; /* The number of constraints on this point */ 5890 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5891 PetscScalar *a; 5892 PetscInt off, cind = 0, k; 5893 5894 PetscFunctionBegin; 5895 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5896 PetscCall(PetscSectionGetOffset(section, point, &off)); 5897 a = &array[off]; 5898 if (!cdof || setBC) { 5899 if (clperm) { 5900 if (perm) { 5901 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5902 } else { 5903 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5904 } 5905 } else { 5906 if (perm) { 5907 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5908 } else { 5909 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5910 } 5911 } 5912 } else { 5913 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5914 if (clperm) { 5915 if (perm) { 5916 for (k = 0; k < dof; ++k) { 5917 if ((cind < cdof) && (k == cdofs[cind])) { 5918 ++cind; 5919 continue; 5920 } 5921 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5922 } 5923 } else { 5924 for (k = 0; k < dof; ++k) { 5925 if ((cind < cdof) && (k == cdofs[cind])) { 5926 ++cind; 5927 continue; 5928 } 5929 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5930 } 5931 } 5932 } else { 5933 if (perm) { 5934 for (k = 0; k < dof; ++k) { 5935 if ((cind < cdof) && (k == cdofs[cind])) { 5936 ++cind; 5937 continue; 5938 } 5939 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5940 } 5941 } else { 5942 for (k = 0; k < dof; ++k) { 5943 if ((cind < cdof) && (k == cdofs[cind])) { 5944 ++cind; 5945 continue; 5946 } 5947 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5948 } 5949 } 5950 } 5951 } 5952 PetscFunctionReturn(0); 5953 } 5954 5955 static inline PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) { 5956 PetscInt cdof; /* The number of constraints on this point */ 5957 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5958 PetscScalar *a; 5959 PetscInt off, cind = 0, k; 5960 5961 PetscFunctionBegin; 5962 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5963 PetscCall(PetscSectionGetOffset(section, point, &off)); 5964 a = &array[off]; 5965 if (cdof) { 5966 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5967 if (clperm) { 5968 if (perm) { 5969 for (k = 0; k < dof; ++k) { 5970 if ((cind < cdof) && (k == cdofs[cind])) { 5971 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5972 cind++; 5973 } 5974 } 5975 } else { 5976 for (k = 0; k < dof; ++k) { 5977 if ((cind < cdof) && (k == cdofs[cind])) { 5978 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5979 cind++; 5980 } 5981 } 5982 } 5983 } else { 5984 if (perm) { 5985 for (k = 0; k < dof; ++k) { 5986 if ((cind < cdof) && (k == cdofs[cind])) { 5987 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5988 cind++; 5989 } 5990 } 5991 } else { 5992 for (k = 0; k < dof; ++k) { 5993 if ((cind < cdof) && (k == cdofs[cind])) { 5994 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5995 cind++; 5996 } 5997 } 5998 } 5999 } 6000 } 6001 PetscFunctionReturn(0); 6002 } 6003 6004 static inline PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) { 6005 PetscScalar *a; 6006 PetscInt fdof, foff, fcdof, foffset = *offset; 6007 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6008 PetscInt cind = 0, b; 6009 6010 PetscFunctionBegin; 6011 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6012 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6013 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6014 a = &array[foff]; 6015 if (!fcdof || setBC) { 6016 if (clperm) { 6017 if (perm) { 6018 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6019 } else { 6020 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6021 } 6022 } else { 6023 if (perm) { 6024 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6025 } else { 6026 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6027 } 6028 } 6029 } else { 6030 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6031 if (clperm) { 6032 if (perm) { 6033 for (b = 0; b < fdof; b++) { 6034 if ((cind < fcdof) && (b == fcdofs[cind])) { 6035 ++cind; 6036 continue; 6037 } 6038 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6039 } 6040 } else { 6041 for (b = 0; b < fdof; b++) { 6042 if ((cind < fcdof) && (b == fcdofs[cind])) { 6043 ++cind; 6044 continue; 6045 } 6046 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6047 } 6048 } 6049 } else { 6050 if (perm) { 6051 for (b = 0; b < fdof; b++) { 6052 if ((cind < fcdof) && (b == fcdofs[cind])) { 6053 ++cind; 6054 continue; 6055 } 6056 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6057 } 6058 } else { 6059 for (b = 0; b < fdof; b++) { 6060 if ((cind < fcdof) && (b == fcdofs[cind])) { 6061 ++cind; 6062 continue; 6063 } 6064 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6065 } 6066 } 6067 } 6068 } 6069 *offset += fdof; 6070 PetscFunctionReturn(0); 6071 } 6072 6073 static inline PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar *, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) { 6074 PetscScalar *a; 6075 PetscInt fdof, foff, fcdof, foffset = *offset; 6076 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6077 PetscInt Nc, cind = 0, ncind = 0, b; 6078 PetscBool ncSet, fcSet; 6079 6080 PetscFunctionBegin; 6081 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6082 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6083 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6084 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6085 a = &array[foff]; 6086 if (fcdof) { 6087 /* We just override fcdof and fcdofs with Ncc and comps */ 6088 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6089 if (clperm) { 6090 if (perm) { 6091 if (comps) { 6092 for (b = 0; b < fdof; b++) { 6093 ncSet = fcSet = PETSC_FALSE; 6094 if (b % Nc == comps[ncind]) { 6095 ncind = (ncind + 1) % Ncc; 6096 ncSet = PETSC_TRUE; 6097 } 6098 if ((cind < fcdof) && (b == fcdofs[cind])) { 6099 ++cind; 6100 fcSet = PETSC_TRUE; 6101 } 6102 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6103 } 6104 } else { 6105 for (b = 0; b < fdof; b++) { 6106 if ((cind < fcdof) && (b == fcdofs[cind])) { 6107 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6108 ++cind; 6109 } 6110 } 6111 } 6112 } else { 6113 if (comps) { 6114 for (b = 0; b < fdof; b++) { 6115 ncSet = fcSet = PETSC_FALSE; 6116 if (b % Nc == comps[ncind]) { 6117 ncind = (ncind + 1) % Ncc; 6118 ncSet = PETSC_TRUE; 6119 } 6120 if ((cind < fcdof) && (b == fcdofs[cind])) { 6121 ++cind; 6122 fcSet = PETSC_TRUE; 6123 } 6124 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6125 } 6126 } else { 6127 for (b = 0; b < fdof; b++) { 6128 if ((cind < fcdof) && (b == fcdofs[cind])) { 6129 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6130 ++cind; 6131 } 6132 } 6133 } 6134 } 6135 } else { 6136 if (perm) { 6137 if (comps) { 6138 for (b = 0; b < fdof; b++) { 6139 ncSet = fcSet = PETSC_FALSE; 6140 if (b % Nc == comps[ncind]) { 6141 ncind = (ncind + 1) % Ncc; 6142 ncSet = PETSC_TRUE; 6143 } 6144 if ((cind < fcdof) && (b == fcdofs[cind])) { 6145 ++cind; 6146 fcSet = PETSC_TRUE; 6147 } 6148 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6149 } 6150 } else { 6151 for (b = 0; b < fdof; b++) { 6152 if ((cind < fcdof) && (b == fcdofs[cind])) { 6153 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6154 ++cind; 6155 } 6156 } 6157 } 6158 } else { 6159 if (comps) { 6160 for (b = 0; b < fdof; b++) { 6161 ncSet = fcSet = PETSC_FALSE; 6162 if (b % Nc == comps[ncind]) { 6163 ncind = (ncind + 1) % Ncc; 6164 ncSet = PETSC_TRUE; 6165 } 6166 if ((cind < fcdof) && (b == fcdofs[cind])) { 6167 ++cind; 6168 fcSet = PETSC_TRUE; 6169 } 6170 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6171 } 6172 } else { 6173 for (b = 0; b < fdof; b++) { 6174 if ((cind < fcdof) && (b == fcdofs[cind])) { 6175 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6176 ++cind; 6177 } 6178 } 6179 } 6180 } 6181 } 6182 } 6183 *offset += fdof; 6184 PetscFunctionReturn(0); 6185 } 6186 6187 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6188 PetscScalar *array; 6189 const PetscInt *cone, *coneO; 6190 PetscInt pStart, pEnd, p, numPoints, off, dof; 6191 6192 PetscFunctionBeginHot; 6193 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6194 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6195 PetscCall(DMPlexGetCone(dm, point, &cone)); 6196 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6197 PetscCall(VecGetArray(v, &array)); 6198 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6199 const PetscInt cp = !p ? point : cone[p - 1]; 6200 const PetscInt o = !p ? 0 : coneO[p - 1]; 6201 6202 if ((cp < pStart) || (cp >= pEnd)) { 6203 dof = 0; 6204 continue; 6205 } 6206 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6207 /* ADD_VALUES */ 6208 { 6209 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6210 PetscScalar *a; 6211 PetscInt cdof, coff, cind = 0, k; 6212 6213 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6214 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6215 a = &array[coff]; 6216 if (!cdof) { 6217 if (o >= 0) { 6218 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6219 } else { 6220 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6221 } 6222 } else { 6223 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6224 if (o >= 0) { 6225 for (k = 0; k < dof; ++k) { 6226 if ((cind < cdof) && (k == cdofs[cind])) { 6227 ++cind; 6228 continue; 6229 } 6230 a[k] += values[off + k]; 6231 } 6232 } else { 6233 for (k = 0; k < dof; ++k) { 6234 if ((cind < cdof) && (k == cdofs[cind])) { 6235 ++cind; 6236 continue; 6237 } 6238 a[k] += values[off + dof - k - 1]; 6239 } 6240 } 6241 } 6242 } 6243 } 6244 PetscCall(VecRestoreArray(v, &array)); 6245 PetscFunctionReturn(0); 6246 } 6247 6248 /*@C 6249 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6250 6251 Not collective 6252 6253 Input Parameters: 6254 + dm - The DM 6255 . section - The section describing the layout in v, or NULL to use the default section 6256 . v - The local vector 6257 . point - The point in the DM 6258 . values - The array of values 6259 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6260 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6261 6262 Fortran Notes: 6263 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6264 6265 Level: intermediate 6266 6267 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6268 @*/ 6269 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6270 PetscSection clSection; 6271 IS clPoints; 6272 PetscScalar *array; 6273 PetscInt *points = NULL; 6274 const PetscInt *clp, *clperm = NULL; 6275 PetscInt depth, numFields, numPoints, p, clsize; 6276 6277 PetscFunctionBeginHot; 6278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6279 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6280 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6281 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6282 PetscCall(DMPlexGetDepth(dm, &depth)); 6283 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6284 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6285 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6286 PetscFunctionReturn(0); 6287 } 6288 /* Get points */ 6289 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6290 for (clsize = 0, p = 0; p < numPoints; p++) { 6291 PetscInt dof; 6292 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6293 clsize += dof; 6294 } 6295 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6296 /* Get array */ 6297 PetscCall(VecGetArray(v, &array)); 6298 /* Get values */ 6299 if (numFields > 0) { 6300 PetscInt offset = 0, f; 6301 for (f = 0; f < numFields; ++f) { 6302 const PetscInt **perms = NULL; 6303 const PetscScalar **flips = NULL; 6304 6305 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6306 switch (mode) { 6307 case INSERT_VALUES: 6308 for (p = 0; p < numPoints; p++) { 6309 const PetscInt point = points[2 * p]; 6310 const PetscInt *perm = perms ? perms[p] : NULL; 6311 const PetscScalar *flip = flips ? flips[p] : NULL; 6312 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6313 } 6314 break; 6315 case INSERT_ALL_VALUES: 6316 for (p = 0; p < numPoints; p++) { 6317 const PetscInt point = points[2 * p]; 6318 const PetscInt *perm = perms ? perms[p] : NULL; 6319 const PetscScalar *flip = flips ? flips[p] : NULL; 6320 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6321 } 6322 break; 6323 case INSERT_BC_VALUES: 6324 for (p = 0; p < numPoints; p++) { 6325 const PetscInt point = points[2 * p]; 6326 const PetscInt *perm = perms ? perms[p] : NULL; 6327 const PetscScalar *flip = flips ? flips[p] : NULL; 6328 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6329 } 6330 break; 6331 case ADD_VALUES: 6332 for (p = 0; p < numPoints; p++) { 6333 const PetscInt point = points[2 * p]; 6334 const PetscInt *perm = perms ? perms[p] : NULL; 6335 const PetscScalar *flip = flips ? flips[p] : NULL; 6336 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6337 } 6338 break; 6339 case ADD_ALL_VALUES: 6340 for (p = 0; p < numPoints; p++) { 6341 const PetscInt point = points[2 * p]; 6342 const PetscInt *perm = perms ? perms[p] : NULL; 6343 const PetscScalar *flip = flips ? flips[p] : NULL; 6344 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6345 } 6346 break; 6347 case ADD_BC_VALUES: 6348 for (p = 0; p < numPoints; p++) { 6349 const PetscInt point = points[2 * p]; 6350 const PetscInt *perm = perms ? perms[p] : NULL; 6351 const PetscScalar *flip = flips ? flips[p] : NULL; 6352 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6353 } 6354 break; 6355 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6356 } 6357 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6358 } 6359 } else { 6360 PetscInt dof, off; 6361 const PetscInt **perms = NULL; 6362 const PetscScalar **flips = NULL; 6363 6364 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6365 switch (mode) { 6366 case INSERT_VALUES: 6367 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6368 const PetscInt point = points[2 * p]; 6369 const PetscInt *perm = perms ? perms[p] : NULL; 6370 const PetscScalar *flip = flips ? flips[p] : NULL; 6371 PetscCall(PetscSectionGetDof(section, point, &dof)); 6372 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6373 } 6374 break; 6375 case INSERT_ALL_VALUES: 6376 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6377 const PetscInt point = points[2 * p]; 6378 const PetscInt *perm = perms ? perms[p] : NULL; 6379 const PetscScalar *flip = flips ? flips[p] : NULL; 6380 PetscCall(PetscSectionGetDof(section, point, &dof)); 6381 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6382 } 6383 break; 6384 case INSERT_BC_VALUES: 6385 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6386 const PetscInt point = points[2 * p]; 6387 const PetscInt *perm = perms ? perms[p] : NULL; 6388 const PetscScalar *flip = flips ? flips[p] : NULL; 6389 PetscCall(PetscSectionGetDof(section, point, &dof)); 6390 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6391 } 6392 break; 6393 case ADD_VALUES: 6394 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6395 const PetscInt point = points[2 * p]; 6396 const PetscInt *perm = perms ? perms[p] : NULL; 6397 const PetscScalar *flip = flips ? flips[p] : NULL; 6398 PetscCall(PetscSectionGetDof(section, point, &dof)); 6399 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6400 } 6401 break; 6402 case ADD_ALL_VALUES: 6403 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6404 const PetscInt point = points[2 * p]; 6405 const PetscInt *perm = perms ? perms[p] : NULL; 6406 const PetscScalar *flip = flips ? flips[p] : NULL; 6407 PetscCall(PetscSectionGetDof(section, point, &dof)); 6408 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6409 } 6410 break; 6411 case ADD_BC_VALUES: 6412 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6413 const PetscInt point = points[2 * p]; 6414 const PetscInt *perm = perms ? perms[p] : NULL; 6415 const PetscScalar *flip = flips ? flips[p] : NULL; 6416 PetscCall(PetscSectionGetDof(section, point, &dof)); 6417 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6418 } 6419 break; 6420 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6421 } 6422 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6423 } 6424 /* Cleanup points */ 6425 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6426 /* Cleanup array */ 6427 PetscCall(VecRestoreArray(v, &array)); 6428 PetscFunctionReturn(0); 6429 } 6430 6431 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6432 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) { 6433 PetscFunctionBegin; 6434 if (label) { 6435 PetscBool contains; 6436 PetscInt fdof; 6437 6438 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6439 if (!contains) { 6440 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6441 *offset += fdof; 6442 PetscFunctionReturn(1); 6443 } 6444 } 6445 PetscFunctionReturn(0); 6446 } 6447 6448 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6449 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode) { 6450 PetscSection clSection; 6451 IS clPoints; 6452 PetscScalar *array; 6453 PetscInt *points = NULL; 6454 const PetscInt *clp; 6455 PetscInt numFields, numPoints, p; 6456 PetscInt offset = 0, f; 6457 6458 PetscFunctionBeginHot; 6459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6460 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6461 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6462 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6463 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6464 /* Get points */ 6465 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6466 /* Get array */ 6467 PetscCall(VecGetArray(v, &array)); 6468 /* Get values */ 6469 for (f = 0; f < numFields; ++f) { 6470 const PetscInt **perms = NULL; 6471 const PetscScalar **flips = NULL; 6472 6473 if (!fieldActive[f]) { 6474 for (p = 0; p < numPoints * 2; p += 2) { 6475 PetscInt fdof; 6476 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6477 offset += fdof; 6478 } 6479 continue; 6480 } 6481 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6482 switch (mode) { 6483 case INSERT_VALUES: 6484 for (p = 0; p < numPoints; p++) { 6485 const PetscInt point = points[2 * p]; 6486 const PetscInt *perm = perms ? perms[p] : NULL; 6487 const PetscScalar *flip = flips ? flips[p] : NULL; 6488 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) 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 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6498 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6499 } 6500 break; 6501 case INSERT_BC_VALUES: 6502 for (p = 0; p < numPoints; p++) { 6503 const PetscInt point = points[2 * p]; 6504 const PetscInt *perm = perms ? perms[p] : NULL; 6505 const PetscScalar *flip = flips ? flips[p] : NULL; 6506 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6507 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6508 } 6509 break; 6510 case ADD_VALUES: 6511 for (p = 0; p < numPoints; p++) { 6512 const PetscInt point = points[2 * p]; 6513 const PetscInt *perm = perms ? perms[p] : NULL; 6514 const PetscScalar *flip = flips ? flips[p] : NULL; 6515 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6516 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6517 } 6518 break; 6519 case ADD_ALL_VALUES: 6520 for (p = 0; p < numPoints; p++) { 6521 const PetscInt point = points[2 * p]; 6522 const PetscInt *perm = perms ? perms[p] : NULL; 6523 const PetscScalar *flip = flips ? flips[p] : NULL; 6524 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6525 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6526 } 6527 break; 6528 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6529 } 6530 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6531 } 6532 /* Cleanup points */ 6533 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6534 /* Cleanup array */ 6535 PetscCall(VecRestoreArray(v, &array)); 6536 PetscFunctionReturn(0); 6537 } 6538 6539 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) { 6540 PetscMPIInt rank; 6541 PetscInt i, j; 6542 6543 PetscFunctionBegin; 6544 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6545 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6546 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6547 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6548 numCIndices = numCIndices ? numCIndices : numRIndices; 6549 if (!values) PetscFunctionReturn(0); 6550 for (i = 0; i < numRIndices; i++) { 6551 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6552 for (j = 0; j < numCIndices; j++) { 6553 #if defined(PETSC_USE_COMPLEX) 6554 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6555 #else 6556 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6557 #endif 6558 } 6559 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6560 } 6561 PetscFunctionReturn(0); 6562 } 6563 6564 /* 6565 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6566 6567 Input Parameters: 6568 + section - The section for this data layout 6569 . islocal - Is the section (and thus indices being requested) local or global? 6570 . point - The point contributing dofs with these indices 6571 . off - The global offset of this point 6572 . loff - The local offset of each field 6573 . setBC - The flag determining whether to include indices of boundary values 6574 . perm - A permutation of the dofs on this point, or NULL 6575 - indperm - A permutation of the entire indices array, or NULL 6576 6577 Output Parameter: 6578 . indices - Indices for dofs on this point 6579 6580 Level: developer 6581 6582 Note: The indices could be local or global, depending on the value of 'off'. 6583 */ 6584 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) { 6585 PetscInt dof; /* The number of unknowns on this point */ 6586 PetscInt cdof; /* The number of constraints on this point */ 6587 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6588 PetscInt cind = 0, k; 6589 6590 PetscFunctionBegin; 6591 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6592 PetscCall(PetscSectionGetDof(section, point, &dof)); 6593 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6594 if (!cdof || setBC) { 6595 for (k = 0; k < dof; ++k) { 6596 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6597 const PetscInt ind = indperm ? indperm[preind] : preind; 6598 6599 indices[ind] = off + k; 6600 } 6601 } else { 6602 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6603 for (k = 0; k < dof; ++k) { 6604 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6605 const PetscInt ind = indperm ? indperm[preind] : preind; 6606 6607 if ((cind < cdof) && (k == cdofs[cind])) { 6608 /* Insert check for returning constrained indices */ 6609 indices[ind] = -(off + k + 1); 6610 ++cind; 6611 } else { 6612 indices[ind] = off + k - (islocal ? 0 : cind); 6613 } 6614 } 6615 } 6616 *loff += dof; 6617 PetscFunctionReturn(0); 6618 } 6619 6620 /* 6621 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6622 6623 Input Parameters: 6624 + section - a section (global or local) 6625 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6626 . point - point within section 6627 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6628 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6629 . setBC - identify constrained (boundary condition) points via involution. 6630 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6631 . permsoff - offset 6632 - indperm - index permutation 6633 6634 Output Parameter: 6635 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6636 . indices - array to hold indices (as defined by section) of each dof associated with point 6637 6638 Notes: 6639 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6640 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6641 in the local vector. 6642 6643 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6644 significant). It is invalid to call with a global section and setBC=true. 6645 6646 Developer Note: 6647 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6648 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6649 offset could be obtained from the section instead of passing it explicitly as we do now. 6650 6651 Example: 6652 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6653 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6654 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6655 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. 6656 6657 Level: developer 6658 */ 6659 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[]) { 6660 PetscInt numFields, foff, f; 6661 6662 PetscFunctionBegin; 6663 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6664 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6665 for (f = 0, foff = 0; f < numFields; ++f) { 6666 PetscInt fdof, cfdof; 6667 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6668 PetscInt cind = 0, b; 6669 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6670 6671 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6672 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6673 if (!cfdof || setBC) { 6674 for (b = 0; b < fdof; ++b) { 6675 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6676 const PetscInt ind = indperm ? indperm[preind] : preind; 6677 6678 indices[ind] = off + foff + b; 6679 } 6680 } else { 6681 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6682 for (b = 0; b < fdof; ++b) { 6683 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6684 const PetscInt ind = indperm ? indperm[preind] : preind; 6685 6686 if ((cind < cfdof) && (b == fcdofs[cind])) { 6687 indices[ind] = -(off + foff + b + 1); 6688 ++cind; 6689 } else { 6690 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6691 } 6692 } 6693 } 6694 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6695 foffs[f] += fdof; 6696 } 6697 PetscFunctionReturn(0); 6698 } 6699 6700 /* 6701 This version believes the globalSection offsets for each field, rather than just the point offset 6702 6703 . foffs - The offset into 'indices' for each field, since it is segregated by field 6704 6705 Notes: 6706 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6707 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6708 */ 6709 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) { 6710 PetscInt numFields, foff, f; 6711 6712 PetscFunctionBegin; 6713 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6714 for (f = 0; f < numFields; ++f) { 6715 PetscInt fdof, cfdof; 6716 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6717 PetscInt cind = 0, b; 6718 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6719 6720 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6721 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6722 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6723 if (!cfdof) { 6724 for (b = 0; b < fdof; ++b) { 6725 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6726 const PetscInt ind = indperm ? indperm[preind] : preind; 6727 6728 indices[ind] = foff + b; 6729 } 6730 } else { 6731 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6732 for (b = 0; b < fdof; ++b) { 6733 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6734 const PetscInt ind = indperm ? indperm[preind] : preind; 6735 6736 if ((cind < cfdof) && (b == fcdofs[cind])) { 6737 indices[ind] = -(foff + b + 1); 6738 ++cind; 6739 } else { 6740 indices[ind] = foff + b - cind; 6741 } 6742 } 6743 } 6744 foffs[f] += fdof; 6745 } 6746 PetscFunctionReturn(0); 6747 } 6748 6749 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) { 6750 Mat cMat; 6751 PetscSection aSec, cSec; 6752 IS aIS; 6753 PetscInt aStart = -1, aEnd = -1; 6754 const PetscInt *anchors; 6755 PetscInt numFields, f, p, q, newP = 0; 6756 PetscInt newNumPoints = 0, newNumIndices = 0; 6757 PetscInt *newPoints, *indices, *newIndices; 6758 PetscInt maxAnchor, maxDof; 6759 PetscInt newOffsets[32]; 6760 PetscInt *pointMatOffsets[32]; 6761 PetscInt *newPointOffsets[32]; 6762 PetscScalar *pointMat[32]; 6763 PetscScalar *newValues = NULL, *tmpValues; 6764 PetscBool anyConstrained = PETSC_FALSE; 6765 6766 PetscFunctionBegin; 6767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6768 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6769 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6770 6771 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6772 /* if there are point-to-point constraints */ 6773 if (aSec) { 6774 PetscCall(PetscArrayzero(newOffsets, 32)); 6775 PetscCall(ISGetIndices(aIS, &anchors)); 6776 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6777 /* figure out how many points are going to be in the new element matrix 6778 * (we allow double counting, because it's all just going to be summed 6779 * into the global matrix anyway) */ 6780 for (p = 0; p < 2 * numPoints; p += 2) { 6781 PetscInt b = points[p]; 6782 PetscInt bDof = 0, bSecDof; 6783 6784 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6785 if (!bSecDof) continue; 6786 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6787 if (bDof) { 6788 /* this point is constrained */ 6789 /* it is going to be replaced by its anchors */ 6790 PetscInt bOff, q; 6791 6792 anyConstrained = PETSC_TRUE; 6793 newNumPoints += bDof; 6794 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6795 for (q = 0; q < bDof; q++) { 6796 PetscInt a = anchors[bOff + q]; 6797 PetscInt aDof; 6798 6799 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6800 newNumIndices += aDof; 6801 for (f = 0; f < numFields; ++f) { 6802 PetscInt fDof; 6803 6804 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6805 newOffsets[f + 1] += fDof; 6806 } 6807 } 6808 } else { 6809 /* this point is not constrained */ 6810 newNumPoints++; 6811 newNumIndices += bSecDof; 6812 for (f = 0; f < numFields; ++f) { 6813 PetscInt fDof; 6814 6815 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6816 newOffsets[f + 1] += fDof; 6817 } 6818 } 6819 } 6820 } 6821 if (!anyConstrained) { 6822 if (outNumPoints) *outNumPoints = 0; 6823 if (outNumIndices) *outNumIndices = 0; 6824 if (outPoints) *outPoints = NULL; 6825 if (outValues) *outValues = NULL; 6826 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6827 PetscFunctionReturn(0); 6828 } 6829 6830 if (outNumPoints) *outNumPoints = newNumPoints; 6831 if (outNumIndices) *outNumIndices = newNumIndices; 6832 6833 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 6834 6835 if (!outPoints && !outValues) { 6836 if (offsets) { 6837 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 6838 } 6839 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6840 PetscFunctionReturn(0); 6841 } 6842 6843 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6844 6845 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6846 6847 /* workspaces */ 6848 if (numFields) { 6849 for (f = 0; f < numFields; f++) { 6850 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 6851 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 6852 } 6853 } else { 6854 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 6855 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 6856 } 6857 6858 /* get workspaces for the point-to-point matrices */ 6859 if (numFields) { 6860 PetscInt totalOffset, totalMatOffset; 6861 6862 for (p = 0; p < numPoints; p++) { 6863 PetscInt b = points[2 * p]; 6864 PetscInt bDof = 0, bSecDof; 6865 6866 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6867 if (!bSecDof) { 6868 for (f = 0; f < numFields; f++) { 6869 newPointOffsets[f][p + 1] = 0; 6870 pointMatOffsets[f][p + 1] = 0; 6871 } 6872 continue; 6873 } 6874 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6875 if (bDof) { 6876 for (f = 0; f < numFields; f++) { 6877 PetscInt fDof, q, bOff, allFDof = 0; 6878 6879 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6880 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6881 for (q = 0; q < bDof; q++) { 6882 PetscInt a = anchors[bOff + q]; 6883 PetscInt aFDof; 6884 6885 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6886 allFDof += aFDof; 6887 } 6888 newPointOffsets[f][p + 1] = allFDof; 6889 pointMatOffsets[f][p + 1] = fDof * allFDof; 6890 } 6891 } else { 6892 for (f = 0; f < numFields; f++) { 6893 PetscInt fDof; 6894 6895 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6896 newPointOffsets[f][p + 1] = fDof; 6897 pointMatOffsets[f][p + 1] = 0; 6898 } 6899 } 6900 } 6901 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6902 newPointOffsets[f][0] = totalOffset; 6903 pointMatOffsets[f][0] = totalMatOffset; 6904 for (p = 0; p < numPoints; p++) { 6905 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 6906 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 6907 } 6908 totalOffset = newPointOffsets[f][numPoints]; 6909 totalMatOffset = pointMatOffsets[f][numPoints]; 6910 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 6911 } 6912 } else { 6913 for (p = 0; p < numPoints; p++) { 6914 PetscInt b = points[2 * p]; 6915 PetscInt bDof = 0, bSecDof; 6916 6917 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6918 if (!bSecDof) { 6919 newPointOffsets[0][p + 1] = 0; 6920 pointMatOffsets[0][p + 1] = 0; 6921 continue; 6922 } 6923 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6924 if (bDof) { 6925 PetscInt bOff, q, allDof = 0; 6926 6927 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6928 for (q = 0; q < bDof; q++) { 6929 PetscInt a = anchors[bOff + q], aDof; 6930 6931 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6932 allDof += aDof; 6933 } 6934 newPointOffsets[0][p + 1] = allDof; 6935 pointMatOffsets[0][p + 1] = bSecDof * allDof; 6936 } else { 6937 newPointOffsets[0][p + 1] = bSecDof; 6938 pointMatOffsets[0][p + 1] = 0; 6939 } 6940 } 6941 newPointOffsets[0][0] = 0; 6942 pointMatOffsets[0][0] = 0; 6943 for (p = 0; p < numPoints; p++) { 6944 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 6945 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 6946 } 6947 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 6948 } 6949 6950 /* output arrays */ 6951 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 6952 6953 /* get the point-to-point matrices; construct newPoints */ 6954 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6955 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6956 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 6957 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 6958 if (numFields) { 6959 for (p = 0, newP = 0; p < numPoints; p++) { 6960 PetscInt b = points[2 * p]; 6961 PetscInt o = points[2 * p + 1]; 6962 PetscInt bDof = 0, bSecDof; 6963 6964 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6965 if (!bSecDof) continue; 6966 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6967 if (bDof) { 6968 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6969 6970 fStart[0] = 0; 6971 fEnd[0] = 0; 6972 for (f = 0; f < numFields; f++) { 6973 PetscInt fDof; 6974 6975 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6976 fStart[f + 1] = fStart[f] + fDof; 6977 fEnd[f + 1] = fStart[f + 1]; 6978 } 6979 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6980 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6981 6982 fAnchorStart[0] = 0; 6983 fAnchorEnd[0] = 0; 6984 for (f = 0; f < numFields; f++) { 6985 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6986 6987 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 6988 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 6989 } 6990 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6991 for (q = 0; q < bDof; q++) { 6992 PetscInt a = anchors[bOff + q], aOff; 6993 6994 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6995 newPoints[2 * (newP + q)] = a; 6996 newPoints[2 * (newP + q) + 1] = 0; 6997 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 6998 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 6999 } 7000 newP += bDof; 7001 7002 if (outValues) { 7003 /* get the point-to-point submatrix */ 7004 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])); 7005 } 7006 } else { 7007 newPoints[2 * newP] = b; 7008 newPoints[2 * newP + 1] = o; 7009 newP++; 7010 } 7011 } 7012 } else { 7013 for (p = 0; p < numPoints; p++) { 7014 PetscInt b = points[2 * p]; 7015 PetscInt o = points[2 * p + 1]; 7016 PetscInt bDof = 0, bSecDof; 7017 7018 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7019 if (!bSecDof) continue; 7020 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7021 if (bDof) { 7022 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7023 7024 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7025 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7026 7027 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7028 for (q = 0; q < bDof; q++) { 7029 PetscInt a = anchors[bOff + q], aOff; 7030 7031 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7032 7033 newPoints[2 * (newP + q)] = a; 7034 newPoints[2 * (newP + q) + 1] = 0; 7035 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7036 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7037 } 7038 newP += bDof; 7039 7040 /* get the point-to-point submatrix */ 7041 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7042 } else { 7043 newPoints[2 * newP] = b; 7044 newPoints[2 * newP + 1] = o; 7045 newP++; 7046 } 7047 } 7048 } 7049 7050 if (outValues) { 7051 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7052 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7053 /* multiply constraints on the right */ 7054 if (numFields) { 7055 for (f = 0; f < numFields; f++) { 7056 PetscInt oldOff = offsets[f]; 7057 7058 for (p = 0; p < numPoints; p++) { 7059 PetscInt cStart = newPointOffsets[f][p]; 7060 PetscInt b = points[2 * p]; 7061 PetscInt c, r, k; 7062 PetscInt dof; 7063 7064 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7065 if (!dof) continue; 7066 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7067 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7068 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7069 7070 for (r = 0; r < numIndices; r++) { 7071 for (c = 0; c < nCols; c++) { 7072 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7073 } 7074 } 7075 } else { 7076 /* copy this column as is */ 7077 for (r = 0; r < numIndices; r++) { 7078 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7079 } 7080 } 7081 oldOff += dof; 7082 } 7083 } 7084 } else { 7085 PetscInt oldOff = 0; 7086 for (p = 0; p < numPoints; p++) { 7087 PetscInt cStart = newPointOffsets[0][p]; 7088 PetscInt b = points[2 * p]; 7089 PetscInt c, r, k; 7090 PetscInt dof; 7091 7092 PetscCall(PetscSectionGetDof(section, b, &dof)); 7093 if (!dof) continue; 7094 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7095 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7096 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7097 7098 for (r = 0; r < numIndices; r++) { 7099 for (c = 0; c < nCols; c++) { 7100 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7101 } 7102 } 7103 } else { 7104 /* copy this column as is */ 7105 for (r = 0; r < numIndices; r++) { 7106 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7107 } 7108 } 7109 oldOff += dof; 7110 } 7111 } 7112 7113 if (multiplyLeft) { 7114 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7115 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7116 /* multiply constraints transpose on the left */ 7117 if (numFields) { 7118 for (f = 0; f < numFields; f++) { 7119 PetscInt oldOff = offsets[f]; 7120 7121 for (p = 0; p < numPoints; p++) { 7122 PetscInt rStart = newPointOffsets[f][p]; 7123 PetscInt b = points[2 * p]; 7124 PetscInt c, r, k; 7125 PetscInt dof; 7126 7127 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7128 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7129 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7130 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7131 7132 for (r = 0; r < nRows; r++) { 7133 for (c = 0; c < newNumIndices; c++) { 7134 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7135 } 7136 } 7137 } else { 7138 /* copy this row as is */ 7139 for (r = 0; r < dof; r++) { 7140 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7141 } 7142 } 7143 oldOff += dof; 7144 } 7145 } 7146 } else { 7147 PetscInt oldOff = 0; 7148 7149 for (p = 0; p < numPoints; p++) { 7150 PetscInt rStart = newPointOffsets[0][p]; 7151 PetscInt b = points[2 * p]; 7152 PetscInt c, r, k; 7153 PetscInt dof; 7154 7155 PetscCall(PetscSectionGetDof(section, b, &dof)); 7156 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7157 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7158 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7159 7160 for (r = 0; r < nRows; r++) { 7161 for (c = 0; c < newNumIndices; c++) { 7162 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7163 } 7164 } 7165 } else { 7166 /* copy this row as is */ 7167 for (r = 0; r < dof; r++) { 7168 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7169 } 7170 } 7171 oldOff += dof; 7172 } 7173 } 7174 7175 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7176 } else { 7177 newValues = tmpValues; 7178 } 7179 } 7180 7181 /* clean up */ 7182 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7183 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7184 7185 if (numFields) { 7186 for (f = 0; f < numFields; f++) { 7187 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7188 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7189 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7190 } 7191 } else { 7192 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7193 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7194 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7195 } 7196 PetscCall(ISRestoreIndices(aIS, &anchors)); 7197 7198 /* output */ 7199 if (outPoints) { 7200 *outPoints = newPoints; 7201 } else { 7202 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7203 } 7204 if (outValues) *outValues = newValues; 7205 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7206 PetscFunctionReturn(0); 7207 } 7208 7209 /*@C 7210 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7211 7212 Not collective 7213 7214 Input Parameters: 7215 + dm - The DM 7216 . section - The PetscSection describing the points (a local section) 7217 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7218 . point - The point defining the closure 7219 - useClPerm - Use the closure point permutation if available 7220 7221 Output Parameters: 7222 + numIndices - The number of dof indices in the closure of point with the input sections 7223 . indices - The dof indices 7224 . outOffsets - Array to write the field offsets into, or NULL 7225 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7226 7227 Notes: 7228 Must call DMPlexRestoreClosureIndices() to free allocated memory 7229 7230 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7231 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7232 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7233 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7234 indices (with the above semantics) are implied. 7235 7236 Level: advanced 7237 7238 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7239 @*/ 7240 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7241 /* Closure ordering */ 7242 PetscSection clSection; 7243 IS clPoints; 7244 const PetscInt *clp; 7245 PetscInt *points; 7246 const PetscInt *clperm = NULL; 7247 /* Dof permutation and sign flips */ 7248 const PetscInt **perms[32] = {NULL}; 7249 const PetscScalar **flips[32] = {NULL}; 7250 PetscScalar *valCopy = NULL; 7251 /* Hanging node constraints */ 7252 PetscInt *pointsC = NULL; 7253 PetscScalar *valuesC = NULL; 7254 PetscInt NclC, NiC; 7255 7256 PetscInt *idx; 7257 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7258 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7259 7260 PetscFunctionBeginHot; 7261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7262 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7263 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7264 if (numIndices) PetscValidIntPointer(numIndices, 6); 7265 if (indices) PetscValidPointer(indices, 7); 7266 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7267 if (values) PetscValidPointer(values, 9); 7268 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7269 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7270 PetscCall(PetscArrayzero(offsets, 32)); 7271 /* 1) Get points in closure */ 7272 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7273 if (useClPerm) { 7274 PetscInt depth, clsize; 7275 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7276 for (clsize = 0, p = 0; p < Ncl; p++) { 7277 PetscInt dof; 7278 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7279 clsize += dof; 7280 } 7281 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7282 } 7283 /* 2) Get number of indices on these points and field offsets from section */ 7284 for (p = 0; p < Ncl * 2; p += 2) { 7285 PetscInt dof, fdof; 7286 7287 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7288 for (f = 0; f < Nf; ++f) { 7289 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7290 offsets[f + 1] += fdof; 7291 } 7292 Ni += dof; 7293 } 7294 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7295 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7296 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7297 for (f = 0; f < PetscMax(1, Nf); ++f) { 7298 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7299 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7300 /* may need to apply sign changes to the element matrix */ 7301 if (values && flips[f]) { 7302 PetscInt foffset = offsets[f]; 7303 7304 for (p = 0; p < Ncl; ++p) { 7305 PetscInt pnt = points[2 * p], fdof; 7306 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7307 7308 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7309 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7310 if (flip) { 7311 PetscInt i, j, k; 7312 7313 if (!valCopy) { 7314 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7315 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7316 *values = valCopy; 7317 } 7318 for (i = 0; i < fdof; ++i) { 7319 PetscScalar fval = flip[i]; 7320 7321 for (k = 0; k < Ni; ++k) { 7322 valCopy[Ni * (foffset + i) + k] *= fval; 7323 valCopy[Ni * k + (foffset + i)] *= fval; 7324 } 7325 } 7326 } 7327 foffset += fdof; 7328 } 7329 } 7330 } 7331 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7332 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7333 if (NclC) { 7334 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7335 for (f = 0; f < PetscMax(1, Nf); ++f) { 7336 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7337 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7338 } 7339 for (f = 0; f < PetscMax(1, Nf); ++f) { 7340 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7341 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7342 } 7343 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7344 Ncl = NclC; 7345 Ni = NiC; 7346 points = pointsC; 7347 if (values) *values = valuesC; 7348 } 7349 /* 5) Calculate indices */ 7350 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7351 if (Nf) { 7352 PetscInt idxOff; 7353 PetscBool useFieldOffsets; 7354 7355 if (outOffsets) { 7356 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7357 } 7358 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7359 if (useFieldOffsets) { 7360 for (p = 0; p < Ncl; ++p) { 7361 const PetscInt pnt = points[p * 2]; 7362 7363 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7364 } 7365 } else { 7366 for (p = 0; p < Ncl; ++p) { 7367 const PetscInt pnt = points[p * 2]; 7368 7369 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7370 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7371 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7372 * global section. */ 7373 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7374 } 7375 } 7376 } else { 7377 PetscInt off = 0, idxOff; 7378 7379 for (p = 0; p < Ncl; ++p) { 7380 const PetscInt pnt = points[p * 2]; 7381 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7382 7383 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7384 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7385 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7386 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7387 } 7388 } 7389 /* 6) Cleanup */ 7390 for (f = 0; f < PetscMax(1, Nf); ++f) { 7391 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7392 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7393 } 7394 if (NclC) { 7395 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7396 } else { 7397 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7398 } 7399 7400 if (numIndices) *numIndices = Ni; 7401 if (indices) *indices = idx; 7402 PetscFunctionReturn(0); 7403 } 7404 7405 /*@C 7406 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7407 7408 Not collective 7409 7410 Input Parameters: 7411 + dm - The DM 7412 . section - The PetscSection describing the points (a local section) 7413 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7414 . point - The point defining the closure 7415 - useClPerm - Use the closure point permutation if available 7416 7417 Output Parameters: 7418 + numIndices - The number of dof indices in the closure of point with the input sections 7419 . indices - The dof indices 7420 . outOffsets - Array to write the field offsets into, or NULL 7421 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7422 7423 Notes: 7424 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7425 7426 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7427 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7428 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7429 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7430 indices (with the above semantics) are implied. 7431 7432 Level: advanced 7433 7434 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7435 @*/ 7436 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7437 PetscFunctionBegin; 7438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7439 PetscValidPointer(indices, 7); 7440 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7441 PetscFunctionReturn(0); 7442 } 7443 7444 /*@C 7445 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7446 7447 Not collective 7448 7449 Input Parameters: 7450 + dm - The DM 7451 . section - The section describing the layout in v, or NULL to use the default section 7452 . globalSection - The section describing the layout in v, or NULL to use the default global section 7453 . A - The matrix 7454 . point - The point in the DM 7455 . values - The array of values 7456 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7457 7458 Fortran Notes: 7459 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7460 7461 Level: intermediate 7462 7463 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7464 @*/ 7465 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7466 DM_Plex *mesh = (DM_Plex *)dm->data; 7467 PetscInt *indices; 7468 PetscInt numIndices; 7469 const PetscScalar *valuesOrig = values; 7470 PetscErrorCode ierr; 7471 7472 PetscFunctionBegin; 7473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7474 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7475 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7476 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7477 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7478 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7479 7480 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7481 7482 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7483 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7484 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7485 if (ierr) { 7486 PetscMPIInt rank; 7487 7488 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7489 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7490 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7491 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7492 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7493 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7494 } 7495 if (mesh->printFEM > 1) { 7496 PetscInt i; 7497 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7498 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7499 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7500 } 7501 7502 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7503 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7504 PetscFunctionReturn(0); 7505 } 7506 7507 /*@C 7508 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7509 7510 Not collective 7511 7512 Input Parameters: 7513 + dmRow - The DM for the row fields 7514 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7515 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7516 . dmCol - The DM for the column fields 7517 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7518 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7519 . A - The matrix 7520 . point - The point in the DMs 7521 . values - The array of values 7522 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7523 7524 Level: intermediate 7525 7526 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7527 @*/ 7528 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7529 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7530 PetscInt *indicesRow, *indicesCol; 7531 PetscInt numIndicesRow, numIndicesCol; 7532 const PetscScalar *valuesOrig = values; 7533 PetscErrorCode ierr; 7534 7535 PetscFunctionBegin; 7536 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7537 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7538 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7539 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7540 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7541 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7542 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7543 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7544 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7545 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7546 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7547 7548 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7549 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7550 7551 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7552 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7553 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7554 if (ierr) { 7555 PetscMPIInt rank; 7556 7557 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7558 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7559 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7560 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7561 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7562 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7563 } 7564 7565 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7566 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7567 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7568 PetscFunctionReturn(0); 7569 } 7570 7571 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7572 DM_Plex *mesh = (DM_Plex *)dmf->data; 7573 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7574 PetscInt *cpoints = NULL; 7575 PetscInt *findices, *cindices; 7576 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7577 PetscInt foffsets[32], coffsets[32]; 7578 DMPolytopeType ct; 7579 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7580 PetscErrorCode ierr; 7581 7582 PetscFunctionBegin; 7583 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7584 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7585 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7586 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7587 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7588 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7589 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7590 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7591 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7592 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7593 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7594 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7595 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7596 PetscCall(PetscArrayzero(foffsets, 32)); 7597 PetscCall(PetscArrayzero(coffsets, 32)); 7598 /* Column indices */ 7599 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7600 maxFPoints = numCPoints; 7601 /* Compress out points not in the section */ 7602 /* TODO: Squeeze out points with 0 dof as well */ 7603 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7604 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7605 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7606 cpoints[q * 2] = cpoints[p]; 7607 cpoints[q * 2 + 1] = cpoints[p + 1]; 7608 ++q; 7609 } 7610 } 7611 numCPoints = q; 7612 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7613 PetscInt fdof; 7614 7615 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7616 if (!dof) continue; 7617 for (f = 0; f < numFields; ++f) { 7618 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7619 coffsets[f + 1] += fdof; 7620 } 7621 numCIndices += dof; 7622 } 7623 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7624 /* Row indices */ 7625 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7626 { 7627 DMPlexTransform tr; 7628 DMPolytopeType *rct; 7629 PetscInt *rsize, *rcone, *rornt, Nt; 7630 7631 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7632 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7633 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7634 numSubcells = rsize[Nt - 1]; 7635 PetscCall(DMPlexTransformDestroy(&tr)); 7636 } 7637 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7638 for (r = 0, q = 0; r < numSubcells; ++r) { 7639 /* TODO Map from coarse to fine cells */ 7640 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7641 /* Compress out points not in the section */ 7642 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7643 for (p = 0; p < numFPoints * 2; p += 2) { 7644 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7645 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7646 if (!dof) continue; 7647 for (s = 0; s < q; ++s) 7648 if (fpoints[p] == ftotpoints[s * 2]) break; 7649 if (s < q) continue; 7650 ftotpoints[q * 2] = fpoints[p]; 7651 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7652 ++q; 7653 } 7654 } 7655 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7656 } 7657 numFPoints = q; 7658 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7659 PetscInt fdof; 7660 7661 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7662 if (!dof) continue; 7663 for (f = 0; f < numFields; ++f) { 7664 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7665 foffsets[f + 1] += fdof; 7666 } 7667 numFIndices += dof; 7668 } 7669 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7670 7671 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7672 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7673 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7674 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7675 if (numFields) { 7676 const PetscInt **permsF[32] = {NULL}; 7677 const PetscInt **permsC[32] = {NULL}; 7678 7679 for (f = 0; f < numFields; f++) { 7680 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7681 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7682 } 7683 for (p = 0; p < numFPoints; p++) { 7684 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7685 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7686 } 7687 for (p = 0; p < numCPoints; p++) { 7688 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7689 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7690 } 7691 for (f = 0; f < numFields; f++) { 7692 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7693 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7694 } 7695 } else { 7696 const PetscInt **permsF = NULL; 7697 const PetscInt **permsC = NULL; 7698 7699 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7700 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7701 for (p = 0, off = 0; p < numFPoints; p++) { 7702 const PetscInt *perm = permsF ? permsF[p] : NULL; 7703 7704 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7705 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7706 } 7707 for (p = 0, off = 0; p < numCPoints; p++) { 7708 const PetscInt *perm = permsC ? permsC[p] : NULL; 7709 7710 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7711 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7712 } 7713 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7714 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7715 } 7716 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7717 /* TODO: flips */ 7718 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7719 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7720 if (ierr) { 7721 PetscMPIInt rank; 7722 7723 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7724 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7725 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7726 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7727 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7728 } 7729 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7730 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7731 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7732 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7733 PetscFunctionReturn(0); 7734 } 7735 7736 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) { 7737 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7738 PetscInt *cpoints = NULL; 7739 PetscInt foffsets[32], coffsets[32]; 7740 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7741 DMPolytopeType ct; 7742 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7743 7744 PetscFunctionBegin; 7745 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7746 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7747 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7748 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7749 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7750 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7751 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7752 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7753 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7754 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7755 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7756 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7757 PetscCall(PetscArrayzero(foffsets, 32)); 7758 PetscCall(PetscArrayzero(coffsets, 32)); 7759 /* Column indices */ 7760 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7761 maxFPoints = numCPoints; 7762 /* Compress out points not in the section */ 7763 /* TODO: Squeeze out points with 0 dof as well */ 7764 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7765 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7766 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7767 cpoints[q * 2] = cpoints[p]; 7768 cpoints[q * 2 + 1] = cpoints[p + 1]; 7769 ++q; 7770 } 7771 } 7772 numCPoints = q; 7773 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7774 PetscInt fdof; 7775 7776 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7777 if (!dof) continue; 7778 for (f = 0; f < numFields; ++f) { 7779 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7780 coffsets[f + 1] += fdof; 7781 } 7782 numCIndices += dof; 7783 } 7784 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7785 /* Row indices */ 7786 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7787 { 7788 DMPlexTransform tr; 7789 DMPolytopeType *rct; 7790 PetscInt *rsize, *rcone, *rornt, Nt; 7791 7792 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7793 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7794 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7795 numSubcells = rsize[Nt - 1]; 7796 PetscCall(DMPlexTransformDestroy(&tr)); 7797 } 7798 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7799 for (r = 0, q = 0; r < numSubcells; ++r) { 7800 /* TODO Map from coarse to fine cells */ 7801 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7802 /* Compress out points not in the section */ 7803 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7804 for (p = 0; p < numFPoints * 2; p += 2) { 7805 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7806 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7807 if (!dof) continue; 7808 for (s = 0; s < q; ++s) 7809 if (fpoints[p] == ftotpoints[s * 2]) break; 7810 if (s < q) continue; 7811 ftotpoints[q * 2] = fpoints[p]; 7812 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7813 ++q; 7814 } 7815 } 7816 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7817 } 7818 numFPoints = q; 7819 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7820 PetscInt fdof; 7821 7822 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7823 if (!dof) continue; 7824 for (f = 0; f < numFields; ++f) { 7825 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7826 foffsets[f + 1] += fdof; 7827 } 7828 numFIndices += dof; 7829 } 7830 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7831 7832 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7833 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7834 if (numFields) { 7835 const PetscInt **permsF[32] = {NULL}; 7836 const PetscInt **permsC[32] = {NULL}; 7837 7838 for (f = 0; f < numFields; f++) { 7839 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7840 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7841 } 7842 for (p = 0; p < numFPoints; p++) { 7843 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7844 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7845 } 7846 for (p = 0; p < numCPoints; p++) { 7847 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7848 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7849 } 7850 for (f = 0; f < numFields; f++) { 7851 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7852 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7853 } 7854 } else { 7855 const PetscInt **permsF = NULL; 7856 const PetscInt **permsC = NULL; 7857 7858 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7859 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7860 for (p = 0, off = 0; p < numFPoints; p++) { 7861 const PetscInt *perm = permsF ? permsF[p] : NULL; 7862 7863 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7864 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7865 } 7866 for (p = 0, off = 0; p < numCPoints; p++) { 7867 const PetscInt *perm = permsC ? permsC[p] : NULL; 7868 7869 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7870 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7871 } 7872 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7873 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7874 } 7875 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7876 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7877 PetscFunctionReturn(0); 7878 } 7879 7880 /*@C 7881 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7882 7883 Input Parameter: 7884 . dm - The DMPlex object 7885 7886 Output Parameter: 7887 . cellHeight - The height of a cell 7888 7889 Level: developer 7890 7891 .seealso `DMPlexSetVTKCellHeight()` 7892 @*/ 7893 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) { 7894 DM_Plex *mesh = (DM_Plex *)dm->data; 7895 7896 PetscFunctionBegin; 7897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7898 PetscValidIntPointer(cellHeight, 2); 7899 *cellHeight = mesh->vtkCellHeight; 7900 PetscFunctionReturn(0); 7901 } 7902 7903 /*@C 7904 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7905 7906 Input Parameters: 7907 + dm - The DMPlex object 7908 - cellHeight - The height of a cell 7909 7910 Level: developer 7911 7912 .seealso `DMPlexGetVTKCellHeight()` 7913 @*/ 7914 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) { 7915 DM_Plex *mesh = (DM_Plex *)dm->data; 7916 7917 PetscFunctionBegin; 7918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7919 mesh->vtkCellHeight = cellHeight; 7920 PetscFunctionReturn(0); 7921 } 7922 7923 /*@ 7924 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7925 7926 Input Parameter: 7927 . dm - The DMPlex object 7928 7929 Output Parameters: 7930 + gcStart - The first ghost cell, or NULL 7931 - gcEnd - The upper bound on ghost cells, or NULL 7932 7933 Level: advanced 7934 7935 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7936 @*/ 7937 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) { 7938 DMLabel ctLabel; 7939 7940 PetscFunctionBegin; 7941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7942 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7943 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7944 // Reset label for fast lookup 7945 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 7946 PetscFunctionReturn(0); 7947 } 7948 7949 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) { 7950 PetscSection section, globalSection; 7951 PetscInt *numbers, p; 7952 7953 PetscFunctionBegin; 7954 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 7955 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 7956 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 7957 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 7958 PetscCall(PetscSectionSetUp(section)); 7959 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 7960 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 7961 for (p = pStart; p < pEnd; ++p) { 7962 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 7963 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 7964 else numbers[p - pStart] += shift; 7965 } 7966 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 7967 if (globalSize) { 7968 PetscLayout layout; 7969 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 7970 PetscCall(PetscLayoutGetSize(layout, globalSize)); 7971 PetscCall(PetscLayoutDestroy(&layout)); 7972 } 7973 PetscCall(PetscSectionDestroy(§ion)); 7974 PetscCall(PetscSectionDestroy(&globalSection)); 7975 PetscFunctionReturn(0); 7976 } 7977 7978 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) { 7979 PetscInt cellHeight, cStart, cEnd; 7980 7981 PetscFunctionBegin; 7982 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 7983 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 7984 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 7985 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 7986 PetscFunctionReturn(0); 7987 } 7988 7989 /*@ 7990 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 7991 7992 Input Parameter: 7993 . dm - The DMPlex object 7994 7995 Output Parameter: 7996 . globalCellNumbers - Global cell numbers for all cells on this process 7997 7998 Level: developer 7999 8000 .seealso `DMPlexGetVertexNumbering()` 8001 @*/ 8002 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) { 8003 DM_Plex *mesh = (DM_Plex *)dm->data; 8004 8005 PetscFunctionBegin; 8006 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8007 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8008 *globalCellNumbers = mesh->globalCellNumbers; 8009 PetscFunctionReturn(0); 8010 } 8011 8012 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) { 8013 PetscInt vStart, vEnd; 8014 8015 PetscFunctionBegin; 8016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8017 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8018 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8019 PetscFunctionReturn(0); 8020 } 8021 8022 /*@ 8023 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8024 8025 Input Parameter: 8026 . dm - The DMPlex object 8027 8028 Output Parameter: 8029 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8030 8031 Level: developer 8032 8033 .seealso `DMPlexGetCellNumbering()` 8034 @*/ 8035 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) { 8036 DM_Plex *mesh = (DM_Plex *)dm->data; 8037 8038 PetscFunctionBegin; 8039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8040 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8041 *globalVertexNumbers = mesh->globalVertexNumbers; 8042 PetscFunctionReturn(0); 8043 } 8044 8045 /*@ 8046 DMPlexCreatePointNumbering - Create a global numbering for all points. 8047 8048 Collective on dm 8049 8050 Input Parameter: 8051 . dm - The DMPlex object 8052 8053 Output Parameter: 8054 . globalPointNumbers - Global numbers for all points on this process 8055 8056 Notes: 8057 8058 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8059 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8060 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8061 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8062 8063 The partitioned mesh is 8064 ``` 8065 (2)--0--(3)--1--(4) (1)--0--(2) 8066 ``` 8067 and its global numbering is 8068 ``` 8069 (3)--0--(4)--1--(5)--2--(6) 8070 ``` 8071 Then the global numbering is provided as 8072 ``` 8073 [0] Number of indices in set 5 8074 [0] 0 0 8075 [0] 1 1 8076 [0] 2 3 8077 [0] 3 4 8078 [0] 4 -6 8079 [1] Number of indices in set 3 8080 [1] 0 2 8081 [1] 1 5 8082 [1] 2 6 8083 ``` 8084 8085 Level: developer 8086 8087 .seealso `DMPlexGetCellNumbering()` 8088 @*/ 8089 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) { 8090 IS nums[4]; 8091 PetscInt depths[4], gdepths[4], starts[4]; 8092 PetscInt depth, d, shift = 0; 8093 8094 PetscFunctionBegin; 8095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8096 PetscCall(DMPlexGetDepth(dm, &depth)); 8097 /* For unstratified meshes use dim instead of depth */ 8098 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8099 for (d = 0; d <= depth; ++d) { 8100 PetscInt end; 8101 8102 depths[d] = depth - d; 8103 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8104 if (!(starts[d] - end)) starts[d] = depths[d] = -1; 8105 } 8106 PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8107 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8108 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]); 8109 for (d = 0; d <= depth; ++d) { 8110 PetscInt pStart, pEnd, gsize; 8111 8112 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8113 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8114 shift += gsize; 8115 } 8116 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8117 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8118 PetscFunctionReturn(0); 8119 } 8120 8121 /*@ 8122 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8123 8124 Input Parameter: 8125 . dm - The DMPlex object 8126 8127 Output Parameter: 8128 . ranks - The rank field 8129 8130 Options Database Keys: 8131 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8132 8133 Level: intermediate 8134 8135 .seealso: `DMView()` 8136 @*/ 8137 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) { 8138 DM rdm; 8139 PetscFE fe; 8140 PetscScalar *r; 8141 PetscMPIInt rank; 8142 DMPolytopeType ct; 8143 PetscInt dim, cStart, cEnd, c; 8144 PetscBool simplex; 8145 8146 PetscFunctionBeginUser; 8147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8148 PetscValidPointer(ranks, 2); 8149 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8150 PetscCall(DMClone(dm, &rdm)); 8151 PetscCall(DMGetDimension(rdm, &dim)); 8152 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8153 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8154 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8155 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8156 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8157 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8158 PetscCall(PetscFEDestroy(&fe)); 8159 PetscCall(DMCreateDS(rdm)); 8160 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8161 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8162 PetscCall(VecGetArray(*ranks, &r)); 8163 for (c = cStart; c < cEnd; ++c) { 8164 PetscScalar *lr; 8165 8166 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8167 if (lr) *lr = rank; 8168 } 8169 PetscCall(VecRestoreArray(*ranks, &r)); 8170 PetscCall(DMDestroy(&rdm)); 8171 PetscFunctionReturn(0); 8172 } 8173 8174 /*@ 8175 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8176 8177 Input Parameters: 8178 + dm - The DMPlex 8179 - label - The DMLabel 8180 8181 Output Parameter: 8182 . val - The label value field 8183 8184 Options Database Keys: 8185 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8186 8187 Level: intermediate 8188 8189 .seealso: `DMView()` 8190 @*/ 8191 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) { 8192 DM rdm; 8193 PetscFE fe; 8194 PetscScalar *v; 8195 PetscInt dim, cStart, cEnd, c; 8196 8197 PetscFunctionBeginUser; 8198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8199 PetscValidPointer(label, 2); 8200 PetscValidPointer(val, 3); 8201 PetscCall(DMClone(dm, &rdm)); 8202 PetscCall(DMGetDimension(rdm, &dim)); 8203 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8204 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8205 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8206 PetscCall(PetscFEDestroy(&fe)); 8207 PetscCall(DMCreateDS(rdm)); 8208 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8209 PetscCall(DMCreateGlobalVector(rdm, val)); 8210 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8211 PetscCall(VecGetArray(*val, &v)); 8212 for (c = cStart; c < cEnd; ++c) { 8213 PetscScalar *lv; 8214 PetscInt cval; 8215 8216 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8217 PetscCall(DMLabelGetValue(label, c, &cval)); 8218 *lv = cval; 8219 } 8220 PetscCall(VecRestoreArray(*val, &v)); 8221 PetscCall(DMDestroy(&rdm)); 8222 PetscFunctionReturn(0); 8223 } 8224 8225 /*@ 8226 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8227 8228 Input Parameter: 8229 . dm - The DMPlex object 8230 8231 Notes: 8232 This is a useful diagnostic when creating meshes programmatically. 8233 8234 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8235 8236 Level: developer 8237 8238 .seealso: `DMCreate()`, `DMSetFromOptions()` 8239 @*/ 8240 PetscErrorCode DMPlexCheckSymmetry(DM dm) { 8241 PetscSection coneSection, supportSection; 8242 const PetscInt *cone, *support; 8243 PetscInt coneSize, c, supportSize, s; 8244 PetscInt pStart, pEnd, p, pp, csize, ssize; 8245 PetscBool storagecheck = PETSC_TRUE; 8246 8247 PetscFunctionBegin; 8248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8249 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8250 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8251 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8252 /* Check that point p is found in the support of its cone points, and vice versa */ 8253 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8254 for (p = pStart; p < pEnd; ++p) { 8255 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8256 PetscCall(DMPlexGetCone(dm, p, &cone)); 8257 for (c = 0; c < coneSize; ++c) { 8258 PetscBool dup = PETSC_FALSE; 8259 PetscInt d; 8260 for (d = c - 1; d >= 0; --d) { 8261 if (cone[c] == cone[d]) { 8262 dup = PETSC_TRUE; 8263 break; 8264 } 8265 } 8266 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8267 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8268 for (s = 0; s < supportSize; ++s) { 8269 if (support[s] == p) break; 8270 } 8271 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8272 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8273 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8274 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8275 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8276 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8277 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8278 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]); 8279 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8280 } 8281 } 8282 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8283 if (p != pp) { 8284 storagecheck = PETSC_FALSE; 8285 continue; 8286 } 8287 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8288 PetscCall(DMPlexGetSupport(dm, p, &support)); 8289 for (s = 0; s < supportSize; ++s) { 8290 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8291 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8292 for (c = 0; c < coneSize; ++c) { 8293 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8294 if (cone[c] != pp) { 8295 c = 0; 8296 break; 8297 } 8298 if (cone[c] == p) break; 8299 } 8300 if (c >= coneSize) { 8301 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8302 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8303 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8304 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8305 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8306 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8307 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8308 } 8309 } 8310 } 8311 if (storagecheck) { 8312 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8313 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8314 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8315 } 8316 PetscFunctionReturn(0); 8317 } 8318 8319 /* 8320 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. 8321 */ 8322 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) { 8323 DMPolytopeType cct; 8324 PetscInt ptpoints[4]; 8325 const PetscInt *cone, *ccone, *ptcone; 8326 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8327 8328 PetscFunctionBegin; 8329 *unsplit = 0; 8330 switch (ct) { 8331 case DM_POLYTOPE_POINT_PRISM_TENSOR: ptpoints[npt++] = c; break; 8332 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8333 PetscCall(DMPlexGetCone(dm, c, &cone)); 8334 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8335 for (cp = 0; cp < coneSize; ++cp) { 8336 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8337 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8338 } 8339 break; 8340 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8341 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8342 PetscCall(DMPlexGetCone(dm, c, &cone)); 8343 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8344 for (cp = 0; cp < coneSize; ++cp) { 8345 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8346 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8347 for (ccp = 0; ccp < cconeSize; ++ccp) { 8348 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8349 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8350 PetscInt p; 8351 for (p = 0; p < npt; ++p) 8352 if (ptpoints[p] == ccone[ccp]) break; 8353 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8354 } 8355 } 8356 } 8357 break; 8358 default: break; 8359 } 8360 for (pt = 0; pt < npt; ++pt) { 8361 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8362 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8363 } 8364 PetscFunctionReturn(0); 8365 } 8366 8367 /*@ 8368 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8369 8370 Input Parameters: 8371 + dm - The DMPlex object 8372 - cellHeight - Normally 0 8373 8374 Notes: 8375 This is a useful diagnostic when creating meshes programmatically. 8376 Currently applicable only to homogeneous simplex or tensor meshes. 8377 8378 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8379 8380 Level: developer 8381 8382 .seealso: `DMCreate()`, `DMSetFromOptions()` 8383 @*/ 8384 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) { 8385 DMPlexInterpolatedFlag interp; 8386 DMPolytopeType ct; 8387 PetscInt vStart, vEnd, cStart, cEnd, c; 8388 8389 PetscFunctionBegin; 8390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8391 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8392 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8393 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8394 for (c = cStart; c < cEnd; ++c) { 8395 PetscInt *closure = NULL; 8396 PetscInt coneSize, closureSize, cl, Nv = 0; 8397 8398 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8399 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8400 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8401 if (interp == DMPLEX_INTERPOLATED_FULL) { 8402 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8403 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)); 8404 } 8405 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8406 for (cl = 0; cl < closureSize * 2; cl += 2) { 8407 const PetscInt p = closure[cl]; 8408 if ((p >= vStart) && (p < vEnd)) ++Nv; 8409 } 8410 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8411 /* Special Case: Tensor faces with identified vertices */ 8412 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8413 PetscInt unsplit; 8414 8415 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8416 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8417 } 8418 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)); 8419 } 8420 PetscFunctionReturn(0); 8421 } 8422 8423 /*@ 8424 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8425 8426 Collective 8427 8428 Input Parameters: 8429 + dm - The DMPlex object 8430 - cellHeight - Normally 0 8431 8432 Notes: 8433 This is a useful diagnostic when creating meshes programmatically. 8434 This routine is only relevant for meshes that are fully interpolated across all ranks. 8435 It will error out if a partially interpolated mesh is given on some rank. 8436 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8437 8438 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8439 8440 Level: developer 8441 8442 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8443 @*/ 8444 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) { 8445 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8446 DMPlexInterpolatedFlag interpEnum; 8447 8448 PetscFunctionBegin; 8449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8450 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8451 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8452 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8453 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8454 PetscFunctionReturn(0); 8455 } 8456 8457 PetscCall(DMGetDimension(dm, &dim)); 8458 PetscCall(DMPlexGetDepth(dm, &depth)); 8459 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8460 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8461 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8462 for (c = cStart; c < cEnd; ++c) { 8463 const PetscInt *cone, *ornt, *faceSizes, *faces; 8464 const DMPolytopeType *faceTypes; 8465 DMPolytopeType ct; 8466 PetscInt numFaces, coneSize, f; 8467 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8468 8469 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8470 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8471 if (unsplit) continue; 8472 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8473 PetscCall(DMPlexGetCone(dm, c, &cone)); 8474 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8475 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8476 for (cl = 0; cl < closureSize * 2; cl += 2) { 8477 const PetscInt p = closure[cl]; 8478 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8479 } 8480 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8481 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); 8482 for (f = 0; f < numFaces; ++f) { 8483 DMPolytopeType fct; 8484 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8485 8486 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8487 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8488 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8489 const PetscInt p = fclosure[cl]; 8490 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8491 } 8492 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]); 8493 for (v = 0; v < fnumCorners; ++v) { 8494 if (fclosure[v] != faces[fOff + v]) { 8495 PetscInt v1; 8496 8497 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8498 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8499 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8500 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8501 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8502 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]); 8503 } 8504 } 8505 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8506 fOff += faceSizes[f]; 8507 } 8508 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8509 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8510 } 8511 } 8512 PetscFunctionReturn(0); 8513 } 8514 8515 /*@ 8516 DMPlexCheckGeometry - Check the geometry of mesh cells 8517 8518 Input Parameter: 8519 . dm - The DMPlex object 8520 8521 Notes: 8522 This is a useful diagnostic when creating meshes programmatically. 8523 8524 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8525 8526 Level: developer 8527 8528 .seealso: `DMCreate()`, `DMSetFromOptions()` 8529 @*/ 8530 PetscErrorCode DMPlexCheckGeometry(DM dm) { 8531 Vec coordinates; 8532 PetscReal detJ, J[9], refVol = 1.0; 8533 PetscReal vol; 8534 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8535 8536 PetscFunctionBegin; 8537 PetscCall(DMGetDimension(dm, &dim)); 8538 PetscCall(DMGetCoordinateDim(dm, &dE)); 8539 if (dim != dE) PetscFunctionReturn(0); 8540 PetscCall(DMPlexGetDepth(dm, &depth)); 8541 for (d = 0; d < dim; ++d) refVol *= 2.0; 8542 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8543 /* Make sure local coordinates are created, because that step is collective */ 8544 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8545 for (c = cStart; c < cEnd; ++c) { 8546 DMPolytopeType ct; 8547 PetscInt unsplit; 8548 PetscBool ignoreZeroVol = PETSC_FALSE; 8549 8550 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8551 switch (ct) { 8552 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8553 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8554 case DM_POLYTOPE_QUAD_PRISM_TENSOR: ignoreZeroVol = PETSC_TRUE; break; 8555 default: break; 8556 } 8557 switch (ct) { 8558 case DM_POLYTOPE_TRI_PRISM: 8559 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8560 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8561 case DM_POLYTOPE_PYRAMID: continue; 8562 default: break; 8563 } 8564 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8565 if (unsplit) continue; 8566 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8567 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); 8568 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8569 /* This should work with periodicity since DG coordinates should be used */ 8570 if (depth > 1) { 8571 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8572 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); 8573 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8574 } 8575 } 8576 PetscFunctionReturn(0); 8577 } 8578 8579 /*@ 8580 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8581 8582 Collective 8583 8584 Input Parameters: 8585 + dm - The DMPlex object 8586 - pointSF - The Point SF, or NULL for Point SF attached to DM 8587 8588 Notes: 8589 This is mainly intended for debugging/testing purposes. 8590 8591 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8592 8593 Level: developer 8594 8595 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8596 @*/ 8597 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) { 8598 PetscInt l, nleaves, nroots, overlap; 8599 const PetscInt *locals; 8600 const PetscSFNode *remotes; 8601 PetscBool distributed; 8602 MPI_Comm comm; 8603 PetscMPIInt rank; 8604 8605 PetscFunctionBegin; 8606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8607 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8608 else pointSF = dm->sf; 8609 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8610 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8611 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8612 { 8613 PetscMPIInt mpiFlag; 8614 8615 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8616 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8617 } 8618 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8619 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8620 if (!distributed) { 8621 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); 8622 PetscFunctionReturn(0); 8623 } 8624 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); 8625 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8626 8627 /* Check SF graph is compatible with DMPlex chart */ 8628 { 8629 PetscInt pStart, pEnd, maxLeaf; 8630 8631 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8632 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8633 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8634 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8635 } 8636 8637 /* Check Point SF has no local points referenced */ 8638 for (l = 0; l < nleaves; l++) { 8639 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); 8640 } 8641 8642 /* Check there are no cells in interface */ 8643 if (!overlap) { 8644 PetscInt cellHeight, cStart, cEnd; 8645 8646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8647 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8648 for (l = 0; l < nleaves; ++l) { 8649 const PetscInt point = locals ? locals[l] : l; 8650 8651 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8652 } 8653 } 8654 8655 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8656 { 8657 const PetscInt *rootdegree; 8658 8659 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8660 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8661 for (l = 0; l < nleaves; ++l) { 8662 const PetscInt point = locals ? locals[l] : l; 8663 const PetscInt *cone; 8664 PetscInt coneSize, c, idx; 8665 8666 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8667 PetscCall(DMPlexGetCone(dm, point, &cone)); 8668 for (c = 0; c < coneSize; ++c) { 8669 if (!rootdegree[cone[c]]) { 8670 if (locals) { 8671 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8672 } else { 8673 idx = (cone[c] < nleaves) ? cone[c] : -1; 8674 } 8675 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8676 } 8677 } 8678 } 8679 } 8680 PetscFunctionReturn(0); 8681 } 8682 8683 /*@ 8684 DMPlexCheck - Perform various checks of Plex sanity 8685 8686 Input Parameter: 8687 . dm - The DMPlex object 8688 8689 Notes: 8690 This is a useful diagnostic when creating meshes programmatically. 8691 8692 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8693 8694 Currently does not include DMPlexCheckCellShape(). 8695 8696 Level: developer 8697 8698 .seealso: DMCreate(), DMSetFromOptions() 8699 @*/ 8700 PetscErrorCode DMPlexCheck(DM dm) { 8701 PetscInt cellHeight; 8702 8703 PetscFunctionBegin; 8704 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8705 PetscCall(DMPlexCheckSymmetry(dm)); 8706 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8707 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8708 PetscCall(DMPlexCheckGeometry(dm)); 8709 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8710 PetscCall(DMPlexCheckInterfaceCones(dm)); 8711 PetscFunctionReturn(0); 8712 } 8713 8714 typedef struct cell_stats { 8715 PetscReal min, max, sum, squaresum; 8716 PetscInt count; 8717 } cell_stats_t; 8718 8719 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) { 8720 PetscInt i, N = *len; 8721 8722 for (i = 0; i < N; i++) { 8723 cell_stats_t *A = (cell_stats_t *)a; 8724 cell_stats_t *B = (cell_stats_t *)b; 8725 8726 B->min = PetscMin(A->min, B->min); 8727 B->max = PetscMax(A->max, B->max); 8728 B->sum += A->sum; 8729 B->squaresum += A->squaresum; 8730 B->count += A->count; 8731 } 8732 } 8733 8734 /*@ 8735 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8736 8737 Collective on dm 8738 8739 Input Parameters: 8740 + dm - The DMPlex object 8741 . output - If true, statistics will be displayed on stdout 8742 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8743 8744 Notes: 8745 This is mainly intended for debugging/testing purposes. 8746 8747 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8748 8749 Level: developer 8750 8751 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8752 @*/ 8753 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) { 8754 DM dmCoarse; 8755 cell_stats_t stats, globalStats; 8756 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8757 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8758 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8759 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8760 PetscMPIInt rank, size; 8761 8762 PetscFunctionBegin; 8763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8764 stats.min = PETSC_MAX_REAL; 8765 stats.max = PETSC_MIN_REAL; 8766 stats.sum = stats.squaresum = 0.; 8767 stats.count = 0; 8768 8769 PetscCallMPI(MPI_Comm_size(comm, &size)); 8770 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8771 PetscCall(DMGetCoordinateDim(dm, &cdim)); 8772 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8773 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 8774 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8775 for (c = cStart; c < cEnd; c++) { 8776 PetscInt i; 8777 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8778 8779 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 8780 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8781 for (i = 0; i < PetscSqr(cdim); ++i) { 8782 frobJ += J[i] * J[i]; 8783 frobInvJ += invJ[i] * invJ[i]; 8784 } 8785 cond2 = frobJ * frobInvJ; 8786 cond = PetscSqrtReal(cond2); 8787 8788 stats.min = PetscMin(stats.min, cond); 8789 stats.max = PetscMax(stats.max, cond); 8790 stats.sum += cond; 8791 stats.squaresum += cond2; 8792 stats.count++; 8793 if (output && cond > limit) { 8794 PetscSection coordSection; 8795 Vec coordsLocal; 8796 PetscScalar *coords = NULL; 8797 PetscInt Nv, d, clSize, cl, *closure = NULL; 8798 8799 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8800 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8801 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8802 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 8803 for (i = 0; i < Nv / cdim; ++i) { 8804 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8805 for (d = 0; d < cdim; ++d) { 8806 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8807 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 8808 } 8809 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8810 } 8811 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8812 for (cl = 0; cl < clSize * 2; cl += 2) { 8813 const PetscInt edge = closure[cl]; 8814 8815 if ((edge >= eStart) && (edge < eEnd)) { 8816 PetscReal len; 8817 8818 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8819 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 8820 } 8821 } 8822 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8823 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8824 } 8825 } 8826 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8827 8828 if (size > 1) { 8829 PetscMPIInt blockLengths[2] = {4, 1}; 8830 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 8831 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 8832 MPI_Op statReduce; 8833 8834 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 8835 PetscCallMPI(MPI_Type_commit(&statType)); 8836 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8837 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 8838 PetscCallMPI(MPI_Op_free(&statReduce)); 8839 PetscCallMPI(MPI_Type_free(&statType)); 8840 } else { 8841 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 8842 } 8843 if (rank == 0) { 8844 count = globalStats.count; 8845 min = globalStats.min; 8846 max = globalStats.max; 8847 mean = globalStats.sum / globalStats.count; 8848 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 8849 } 8850 8851 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)); 8852 PetscCall(PetscFree2(J, invJ)); 8853 8854 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 8855 if (dmCoarse) { 8856 PetscBool isplex; 8857 8858 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 8859 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 8860 } 8861 PetscFunctionReturn(0); 8862 } 8863 8864 /*@ 8865 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8866 orthogonal quality below given tolerance. 8867 8868 Collective on dm 8869 8870 Input Parameters: 8871 + dm - The DMPlex object 8872 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8873 - atol - [0, 1] Absolute tolerance for tagging cells. 8874 8875 Output Parameters: 8876 + OrthQual - Vec containing orthogonal quality per cell 8877 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8878 8879 Options Database Keys: 8880 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8881 supported. 8882 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8883 8884 Notes: 8885 Orthogonal quality is given by the following formula: 8886 8887 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8888 8889 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 8890 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8891 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8892 calculating the cosine of the angle between these vectors. 8893 8894 Orthogonal quality ranges from 1 (best) to 0 (worst). 8895 8896 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8897 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8898 8899 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8900 8901 Level: intermediate 8902 8903 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8904 @*/ 8905 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) { 8906 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8907 PetscInt *idx; 8908 PetscScalar *oqVals; 8909 const PetscScalar *cellGeomArr, *faceGeomArr; 8910 PetscReal *ci, *fi, *Ai; 8911 MPI_Comm comm; 8912 Vec cellgeom, facegeom; 8913 DM dmFace, dmCell; 8914 IS glob; 8915 ISLocalToGlobalMapping ltog; 8916 PetscViewer vwr; 8917 8918 PetscFunctionBegin; 8919 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8920 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 8921 PetscValidPointer(OrthQual, 4); 8922 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 8923 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8924 PetscCall(DMGetDimension(dm, &nc)); 8925 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8926 { 8927 DMPlexInterpolatedFlag interpFlag; 8928 8929 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8930 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8931 PetscMPIInt rank; 8932 8933 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8934 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8935 } 8936 } 8937 if (OrthQualLabel) { 8938 PetscValidPointer(OrthQualLabel, 5); 8939 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8940 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8941 } else { 8942 *OrthQualLabel = NULL; 8943 } 8944 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8945 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8946 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8947 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8948 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8949 PetscCall(VecCreate(comm, OrthQual)); 8950 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8951 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 8952 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8953 PetscCall(VecSetUp(*OrthQual)); 8954 PetscCall(ISDestroy(&glob)); 8955 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8956 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8957 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8958 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8959 PetscCall(VecGetDM(cellgeom, &dmCell)); 8960 PetscCall(VecGetDM(facegeom, &dmFace)); 8961 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8962 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 8963 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8964 PetscInt cellarr[2], *adj = NULL; 8965 PetscScalar *cArr, *fArr; 8966 PetscReal minvalc = 1.0, minvalf = 1.0; 8967 PetscFVCellGeom *cg; 8968 8969 idx[cellIter] = cell - cStart; 8970 cellarr[0] = cell; 8971 /* Make indexing into cellGeom easier */ 8972 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8973 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8974 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8975 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8976 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 8977 PetscInt i; 8978 const PetscInt neigh = adj[cellneigh]; 8979 PetscReal normci = 0, normfi = 0, normai = 0; 8980 PetscFVCellGeom *cgneigh; 8981 PetscFVFaceGeom *fg; 8982 8983 /* Don't count ourselves in the neighbor list */ 8984 if (neigh == cell) continue; 8985 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 8986 cellarr[1] = neigh; 8987 { 8988 PetscInt numcovpts; 8989 const PetscInt *covpts; 8990 8991 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8992 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 8993 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8994 } 8995 8996 /* Compute c_i, f_i and their norms */ 8997 for (i = 0; i < nc; i++) { 8998 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 8999 fi[i] = fg->centroid[i] - cg->centroid[i]; 9000 Ai[i] = fg->normal[i]; 9001 normci += PetscPowReal(ci[i], 2); 9002 normfi += PetscPowReal(fi[i], 2); 9003 normai += PetscPowReal(Ai[i], 2); 9004 } 9005 normci = PetscSqrtReal(normci); 9006 normfi = PetscSqrtReal(normfi); 9007 normai = PetscSqrtReal(normai); 9008 9009 /* Normalize and compute for each face-cell-normal pair */ 9010 for (i = 0; i < nc; i++) { 9011 ci[i] = ci[i] / normci; 9012 fi[i] = fi[i] / normfi; 9013 Ai[i] = Ai[i] / normai; 9014 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9015 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9016 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9017 } 9018 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9019 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9020 } 9021 PetscCall(PetscFree(adj)); 9022 PetscCall(PetscFree2(cArr, fArr)); 9023 /* Defer to cell if they're equal */ 9024 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9025 if (OrthQualLabel) { 9026 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9027 } 9028 } 9029 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9030 PetscCall(VecAssemblyBegin(*OrthQual)); 9031 PetscCall(VecAssemblyEnd(*OrthQual)); 9032 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9033 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9034 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9035 if (OrthQualLabel) { 9036 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9037 } 9038 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9039 PetscCall(PetscViewerDestroy(&vwr)); 9040 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9041 PetscFunctionReturn(0); 9042 } 9043 9044 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9045 * interpolator construction */ 9046 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) { 9047 PetscSection section, newSection, gsection; 9048 PetscSF sf; 9049 PetscBool hasConstraints, ghasConstraints; 9050 9051 PetscFunctionBegin; 9052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9053 PetscValidPointer(odm, 2); 9054 PetscCall(DMGetLocalSection(dm, §ion)); 9055 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9056 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9057 if (!ghasConstraints) { 9058 PetscCall(PetscObjectReference((PetscObject)dm)); 9059 *odm = dm; 9060 PetscFunctionReturn(0); 9061 } 9062 PetscCall(DMClone(dm, odm)); 9063 PetscCall(DMCopyFields(dm, *odm)); 9064 PetscCall(DMGetLocalSection(*odm, &newSection)); 9065 PetscCall(DMGetPointSF(*odm, &sf)); 9066 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9067 PetscCall(DMSetGlobalSection(*odm, gsection)); 9068 PetscCall(PetscSectionDestroy(&gsection)); 9069 PetscFunctionReturn(0); 9070 } 9071 9072 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) { 9073 DM dmco, dmfo; 9074 Mat interpo; 9075 Vec rscale; 9076 Vec cglobalo, clocal; 9077 Vec fglobal, fglobalo, flocal; 9078 PetscBool regular; 9079 9080 PetscFunctionBegin; 9081 PetscCall(DMGetFullDM(dmc, &dmco)); 9082 PetscCall(DMGetFullDM(dmf, &dmfo)); 9083 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9084 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9085 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9086 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9087 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9088 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9089 PetscCall(VecSet(cglobalo, 0.)); 9090 PetscCall(VecSet(clocal, 0.)); 9091 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9092 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9093 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9094 PetscCall(VecSet(fglobal, 0.)); 9095 PetscCall(VecSet(fglobalo, 0.)); 9096 PetscCall(VecSet(flocal, 0.)); 9097 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9098 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9099 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9100 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9101 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9102 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9103 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9104 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9105 *shift = fglobal; 9106 PetscCall(VecDestroy(&flocal)); 9107 PetscCall(VecDestroy(&fglobalo)); 9108 PetscCall(VecDestroy(&clocal)); 9109 PetscCall(VecDestroy(&cglobalo)); 9110 PetscCall(VecDestroy(&rscale)); 9111 PetscCall(MatDestroy(&interpo)); 9112 PetscCall(DMDestroy(&dmfo)); 9113 PetscCall(DMDestroy(&dmco)); 9114 PetscFunctionReturn(0); 9115 } 9116 9117 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) { 9118 PetscObject shifto; 9119 Vec shift; 9120 9121 PetscFunctionBegin; 9122 if (!interp) { 9123 Vec rscale; 9124 9125 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9126 PetscCall(VecDestroy(&rscale)); 9127 } else { 9128 PetscCall(PetscObjectReference((PetscObject)interp)); 9129 } 9130 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9131 if (!shifto) { 9132 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9133 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9134 shifto = (PetscObject)shift; 9135 PetscCall(VecDestroy(&shift)); 9136 } 9137 shift = (Vec)shifto; 9138 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9139 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9140 PetscCall(MatDestroy(&interp)); 9141 PetscFunctionReturn(0); 9142 } 9143 9144 /* Pointwise interpolation 9145 Just code FEM for now 9146 u^f = I u^c 9147 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9148 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9149 I_{ij} = psi^f_i phi^c_j 9150 */ 9151 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) { 9152 PetscSection gsc, gsf; 9153 PetscInt m, n; 9154 void *ctx; 9155 DM cdm; 9156 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9157 9158 PetscFunctionBegin; 9159 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9160 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9161 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9162 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9163 9164 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9165 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9166 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9167 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9168 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9169 9170 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9171 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9172 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9173 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9174 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9175 if (scaling) { 9176 /* Use naive scaling */ 9177 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9178 } 9179 PetscFunctionReturn(0); 9180 } 9181 9182 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) { 9183 VecScatter ctx; 9184 9185 PetscFunctionBegin; 9186 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9187 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9188 PetscCall(VecScatterDestroy(&ctx)); 9189 PetscFunctionReturn(0); 9190 } 9191 9192 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[]) { 9193 const PetscInt Nc = uOff[1] - uOff[0]; 9194 PetscInt c; 9195 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9196 } 9197 9198 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) { 9199 DM dmc; 9200 PetscDS ds; 9201 Vec ones, locmass; 9202 IS cellIS; 9203 PetscFormKey key; 9204 PetscInt depth; 9205 9206 PetscFunctionBegin; 9207 PetscCall(DMClone(dm, &dmc)); 9208 PetscCall(DMCopyDisc(dm, dmc)); 9209 PetscCall(DMGetDS(dmc, &ds)); 9210 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9211 PetscCall(DMCreateGlobalVector(dmc, mass)); 9212 PetscCall(DMGetLocalVector(dmc, &ones)); 9213 PetscCall(DMGetLocalVector(dmc, &locmass)); 9214 PetscCall(DMPlexGetDepth(dmc, &depth)); 9215 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9216 PetscCall(VecSet(locmass, 0.0)); 9217 PetscCall(VecSet(ones, 1.0)); 9218 key.label = NULL; 9219 key.value = 0; 9220 key.field = 0; 9221 key.part = 0; 9222 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9223 PetscCall(ISDestroy(&cellIS)); 9224 PetscCall(VecSet(*mass, 0.0)); 9225 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9226 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9227 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9228 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9229 PetscCall(DMDestroy(&dmc)); 9230 PetscFunctionReturn(0); 9231 } 9232 9233 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) { 9234 PetscSection gsc, gsf; 9235 PetscInt m, n; 9236 void *ctx; 9237 DM cdm; 9238 PetscBool regular; 9239 9240 PetscFunctionBegin; 9241 if (dmFine == dmCoarse) { 9242 DM dmc; 9243 PetscDS ds; 9244 PetscWeakForm wf; 9245 Vec u; 9246 IS cellIS; 9247 PetscFormKey key; 9248 PetscInt depth; 9249 9250 PetscCall(DMClone(dmFine, &dmc)); 9251 PetscCall(DMCopyDisc(dmFine, dmc)); 9252 PetscCall(DMGetDS(dmc, &ds)); 9253 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9254 PetscCall(PetscWeakFormClear(wf)); 9255 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9256 PetscCall(DMCreateMatrix(dmc, mass)); 9257 PetscCall(DMGetLocalVector(dmc, &u)); 9258 PetscCall(DMPlexGetDepth(dmc, &depth)); 9259 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9260 PetscCall(MatZeroEntries(*mass)); 9261 key.label = NULL; 9262 key.value = 0; 9263 key.field = 0; 9264 key.part = 0; 9265 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9266 PetscCall(ISDestroy(&cellIS)); 9267 PetscCall(DMRestoreLocalVector(dmc, &u)); 9268 PetscCall(DMDestroy(&dmc)); 9269 } else { 9270 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9271 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9272 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9273 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9274 9275 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9276 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9277 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9278 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9279 9280 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9281 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9282 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9283 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9284 } 9285 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9286 PetscFunctionReturn(0); 9287 } 9288 9289 /*@ 9290 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9291 9292 Input Parameter: 9293 . dm - The DMPlex object 9294 9295 Output Parameter: 9296 . regular - The flag 9297 9298 Level: intermediate 9299 9300 .seealso: `DMPlexSetRegularRefinement()` 9301 @*/ 9302 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) { 9303 PetscFunctionBegin; 9304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9305 PetscValidBoolPointer(regular, 2); 9306 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9307 PetscFunctionReturn(0); 9308 } 9309 9310 /*@ 9311 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9312 9313 Input Parameters: 9314 + dm - The DMPlex object 9315 - regular - The flag 9316 9317 Level: intermediate 9318 9319 .seealso: `DMPlexGetRegularRefinement()` 9320 @*/ 9321 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) { 9322 PetscFunctionBegin; 9323 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9324 ((DM_Plex *)dm->data)->regularRefinement = regular; 9325 PetscFunctionReturn(0); 9326 } 9327 9328 /* anchors */ 9329 /*@ 9330 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9331 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9332 9333 not collective 9334 9335 Input Parameter: 9336 . dm - The DMPlex object 9337 9338 Output Parameters: 9339 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9340 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9341 9342 Level: intermediate 9343 9344 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9345 @*/ 9346 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) { 9347 DM_Plex *plex = (DM_Plex *)dm->data; 9348 9349 PetscFunctionBegin; 9350 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9351 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9352 if (anchorSection) *anchorSection = plex->anchorSection; 9353 if (anchorIS) *anchorIS = plex->anchorIS; 9354 PetscFunctionReturn(0); 9355 } 9356 9357 /*@ 9358 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9359 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9360 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9361 9362 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9363 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9364 9365 collective on dm 9366 9367 Input Parameters: 9368 + dm - The DMPlex object 9369 . 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). 9370 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9371 9372 The reference counts of anchorSection and anchorIS are incremented. 9373 9374 Level: intermediate 9375 9376 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9377 @*/ 9378 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) { 9379 DM_Plex *plex = (DM_Plex *)dm->data; 9380 PetscMPIInt result; 9381 9382 PetscFunctionBegin; 9383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9384 if (anchorSection) { 9385 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9386 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9387 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9388 } 9389 if (anchorIS) { 9390 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9391 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9392 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9393 } 9394 9395 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9396 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9397 plex->anchorSection = anchorSection; 9398 9399 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9400 PetscCall(ISDestroy(&plex->anchorIS)); 9401 plex->anchorIS = anchorIS; 9402 9403 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9404 PetscInt size, a, pStart, pEnd; 9405 const PetscInt *anchors; 9406 9407 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9408 PetscCall(ISGetLocalSize(anchorIS, &size)); 9409 PetscCall(ISGetIndices(anchorIS, &anchors)); 9410 for (a = 0; a < size; a++) { 9411 PetscInt p; 9412 9413 p = anchors[a]; 9414 if (p >= pStart && p < pEnd) { 9415 PetscInt dof; 9416 9417 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9418 if (dof) { 9419 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9420 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9421 } 9422 } 9423 } 9424 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9425 } 9426 /* reset the generic constraints */ 9427 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9428 PetscFunctionReturn(0); 9429 } 9430 9431 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) { 9432 PetscSection anchorSection; 9433 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9434 9435 PetscFunctionBegin; 9436 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9437 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9438 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9439 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9440 if (numFields) { 9441 PetscInt f; 9442 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9443 9444 for (f = 0; f < numFields; f++) { 9445 PetscInt numComp; 9446 9447 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9448 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9449 } 9450 } 9451 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9452 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9453 pStart = PetscMax(pStart, sStart); 9454 pEnd = PetscMin(pEnd, sEnd); 9455 pEnd = PetscMax(pStart, pEnd); 9456 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9457 for (p = pStart; p < pEnd; p++) { 9458 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9459 if (dof) { 9460 PetscCall(PetscSectionGetDof(section, p, &dof)); 9461 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9462 for (f = 0; f < numFields; f++) { 9463 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9464 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9465 } 9466 } 9467 } 9468 PetscCall(PetscSectionSetUp(*cSec)); 9469 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9470 PetscFunctionReturn(0); 9471 } 9472 9473 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) { 9474 PetscSection aSec; 9475 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9476 const PetscInt *anchors; 9477 PetscInt numFields, f; 9478 IS aIS; 9479 MatType mtype; 9480 PetscBool iscuda, iskokkos; 9481 9482 PetscFunctionBegin; 9483 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9484 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9485 PetscCall(PetscSectionGetStorageSize(section, &n)); 9486 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9487 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9488 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9489 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9490 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9491 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9492 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9493 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9494 else mtype = MATSEQAIJ; 9495 PetscCall(MatSetType(*cMat, mtype)); 9496 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9497 PetscCall(ISGetIndices(aIS, &anchors)); 9498 /* cSec will be a subset of aSec and section */ 9499 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9500 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9501 PetscCall(PetscMalloc1(m + 1, &i)); 9502 i[0] = 0; 9503 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9504 for (p = pStart; p < pEnd; p++) { 9505 PetscInt rDof, rOff, r; 9506 9507 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9508 if (!rDof) continue; 9509 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9510 if (numFields) { 9511 for (f = 0; f < numFields; f++) { 9512 annz = 0; 9513 for (r = 0; r < rDof; r++) { 9514 a = anchors[rOff + r]; 9515 if (a < sStart || a >= sEnd) continue; 9516 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9517 annz += aDof; 9518 } 9519 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9520 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9521 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9522 } 9523 } else { 9524 annz = 0; 9525 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9526 for (q = 0; q < dof; q++) { 9527 a = anchors[rOff + q]; 9528 if (a < sStart || a >= sEnd) continue; 9529 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9530 annz += aDof; 9531 } 9532 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9533 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9534 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9535 } 9536 } 9537 nnz = i[m]; 9538 PetscCall(PetscMalloc1(nnz, &j)); 9539 offset = 0; 9540 for (p = pStart; p < pEnd; p++) { 9541 if (numFields) { 9542 for (f = 0; f < numFields; f++) { 9543 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9544 for (q = 0; q < dof; q++) { 9545 PetscInt rDof, rOff, r; 9546 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9547 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9548 for (r = 0; r < rDof; r++) { 9549 PetscInt s; 9550 9551 a = anchors[rOff + r]; 9552 if (a < sStart || a >= sEnd) continue; 9553 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9554 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9555 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9556 } 9557 } 9558 } 9559 } else { 9560 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9561 for (q = 0; q < dof; q++) { 9562 PetscInt rDof, rOff, r; 9563 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9564 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9565 for (r = 0; r < rDof; r++) { 9566 PetscInt s; 9567 9568 a = anchors[rOff + r]; 9569 if (a < sStart || a >= sEnd) continue; 9570 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9571 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9572 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9573 } 9574 } 9575 } 9576 } 9577 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9578 PetscCall(PetscFree(i)); 9579 PetscCall(PetscFree(j)); 9580 PetscCall(ISRestoreIndices(aIS, &anchors)); 9581 PetscFunctionReturn(0); 9582 } 9583 9584 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) { 9585 DM_Plex *plex = (DM_Plex *)dm->data; 9586 PetscSection anchorSection, section, cSec; 9587 Mat cMat; 9588 9589 PetscFunctionBegin; 9590 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9591 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9592 if (anchorSection) { 9593 PetscInt Nf; 9594 9595 PetscCall(DMGetLocalSection(dm, §ion)); 9596 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9597 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9598 PetscCall(DMGetNumFields(dm, &Nf)); 9599 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9600 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9601 PetscCall(PetscSectionDestroy(&cSec)); 9602 PetscCall(MatDestroy(&cMat)); 9603 } 9604 PetscFunctionReturn(0); 9605 } 9606 9607 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) { 9608 IS subis; 9609 PetscSection section, subsection; 9610 9611 PetscFunctionBegin; 9612 PetscCall(DMGetLocalSection(dm, §ion)); 9613 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9614 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9615 /* Create subdomain */ 9616 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9617 /* Create submodel */ 9618 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9619 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9620 PetscCall(DMSetLocalSection(*subdm, subsection)); 9621 PetscCall(PetscSectionDestroy(&subsection)); 9622 PetscCall(DMCopyDisc(dm, *subdm)); 9623 /* Create map from submodel to global model */ 9624 if (is) { 9625 PetscSection sectionGlobal, subsectionGlobal; 9626 IS spIS; 9627 const PetscInt *spmap; 9628 PetscInt *subIndices; 9629 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9630 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9631 9632 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9633 PetscCall(ISGetIndices(spIS, &spmap)); 9634 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9635 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9636 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9637 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9638 for (p = pStart; p < pEnd; ++p) { 9639 PetscInt gdof, pSubSize = 0; 9640 9641 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9642 if (gdof > 0) { 9643 for (f = 0; f < Nf; ++f) { 9644 PetscInt fdof, fcdof; 9645 9646 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9647 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9648 pSubSize += fdof - fcdof; 9649 } 9650 subSize += pSubSize; 9651 if (pSubSize) { 9652 if (bs < 0) { 9653 bs = pSubSize; 9654 } else if (bs != pSubSize) { 9655 /* Layout does not admit a pointwise block size */ 9656 bs = 1; 9657 } 9658 } 9659 } 9660 } 9661 /* Must have same blocksize on all procs (some might have no points) */ 9662 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9663 bsLocal[1] = bs; 9664 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9665 if (bsMinMax[0] != bsMinMax[1]) { 9666 bs = 1; 9667 } else { 9668 bs = bsMinMax[0]; 9669 } 9670 PetscCall(PetscMalloc1(subSize, &subIndices)); 9671 for (p = pStart; p < pEnd; ++p) { 9672 PetscInt gdof, goff; 9673 9674 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9675 if (gdof > 0) { 9676 const PetscInt point = spmap[p]; 9677 9678 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9679 for (f = 0; f < Nf; ++f) { 9680 PetscInt fdof, fcdof, fc, f2, poff = 0; 9681 9682 /* Can get rid of this loop by storing field information in the global section */ 9683 for (f2 = 0; f2 < f; ++f2) { 9684 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9685 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9686 poff += fdof - fcdof; 9687 } 9688 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9689 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9690 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 9691 } 9692 } 9693 } 9694 PetscCall(ISRestoreIndices(spIS, &spmap)); 9695 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9696 if (bs > 1) { 9697 /* We need to check that the block size does not come from non-contiguous fields */ 9698 PetscInt i, j, set = 1; 9699 for (i = 0; i < subSize; i += bs) { 9700 for (j = 0; j < bs; ++j) { 9701 if (subIndices[i + j] != subIndices[i] + j) { 9702 set = 0; 9703 break; 9704 } 9705 } 9706 } 9707 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9708 } 9709 /* Attach nullspace */ 9710 for (f = 0; f < Nf; ++f) { 9711 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9712 if ((*subdm)->nullspaceConstructors[f]) break; 9713 } 9714 if (f < Nf) { 9715 MatNullSpace nullSpace; 9716 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9717 9718 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9719 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9720 } 9721 } 9722 PetscFunctionReturn(0); 9723 } 9724 9725 /*@ 9726 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9727 9728 Input Parameter: 9729 - dm - The DM 9730 9731 Level: developer 9732 9733 Options Database Keys: 9734 . -dm_plex_monitor_throughput - Activate the monitor 9735 9736 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9737 @*/ 9738 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) { 9739 #if defined(PETSC_USE_LOG) 9740 PetscStageLog stageLog; 9741 PetscLogEvent event; 9742 PetscLogStage stage; 9743 PetscEventPerfInfo eventInfo; 9744 PetscReal cellRate, flopRate; 9745 PetscInt cStart, cEnd, Nf, N; 9746 const char *name; 9747 #endif 9748 9749 PetscFunctionBegin; 9750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9751 #if defined(PETSC_USE_LOG) 9752 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 9753 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9754 PetscCall(DMGetNumFields(dm, &Nf)); 9755 PetscCall(PetscLogGetStageLog(&stageLog)); 9756 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9757 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9758 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9759 N = (cEnd - cStart) * Nf * eventInfo.count; 9760 flopRate = eventInfo.flops / eventInfo.time; 9761 cellRate = N / eventInfo.time; 9762 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))); 9763 #else 9764 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9765 #endif 9766 PetscFunctionReturn(0); 9767 } 9768