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 { 36 DMPolytopeType ct; 37 PetscInt cStart, cEnd; 38 39 PetscFunctionBegin; 40 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 41 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 42 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 43 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 44 PetscFunctionReturn(0); 45 } 46 47 /*@ 48 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 49 50 Input Parameters: 51 + dm - The DMPlex object 52 - height - The cell height in the Plex, 0 is the default 53 54 Output Parameters: 55 + cStart - The first "normal" cell 56 - cEnd - The upper bound on "normal"" cells 57 58 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 59 60 Level: developer 61 62 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 63 @*/ 64 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 65 { 66 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 67 PetscInt cS, cE, c; 68 69 PetscFunctionBegin; 70 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 71 for (c = cS; c < cE; ++c) { 72 DMPolytopeType cct; 73 74 PetscCall(DMPlexGetCellType(dm, c, &cct)); 75 if ((PetscInt) cct < 0) break; 76 switch (cct) { 77 case DM_POLYTOPE_POINT: 78 case DM_POLYTOPE_SEGMENT: 79 case DM_POLYTOPE_TRIANGLE: 80 case DM_POLYTOPE_QUADRILATERAL: 81 case DM_POLYTOPE_TETRAHEDRON: 82 case DM_POLYTOPE_HEXAHEDRON: 83 ct = cct; 84 break; 85 default: break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) break; 88 } 89 if (ct != DM_POLYTOPE_UNKNOWN) { 90 DMLabel ctLabel; 91 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 94 // Reset label for fast lookup 95 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 96 } 97 if (cStart) *cStart = cS; 98 if (cEnd) *cEnd = cE; 99 PetscFunctionReturn(0); 100 } 101 102 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 103 { 104 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 105 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 106 107 PetscFunctionBegin; 108 *ft = PETSC_VTK_INVALID; 109 PetscCall(DMGetCoordinateDim(dm, &cdim)); 110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 111 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 112 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 113 if (field >= 0) { 114 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 115 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 116 } else { 117 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 118 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 119 } 120 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 121 if (globalvcdof[0]) { 122 *sStart = vStart; 123 *sEnd = vEnd; 124 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 125 else *ft = PETSC_VTK_POINT_FIELD; 126 } else if (globalvcdof[1]) { 127 *sStart = cStart; 128 *sEnd = cEnd; 129 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 130 else *ft = PETSC_VTK_CELL_FIELD; 131 } else { 132 if (field >= 0) { 133 const char *fieldname; 134 135 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 136 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 137 } else { 138 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 139 } 140 } 141 PetscFunctionReturn(0); 142 } 143 144 /*@ 145 DMPlexVecView1D - Plot many 1D solutions on the same line graph 146 147 Collective on dm 148 149 Input Parameters: 150 + dm - The DMPlex 151 . n - The number of vectors 152 . u - The array of local vectors 153 - viewer - The Draw viewer 154 155 Level: advanced 156 157 .seealso: `VecViewFromOptions()`, `VecView()` 158 @*/ 159 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 160 { 161 PetscDS ds; 162 PetscDraw draw = NULL; 163 PetscDrawLG lg; 164 Vec coordinates; 165 const PetscScalar *coords, **sol; 166 PetscReal *vals; 167 PetscInt *Nc; 168 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 169 char **names; 170 171 PetscFunctionBegin; 172 PetscCall(DMGetDS(dm, &ds)); 173 PetscCall(PetscDSGetNumFields(ds, &Nf)); 174 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 175 PetscCall(PetscDSGetComponents(ds, &Nc)); 176 177 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 178 if (!draw) PetscFunctionReturn(0); 179 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 180 181 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 182 for (i = 0, l = 0; i < n; ++i) { 183 const char *vname; 184 185 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 186 for (f = 0; f < Nf; ++f) { 187 PetscObject disc; 188 const char *fname; 189 char tmpname[PETSC_MAX_PATH_LEN]; 190 191 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 192 /* TODO Create names for components */ 193 for (c = 0; c < Nc[f]; ++c, ++l) { 194 PetscCall(PetscObjectGetName(disc, &fname)); 195 PetscCall(PetscStrcpy(tmpname, vname)); 196 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 197 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 198 PetscCall(PetscStrallocpy(tmpname, &names[l])); 199 } 200 } 201 } 202 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 203 /* Just add P_1 support for now */ 204 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 205 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 206 PetscCall(VecGetArrayRead(coordinates, &coords)); 207 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 208 for (v = vStart; v < vEnd; ++v) { 209 PetscScalar *x, *svals; 210 211 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 212 for (i = 0; i < n; ++i) { 213 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 214 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 215 } 216 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 217 } 218 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 219 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 220 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 221 PetscCall(PetscFree3(sol, names, vals)); 222 223 PetscCall(PetscDrawLGDraw(lg)); 224 PetscCall(PetscDrawLGDestroy(&lg)); 225 PetscFunctionReturn(0); 226 } 227 228 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 229 { 230 DM dm; 231 232 PetscFunctionBegin; 233 PetscCall(VecGetDM(u, &dm)); 234 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 235 PetscFunctionReturn(0); 236 } 237 238 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 239 { 240 DM dm; 241 PetscSection s; 242 PetscDraw draw, popup; 243 DM cdm; 244 PetscSection coordSection; 245 Vec coordinates; 246 const PetscScalar *coords, *array; 247 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 248 PetscReal vbound[2], time; 249 PetscBool flg; 250 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 251 const char *name; 252 char title[PETSC_MAX_PATH_LEN]; 253 254 PetscFunctionBegin; 255 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 256 PetscCall(VecGetDM(v, &dm)); 257 PetscCall(DMGetCoordinateDim(dm, &dim)); 258 PetscCall(DMGetLocalSection(dm, &s)); 259 PetscCall(PetscSectionGetNumFields(s, &Nf)); 260 PetscCall(DMGetCoarsenLevel(dm, &level)); 261 PetscCall(DMGetCoordinateDM(dm, &cdm)); 262 PetscCall(DMGetLocalSection(cdm, &coordSection)); 263 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 264 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 265 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 266 267 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 268 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 269 270 PetscCall(VecGetLocalSize(coordinates, &N)); 271 PetscCall(VecGetArrayRead(coordinates, &coords)); 272 for (c = 0; c < N; c += dim) { 273 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 274 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 275 } 276 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 277 PetscCall(PetscDrawClear(draw)); 278 279 /* Could implement something like DMDASelectFields() */ 280 for (f = 0; f < Nf; ++f) { 281 DM fdm = dm; 282 Vec fv = v; 283 IS fis; 284 char prefix[PETSC_MAX_PATH_LEN]; 285 const char *fname; 286 287 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 288 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 289 290 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 291 else {prefix[0] = '\0';} 292 if (Nf > 1) { 293 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 294 PetscCall(VecGetSubVector(v, fis, &fv)); 295 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 296 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 297 } 298 for (comp = 0; comp < Nc; ++comp, ++w) { 299 PetscInt nmax = 2; 300 301 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 302 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 303 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 304 PetscCall(PetscDrawSetTitle(draw, title)); 305 306 /* TODO Get max and min only for this component */ 307 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 308 if (!flg) { 309 PetscCall(VecMin(fv, NULL, &vbound[0])); 310 PetscCall(VecMax(fv, NULL, &vbound[1])); 311 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 312 } 313 PetscCall(PetscDrawGetPopup(draw, &popup)); 314 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 315 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 316 317 PetscCall(VecGetArrayRead(fv, &array)); 318 for (c = cStart; c < cEnd; ++c) { 319 PetscScalar *coords = NULL, *a = NULL; 320 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 321 322 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 323 if (a) { 324 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 325 color[1] = color[2] = color[3] = color[0]; 326 } else { 327 PetscScalar *vals = NULL; 328 PetscInt numVals, va; 329 330 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 331 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); 332 switch (numVals/Nc) { 333 case 3: /* P1 Triangle */ 334 case 4: /* P1 Quadrangle */ 335 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 336 break; 337 case 6: /* P2 Triangle */ 338 case 8: /* P2 Quadrangle */ 339 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 340 break; 341 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 342 } 343 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 344 } 345 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 346 switch (numCoords) { 347 case 6: 348 case 12: /* Localized triangle */ 349 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])); 350 break; 351 case 8: 352 case 16: /* Localized quadrilateral */ 353 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])); 354 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])); 355 break; 356 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 357 } 358 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 359 } 360 PetscCall(VecRestoreArrayRead(fv, &array)); 361 PetscCall(PetscDrawFlush(draw)); 362 PetscCall(PetscDrawPause(draw)); 363 PetscCall(PetscDrawSave(draw)); 364 } 365 if (Nf > 1) { 366 PetscCall(VecRestoreSubVector(v, fis, &fv)); 367 PetscCall(ISDestroy(&fis)); 368 PetscCall(DMDestroy(&fdm)); 369 } 370 } 371 PetscFunctionReturn(0); 372 } 373 374 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 375 { 376 DM dm; 377 PetscDraw draw; 378 PetscInt dim; 379 PetscBool isnull; 380 381 PetscFunctionBegin; 382 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 383 PetscCall(PetscDrawIsNull(draw, &isnull)); 384 if (isnull) PetscFunctionReturn(0); 385 386 PetscCall(VecGetDM(v, &dm)); 387 PetscCall(DMGetCoordinateDim(dm, &dim)); 388 switch (dim) { 389 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 390 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 391 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 392 } 393 PetscFunctionReturn(0); 394 } 395 396 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 397 { 398 DM dm; 399 Vec locv; 400 const char *name; 401 PetscSection section; 402 PetscInt pStart, pEnd; 403 PetscInt numFields; 404 PetscViewerVTKFieldType ft; 405 406 PetscFunctionBegin; 407 PetscCall(VecGetDM(v, &dm)); 408 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 409 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 410 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 411 PetscCall(VecCopy(v, locv)); 412 PetscCall(DMGetLocalSection(dm, §ion)); 413 PetscCall(PetscSectionGetNumFields(section, &numFields)); 414 if (!numFields) { 415 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 416 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 417 } else { 418 PetscInt f; 419 420 for (f = 0; f < numFields; f++) { 421 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 422 if (ft == PETSC_VTK_INVALID) continue; 423 PetscCall(PetscObjectReference((PetscObject)locv)); 424 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 425 } 426 PetscCall(VecDestroy(&locv)); 427 } 428 PetscFunctionReturn(0); 429 } 430 431 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 432 { 433 DM dm; 434 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 435 436 PetscFunctionBegin; 437 PetscCall(VecGetDM(v, &dm)); 438 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 439 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 440 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 441 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 442 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 443 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 444 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 445 PetscInt i,numFields; 446 PetscObject fe; 447 PetscBool fem = PETSC_FALSE; 448 Vec locv = v; 449 const char *name; 450 PetscInt step; 451 PetscReal time; 452 453 PetscCall(DMGetNumFields(dm, &numFields)); 454 for (i=0; i<numFields; i++) { 455 PetscCall(DMGetField(dm, i, NULL, &fe)); 456 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 457 } 458 if (fem) { 459 PetscObject isZero; 460 461 PetscCall(DMGetLocalVector(dm, &locv)); 462 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 463 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 464 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 465 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 466 PetscCall(VecCopy(v, locv)); 467 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 468 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 469 } 470 if (isvtk) { 471 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 472 } else if (ishdf5) { 473 #if defined(PETSC_HAVE_HDF5) 474 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 475 #else 476 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 477 #endif 478 } else if (isdraw) { 479 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 480 } else if (isglvis) { 481 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 482 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 483 PetscCall(VecView_GLVis(locv, viewer)); 484 } else if (iscgns) { 485 #if defined(PETSC_HAVE_CGNS) 486 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 487 #else 488 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 489 #endif 490 } 491 if (fem) { 492 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 493 PetscCall(DMRestoreLocalVector(dm, &locv)); 494 } 495 } else { 496 PetscBool isseq; 497 498 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 499 if (isseq) PetscCall(VecView_Seq(v, viewer)); 500 else PetscCall(VecView_MPI(v, viewer)); 501 } 502 PetscFunctionReturn(0); 503 } 504 505 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 506 { 507 DM dm; 508 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 509 510 PetscFunctionBegin; 511 PetscCall(VecGetDM(v, &dm)); 512 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 513 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 514 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 515 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 516 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 517 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 518 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 519 if (isvtk || isdraw || isglvis || iscgns) { 520 Vec locv; 521 PetscObject isZero; 522 const char *name; 523 524 PetscCall(DMGetLocalVector(dm, &locv)); 525 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 526 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 527 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 528 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 529 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 530 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 531 PetscCall(VecView_Plex_Local(locv, viewer)); 532 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 533 PetscCall(DMRestoreLocalVector(dm, &locv)); 534 } else if (ishdf5) { 535 #if defined(PETSC_HAVE_HDF5) 536 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 537 #else 538 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 539 #endif 540 } else if (isexodusii) { 541 #if defined(PETSC_HAVE_EXODUSII) 542 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 543 #else 544 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 545 #endif 546 } else { 547 PetscBool isseq; 548 549 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 550 if (isseq) PetscCall(VecView_Seq(v, viewer)); 551 else PetscCall(VecView_MPI(v, viewer)); 552 } 553 PetscFunctionReturn(0); 554 } 555 556 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 557 { 558 DM dm; 559 MPI_Comm comm; 560 PetscViewerFormat format; 561 Vec v; 562 PetscBool isvtk, ishdf5; 563 564 PetscFunctionBegin; 565 PetscCall(VecGetDM(originalv, &dm)); 566 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 567 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 568 PetscCall(PetscViewerGetFormat(viewer, &format)); 569 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 570 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 571 if (format == PETSC_VIEWER_NATIVE) { 572 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 573 /* this need a better fix */ 574 if (dm->useNatural) { 575 if (dm->sfNatural) { 576 const char *vecname; 577 PetscInt n, nroots; 578 579 PetscCall(VecGetLocalSize(originalv, &n)); 580 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 581 if (n == nroots) { 582 PetscCall(DMGetGlobalVector(dm, &v)); 583 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 584 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 585 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 586 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 587 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 588 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 589 } else v = originalv; 590 } else v = originalv; 591 592 if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 595 #else 596 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isvtk) { 599 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 600 } else { 601 PetscBool isseq; 602 603 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 604 if (isseq) PetscCall(VecView_Seq(v, viewer)); 605 else PetscCall(VecView_MPI(v, viewer)); 606 } 607 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 608 PetscFunctionReturn(0); 609 } 610 611 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 612 { 613 DM dm; 614 PetscBool ishdf5; 615 616 PetscFunctionBegin; 617 PetscCall(VecGetDM(v, &dm)); 618 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 619 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 620 if (ishdf5) { 621 DM dmBC; 622 Vec gv; 623 const char *name; 624 625 PetscCall(DMGetOutputDM(dm, &dmBC)); 626 PetscCall(DMGetGlobalVector(dmBC, &gv)); 627 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 628 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 629 PetscCall(VecLoad_Default(gv, viewer)); 630 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 631 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 632 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 633 } else PetscCall(VecLoad_Default(v, viewer)); 634 PetscFunctionReturn(0); 635 } 636 637 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 638 { 639 DM dm; 640 PetscBool ishdf5,isexodusii; 641 642 PetscFunctionBegin; 643 PetscCall(VecGetDM(v, &dm)); 644 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 645 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 646 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 647 if (ishdf5) { 648 #if defined(PETSC_HAVE_HDF5) 649 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 650 #else 651 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 652 #endif 653 } else if (isexodusii) { 654 #if defined(PETSC_HAVE_EXODUSII) 655 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 656 #else 657 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 658 #endif 659 } else PetscCall(VecLoad_Default(v, viewer)); 660 PetscFunctionReturn(0); 661 } 662 663 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 664 { 665 DM dm; 666 PetscViewerFormat format; 667 PetscBool ishdf5; 668 669 PetscFunctionBegin; 670 PetscCall(VecGetDM(originalv, &dm)); 671 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 672 PetscCall(PetscViewerGetFormat(viewer, &format)); 673 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 674 if (format == PETSC_VIEWER_NATIVE) { 675 if (dm->useNatural) { 676 if (dm->sfNatural) { 677 if (ishdf5) { 678 #if defined(PETSC_HAVE_HDF5) 679 Vec v; 680 const char *vecname; 681 682 PetscCall(DMGetGlobalVector(dm, &v)); 683 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 684 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 685 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 686 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 687 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 688 PetscCall(DMRestoreGlobalVector(dm, &v)); 689 #else 690 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 691 #endif 692 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 693 } 694 } else PetscCall(VecLoad_Default(originalv, viewer)); 695 } 696 PetscFunctionReturn(0); 697 } 698 699 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 700 { 701 PetscSection coordSection; 702 Vec coordinates; 703 DMLabel depthLabel, celltypeLabel; 704 const char *name[4]; 705 const PetscScalar *a; 706 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 707 708 PetscFunctionBegin; 709 PetscCall(DMGetDimension(dm, &dim)); 710 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 711 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 712 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 713 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 714 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 715 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 716 PetscCall(VecGetArrayRead(coordinates, &a)); 717 name[0] = "vertex"; 718 name[1] = "edge"; 719 name[dim-1] = "face"; 720 name[dim] = "cell"; 721 for (c = cStart; c < cEnd; ++c) { 722 PetscInt *closure = NULL; 723 PetscInt closureSize, cl, ct; 724 725 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 726 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 727 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 728 PetscCall(PetscViewerASCIIPushTab(viewer)); 729 for (cl = 0; cl < closureSize*2; cl += 2) { 730 PetscInt point = closure[cl], depth, dof, off, d, p; 731 732 if ((point < pStart) || (point >= pEnd)) continue; 733 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 734 if (!dof) continue; 735 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 736 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 737 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 738 for (p = 0; p < dof/dim; ++p) { 739 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 740 for (d = 0; d < dim; ++d) { 741 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 742 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 743 } 744 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 745 } 746 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 747 } 748 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 749 PetscCall(PetscViewerASCIIPopTab(viewer)); 750 } 751 PetscCall(VecRestoreArrayRead(coordinates, &a)); 752 PetscFunctionReturn(0); 753 } 754 755 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 756 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 757 758 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 759 { 760 PetscInt i; 761 762 PetscFunctionBegin; 763 if (dim > 3) { 764 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 765 } else { 766 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 767 768 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 769 switch (cs) { 770 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 771 case CS_POLAR: 772 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 773 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 774 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 775 break; 776 case CS_CYLINDRICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 779 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 780 trcoords[2] = coords[2]; 781 break; 782 case CS_SPHERICAL: 783 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 784 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 785 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 786 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 787 break; 788 } 789 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 790 } 791 PetscFunctionReturn(0); 792 } 793 794 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 795 { 796 DM_Plex *mesh = (DM_Plex*) dm->data; 797 DM cdm, cdmCell; 798 PetscSection coordSection, coordSectionCell; 799 Vec coordinates, coordinatesCell; 800 PetscViewerFormat format; 801 802 PetscFunctionBegin; 803 PetscCall(DMGetCoordinateDM(dm, &cdm)); 804 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 805 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 806 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 807 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 808 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 809 PetscCall(PetscViewerGetFormat(viewer, &format)); 810 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 811 const char *name; 812 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 813 PetscInt pStart, pEnd, p, numLabels, l; 814 PetscMPIInt rank, size; 815 816 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 817 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 818 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 819 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 820 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 821 PetscCall(DMGetDimension(dm, &dim)); 822 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 823 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 824 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 825 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 826 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 827 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 828 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 829 for (p = pStart; p < pEnd; ++p) { 830 PetscInt dof, off, s; 831 832 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 833 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 834 for (s = off; s < off+dof; ++s) { 835 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 836 } 837 } 838 PetscCall(PetscViewerFlush(viewer)); 839 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 840 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 841 for (p = pStart; p < pEnd; ++p) { 842 PetscInt dof, off, c; 843 844 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 845 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 846 for (c = off; c < off+dof; ++c) { 847 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 848 } 849 } 850 PetscCall(PetscViewerFlush(viewer)); 851 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 852 if (coordSection && coordinates) { 853 CoordSystem cs = CS_CARTESIAN; 854 const PetscScalar *array, *arrayCell = NULL; 855 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 856 PetscMPIInt rank; 857 const char *name; 858 859 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 860 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 861 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 862 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 863 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 864 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 865 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 866 pStart = PetscMin(pvStart, pcStart); 867 pEnd = PetscMax(pvEnd, pcEnd); 868 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 869 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 870 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 871 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 872 873 PetscCall(VecGetArrayRead(coordinates, &array)); 874 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 875 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 877 for (p = pStart; p < pEnd; ++p) { 878 PetscInt dof, off; 879 880 if (p >= pvStart && p < pvEnd) { 881 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 882 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 883 if (dof) { 884 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 885 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 886 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 887 } 888 } 889 if (cdmCell && p >= pcStart && p < pcEnd) { 890 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 891 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 892 if (dof) { 893 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 894 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 895 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 896 } 897 } 898 } 899 PetscCall(PetscViewerFlush(viewer)); 900 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 901 PetscCall(VecRestoreArrayRead(coordinates, &array)); 902 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 903 } 904 PetscCall(DMGetNumLabels(dm, &numLabels)); 905 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 906 for (l = 0; l < numLabels; ++l) { 907 DMLabel label; 908 PetscBool isdepth; 909 const char *name; 910 911 PetscCall(DMGetLabelName(dm, l, &name)); 912 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 913 if (isdepth) continue; 914 PetscCall(DMGetLabel(dm, name, &label)); 915 PetscCall(DMLabelView(label, viewer)); 916 } 917 if (size > 1) { 918 PetscSF sf; 919 920 PetscCall(DMGetPointSF(dm, &sf)); 921 PetscCall(PetscSFView(sf, viewer)); 922 } 923 PetscCall(PetscViewerFlush(viewer)); 924 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 925 const char *name, *color; 926 const char *defcolors[3] = {"gray", "orange", "green"}; 927 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 928 char lname[PETSC_MAX_PATH_LEN]; 929 PetscReal scale = 2.0; 930 PetscReal tikzscale = 1.0; 931 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 932 double tcoords[3]; 933 PetscScalar *coords; 934 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 935 PetscMPIInt rank, size; 936 char **names, **colors, **lcolors; 937 PetscBool flg, lflg; 938 PetscBT wp = NULL; 939 PetscInt pEnd, pStart; 940 941 PetscCall(DMGetDimension(dm, &dim)); 942 PetscCall(DMPlexGetDepth(dm, &depth)); 943 PetscCall(DMGetNumLabels(dm, &numLabels)); 944 numLabels = PetscMax(numLabels, 10); 945 numColors = 10; 946 numLColors = 10; 947 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 948 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 949 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 950 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 951 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 952 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 953 n = 4; 954 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 955 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 956 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 957 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 958 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 959 if (!useLabels) numLabels = 0; 960 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 961 if (!useColors) { 962 numColors = 3; 963 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 964 } 965 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 966 if (!useColors) { 967 numLColors = 4; 968 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 969 } 970 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 971 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 972 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 973 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 974 if (depth < dim) plotEdges = PETSC_FALSE; 975 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 976 977 /* filter points with labelvalue != labeldefaultvalue */ 978 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 979 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 980 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 981 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 982 if (lflg) { 983 DMLabel lbl; 984 985 PetscCall(DMGetLabel(dm, lname, &lbl)); 986 if (lbl) { 987 PetscInt val, defval; 988 989 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 990 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 991 for (c = pStart; c < pEnd; c++) { 992 PetscInt *closure = NULL; 993 PetscInt closureSize; 994 995 PetscCall(DMLabelGetValue(lbl, c, &val)); 996 if (val == defval) continue; 997 998 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 999 for (p = 0; p < closureSize*2; p += 2) { 1000 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1001 } 1002 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1003 } 1004 } 1005 } 1006 1007 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1008 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1009 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1011 \\documentclass[tikz]{standalone}\n\n\ 1012 \\usepackage{pgflibraryshapes}\n\ 1013 \\usetikzlibrary{backgrounds}\n\ 1014 \\usetikzlibrary{arrows}\n\ 1015 \\begin{document}\n")); 1016 if (size > 1) { 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1018 for (p = 0; p < size; ++p) { 1019 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 1021 } 1022 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1023 } 1024 if (drawHasse) { 1025 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1026 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1029 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1031 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1032 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1033 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1034 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1035 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1036 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1037 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1038 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1039 } 1040 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1041 1042 /* Plot vertices */ 1043 PetscCall(VecGetArray(coordinates, &coords)); 1044 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1045 for (v = vStart; v < vEnd; ++v) { 1046 PetscInt off, dof, d; 1047 PetscBool isLabeled = PETSC_FALSE; 1048 1049 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1050 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1051 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1052 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1053 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1054 for (d = 0; d < dof; ++d) { 1055 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1056 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1057 } 1058 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1059 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1060 for (d = 0; d < dof; ++d) { 1061 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1062 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1063 } 1064 if (drawHasse) color = colors[0%numColors]; 1065 else color = colors[rank%numColors]; 1066 for (l = 0; l < numLabels; ++l) { 1067 PetscInt val; 1068 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1069 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1070 } 1071 if (drawNumbers[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1073 } else if (drawColors[0]) { 1074 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1075 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1076 } 1077 PetscCall(VecRestoreArray(coordinates, &coords)); 1078 PetscCall(PetscViewerFlush(viewer)); 1079 /* Plot edges */ 1080 if (plotEdges) { 1081 PetscCall(VecGetArray(coordinates, &coords)); 1082 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1083 for (e = eStart; e < eEnd; ++e) { 1084 const PetscInt *cone; 1085 PetscInt coneSize, offA, offB, dof, d; 1086 1087 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1088 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1089 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1090 PetscCall(DMPlexGetCone(dm, e, &cone)); 1091 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1092 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1093 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1094 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1095 for (d = 0; d < dof; ++d) { 1096 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1097 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1098 } 1099 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1100 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1101 for (d = 0; d < dof; ++d) { 1102 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1104 } 1105 if (drawHasse) color = colors[1%numColors]; 1106 else color = colors[rank%numColors]; 1107 for (l = 0; l < numLabels; ++l) { 1108 PetscInt val; 1109 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1110 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1111 } 1112 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1113 } 1114 PetscCall(VecRestoreArray(coordinates, &coords)); 1115 PetscCall(PetscViewerFlush(viewer)); 1116 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1117 } 1118 /* Plot cells */ 1119 if (dim == 3 || !drawNumbers[1]) { 1120 for (e = eStart; e < eEnd; ++e) { 1121 const PetscInt *cone; 1122 1123 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1124 color = colors[rank%numColors]; 1125 for (l = 0; l < numLabels; ++l) { 1126 PetscInt val; 1127 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1128 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1129 } 1130 PetscCall(DMPlexGetCone(dm, e, &cone)); 1131 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1132 } 1133 } else { 1134 DMPolytopeType ct; 1135 1136 /* Drawing a 2D polygon */ 1137 for (c = cStart; c < cEnd; ++c) { 1138 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1139 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1140 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1141 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1142 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1143 const PetscInt *cone; 1144 PetscInt coneSize, e; 1145 1146 PetscCall(DMPlexGetCone(dm, c, &cone)); 1147 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1148 for (e = 0; e < coneSize; ++e) { 1149 const PetscInt *econe; 1150 1151 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1152 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)); 1153 } 1154 } else { 1155 PetscInt *closure = NULL; 1156 PetscInt closureSize, Nv = 0, v; 1157 1158 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1159 for (p = 0; p < closureSize*2; p += 2) { 1160 const PetscInt point = closure[p]; 1161 1162 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1163 } 1164 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1165 for (v = 0; v <= Nv; ++v) { 1166 const PetscInt vertex = closure[v%Nv]; 1167 1168 if (v > 0) { 1169 if (plotEdges) { 1170 const PetscInt *edge; 1171 PetscInt endpoints[2], ne; 1172 1173 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1174 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1175 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1176 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1177 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1178 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1179 } 1180 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1181 } 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1183 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1184 } 1185 } 1186 } 1187 PetscCall(VecGetArray(coordinates, &coords)); 1188 for (c = cStart; c < cEnd; ++c) { 1189 double ccoords[3] = {0.0, 0.0, 0.0}; 1190 PetscBool isLabeled = PETSC_FALSE; 1191 PetscInt *closure = NULL; 1192 PetscInt closureSize, dof, d, n = 0; 1193 1194 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1195 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1197 for (p = 0; p < closureSize*2; p += 2) { 1198 const PetscInt point = closure[p]; 1199 PetscInt off; 1200 1201 if ((point < vStart) || (point >= vEnd)) continue; 1202 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1203 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1204 for (d = 0; d < dof; ++d) { 1205 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1206 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1207 } 1208 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1209 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1210 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1211 ++n; 1212 } 1213 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1214 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1215 for (d = 0; d < dof; ++d) { 1216 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1218 } 1219 if (drawHasse) color = colors[depth%numColors]; 1220 else color = colors[rank%numColors]; 1221 for (l = 0; l < numLabels; ++l) { 1222 PetscInt val; 1223 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1224 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1225 } 1226 if (drawNumbers[dim]) { 1227 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1228 } else if (drawColors[dim]) { 1229 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1230 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1231 } 1232 PetscCall(VecRestoreArray(coordinates, &coords)); 1233 if (drawHasse) { 1234 color = colors[depth%numColors]; 1235 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1240 1241 color = colors[1%numColors]; 1242 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1244 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1245 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1247 1248 color = colors[0%numColors]; 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1254 1255 for (p = pStart; p < pEnd; ++p) { 1256 const PetscInt *cone; 1257 PetscInt coneSize, cp; 1258 1259 PetscCall(DMPlexGetCone(dm, p, &cone)); 1260 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1261 for (cp = 0; cp < coneSize; ++cp) { 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1263 } 1264 } 1265 } 1266 PetscCall(PetscViewerFlush(viewer)); 1267 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1268 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1269 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1270 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1271 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1272 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1273 PetscCall(PetscFree3(names, colors, lcolors)); 1274 PetscCall(PetscBTDestroy(&wp)); 1275 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1276 Vec cown,acown; 1277 VecScatter sct; 1278 ISLocalToGlobalMapping g2l; 1279 IS gid,acis; 1280 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1281 MPI_Group ggroup,ngroup; 1282 PetscScalar *array,nid; 1283 const PetscInt *idxs; 1284 PetscInt *idxs2,*start,*adjacency,*work; 1285 PetscInt64 lm[3],gm[3]; 1286 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1287 PetscMPIInt d1,d2,rank; 1288 1289 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1290 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1291 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1292 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1293 #endif 1294 if (ncomm != MPI_COMM_NULL) { 1295 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1296 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1297 d1 = 0; 1298 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1299 nid = d2; 1300 PetscCallMPI(MPI_Group_free(&ggroup)); 1301 PetscCallMPI(MPI_Group_free(&ngroup)); 1302 PetscCallMPI(MPI_Comm_free(&ncomm)); 1303 } else nid = 0.0; 1304 1305 /* Get connectivity */ 1306 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1307 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1308 1309 /* filter overlapped local cells */ 1310 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1311 PetscCall(ISGetIndices(gid,&idxs)); 1312 PetscCall(ISGetLocalSize(gid,&cum)); 1313 PetscCall(PetscMalloc1(cum,&idxs2)); 1314 for (c = cStart, cum = 0; c < cEnd; c++) { 1315 if (idxs[c-cStart] < 0) continue; 1316 idxs2[cum++] = idxs[c-cStart]; 1317 } 1318 PetscCall(ISRestoreIndices(gid,&idxs)); 1319 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1320 PetscCall(ISDestroy(&gid)); 1321 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1322 1323 /* support for node-aware cell locality */ 1324 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1325 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1326 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1327 PetscCall(VecGetArray(cown,&array)); 1328 for (c = 0; c < numVertices; c++) array[c] = nid; 1329 PetscCall(VecRestoreArray(cown,&array)); 1330 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1331 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1332 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1333 PetscCall(ISDestroy(&acis)); 1334 PetscCall(VecScatterDestroy(&sct)); 1335 PetscCall(VecDestroy(&cown)); 1336 1337 /* compute edgeCut */ 1338 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1339 PetscCall(PetscMalloc1(cum,&work)); 1340 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1341 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1342 PetscCall(ISDestroy(&gid)); 1343 PetscCall(VecGetArray(acown,&array)); 1344 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1345 PetscInt totl; 1346 1347 totl = start[c+1]-start[c]; 1348 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1349 for (i = 0; i < totl; i++) { 1350 if (work[i] < 0) { 1351 ect += 1; 1352 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1353 } 1354 } 1355 } 1356 PetscCall(PetscFree(work)); 1357 PetscCall(VecRestoreArray(acown,&array)); 1358 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1359 lm[1] = -numVertices; 1360 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1361 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1362 lm[0] = ect; /* edgeCut */ 1363 lm[1] = ectn; /* node-aware edgeCut */ 1364 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1365 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1366 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1367 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1368 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1369 #else 1370 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1371 #endif 1372 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1373 PetscCall(PetscFree(start)); 1374 PetscCall(PetscFree(adjacency)); 1375 PetscCall(VecDestroy(&acown)); 1376 } else { 1377 const char *name; 1378 PetscInt *sizes, *hybsizes, *ghostsizes; 1379 PetscInt locDepth, depth, cellHeight, dim, d; 1380 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1381 PetscInt numLabels, l, maxSize = 17; 1382 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1383 MPI_Comm comm; 1384 PetscMPIInt size, rank; 1385 1386 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1387 PetscCallMPI(MPI_Comm_size(comm, &size)); 1388 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1389 PetscCall(DMGetDimension(dm, &dim)); 1390 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1391 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1392 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1393 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1394 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1395 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1396 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1397 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1398 gcNum = gcEnd - gcStart; 1399 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1400 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1401 for (d = 0; d <= depth; d++) { 1402 PetscInt Nc[2] = {0, 0}, ict; 1403 1404 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1405 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1406 ict = ct0; 1407 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1408 ct0 = (DMPolytopeType) ict; 1409 for (p = pStart; p < pEnd; ++p) { 1410 DMPolytopeType ct; 1411 1412 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1413 if (ct == ct0) ++Nc[0]; 1414 else ++Nc[1]; 1415 } 1416 if (size < maxSize) { 1417 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1418 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1419 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1420 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1421 for (p = 0; p < size; ++p) { 1422 if (rank == 0) { 1423 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1424 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1425 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1426 } 1427 } 1428 } else { 1429 PetscInt locMinMax[2]; 1430 1431 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1432 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1433 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1434 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1435 if (d == depth) { 1436 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1437 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1438 } 1439 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1440 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1441 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1442 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1443 } 1444 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1445 } 1446 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1447 { 1448 const PetscReal *maxCell; 1449 const PetscReal *L; 1450 PetscBool localized; 1451 1452 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1453 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1454 if (L || localized) { 1455 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1456 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1457 if (L) { 1458 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1459 for (d = 0; d < dim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1461 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1462 } 1463 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1464 } 1465 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1466 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1467 } 1468 } 1469 PetscCall(DMGetNumLabels(dm, &numLabels)); 1470 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1471 for (l = 0; l < numLabels; ++l) { 1472 DMLabel label; 1473 const char *name; 1474 IS valueIS; 1475 const PetscInt *values; 1476 PetscInt numValues, v; 1477 1478 PetscCall(DMGetLabelName(dm, l, &name)); 1479 PetscCall(DMGetLabel(dm, name, &label)); 1480 PetscCall(DMLabelGetNumValues(label, &numValues)); 1481 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1482 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1483 PetscCall(ISGetIndices(valueIS, &values)); 1484 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1485 for (v = 0; v < numValues; ++v) { 1486 PetscInt size; 1487 1488 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1489 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1491 } 1492 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1493 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1494 PetscCall(ISRestoreIndices(valueIS, &values)); 1495 PetscCall(ISDestroy(&valueIS)); 1496 } 1497 { 1498 char **labelNames; 1499 PetscInt Nl = numLabels; 1500 PetscBool flg; 1501 1502 PetscCall(PetscMalloc1(Nl, &labelNames)); 1503 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1504 for (l = 0; l < Nl; ++l) { 1505 DMLabel label; 1506 1507 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1508 if (flg) { 1509 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1510 PetscCall(DMLabelView(label, viewer)); 1511 } 1512 PetscCall(PetscFree(labelNames[l])); 1513 } 1514 PetscCall(PetscFree(labelNames)); 1515 } 1516 /* If no fields are specified, people do not want to see adjacency */ 1517 if (dm->Nf) { 1518 PetscInt f; 1519 1520 for (f = 0; f < dm->Nf; ++f) { 1521 const char *name; 1522 1523 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1524 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1525 PetscCall(PetscViewerASCIIPushTab(viewer)); 1526 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1527 if (dm->fields[f].adjacency[0]) { 1528 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1529 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1530 } else { 1531 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1532 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1533 } 1534 PetscCall(PetscViewerASCIIPopTab(viewer)); 1535 } 1536 } 1537 PetscCall(DMGetCoarseDM(dm, &cdm)); 1538 if (cdm) { 1539 PetscCall(PetscViewerASCIIPushTab(viewer)); 1540 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1541 PetscCall(PetscViewerASCIIPopTab(viewer)); 1542 } 1543 } 1544 PetscFunctionReturn(0); 1545 } 1546 1547 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1548 { 1549 DMPolytopeType ct; 1550 PetscMPIInt rank; 1551 PetscInt cdim; 1552 1553 PetscFunctionBegin; 1554 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1555 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1556 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1557 switch (ct) { 1558 case DM_POLYTOPE_SEGMENT: 1559 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1560 switch (cdim) { 1561 case 1: 1562 { 1563 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1564 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1565 1566 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1567 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1568 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1569 } 1570 break; 1571 case 2: 1572 { 1573 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1574 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1575 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1576 1577 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1578 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)); 1579 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)); 1580 } 1581 break; 1582 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1583 } 1584 break; 1585 case DM_POLYTOPE_TRIANGLE: 1586 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1587 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1588 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1589 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1590 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1591 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1592 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1593 break; 1594 case DM_POLYTOPE_QUADRILATERAL: 1595 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1596 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1597 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1598 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]), 1600 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1601 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1602 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1603 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1604 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1605 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1606 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1607 break; 1608 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1609 } 1610 PetscFunctionReturn(0); 1611 } 1612 1613 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1614 { 1615 DMPolytopeType ct; 1616 PetscReal centroid[2] = {0., 0.}; 1617 PetscMPIInt rank; 1618 PetscInt fillColor, v, e, d; 1619 1620 PetscFunctionBegin; 1621 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1622 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1623 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1624 switch (ct) { 1625 case DM_POLYTOPE_TRIANGLE: 1626 { 1627 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1628 1629 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1630 for (e = 0; e < 3; ++e) { 1631 refCoords[0] = refVertices[e*2+0]; 1632 refCoords[1] = refVertices[e*2+1]; 1633 for (d = 1; d <= edgeDiv; ++d) { 1634 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1635 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1636 } 1637 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1638 for (d = 0; d < edgeDiv; ++d) { 1639 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)); 1640 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1641 } 1642 } 1643 } 1644 break; 1645 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1646 } 1647 PetscFunctionReturn(0); 1648 } 1649 1650 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1651 { 1652 PetscDraw draw; 1653 DM cdm; 1654 PetscSection coordSection; 1655 Vec coordinates; 1656 const PetscScalar *coords; 1657 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1658 PetscReal *refCoords, *edgeCoords; 1659 PetscBool isnull, drawAffine = PETSC_TRUE; 1660 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1661 1662 PetscFunctionBegin; 1663 PetscCall(DMGetCoordinateDim(dm, &dim)); 1664 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1665 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1666 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1667 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1668 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1669 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1670 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1671 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1672 1673 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1674 PetscCall(PetscDrawIsNull(draw, &isnull)); 1675 if (isnull) PetscFunctionReturn(0); 1676 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1677 1678 PetscCall(VecGetLocalSize(coordinates, &N)); 1679 PetscCall(VecGetArrayRead(coordinates, &coords)); 1680 for (c = 0; c < N; c += dim) { 1681 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1682 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1683 } 1684 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1685 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1686 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1687 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1688 PetscCall(PetscDrawClear(draw)); 1689 1690 for (c = cStart; c < cEnd; ++c) { 1691 PetscScalar *coords = NULL; 1692 PetscInt numCoords; 1693 1694 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1695 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1696 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1697 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1698 } 1699 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1700 PetscCall(PetscDrawFlush(draw)); 1701 PetscCall(PetscDrawPause(draw)); 1702 PetscCall(PetscDrawSave(draw)); 1703 PetscFunctionReturn(0); 1704 } 1705 1706 #if defined(PETSC_HAVE_EXODUSII) 1707 #include <exodusII.h> 1708 #include <petscviewerexodusii.h> 1709 #endif 1710 1711 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1712 { 1713 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1714 char name[PETSC_MAX_PATH_LEN]; 1715 1716 PetscFunctionBegin; 1717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1718 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1719 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1721 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1722 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1723 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1724 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1725 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 1726 if (iascii) { 1727 PetscViewerFormat format; 1728 PetscCall(PetscViewerGetFormat(viewer, &format)); 1729 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1730 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1731 } else if (ishdf5) { 1732 #if defined(PETSC_HAVE_HDF5) 1733 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1734 #else 1735 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1736 #endif 1737 } else if (isvtk) { 1738 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1739 } else if (isdraw) { 1740 PetscCall(DMPlexView_Draw(dm, viewer)); 1741 } else if (isglvis) { 1742 PetscCall(DMPlexView_GLVis(dm, viewer)); 1743 #if defined(PETSC_HAVE_EXODUSII) 1744 } else if (isexodus) { 1745 /* 1746 exodusII requires that all sets be part of exactly one cell set. 1747 If the dm does not have a "Cell Sets" label defined, we create one 1748 with ID 1, containig all cells. 1749 Note that if the Cell Sets label is defined but does not cover all cells, 1750 we may still have a problem. This should probably be checked here or in the viewer; 1751 */ 1752 PetscInt numCS; 1753 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1754 if (!numCS) { 1755 PetscInt cStart, cEnd, c; 1756 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1757 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1758 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1759 } 1760 PetscCall(DMView_PlexExodusII(dm, viewer)); 1761 #endif 1762 #if defined(PETSC_HAVE_CGNS) 1763 } else if (iscgns) { 1764 PetscCall(DMView_PlexCGNS(dm, viewer)); 1765 #endif 1766 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1767 /* Optionally view the partition */ 1768 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1769 if (flg) { 1770 Vec ranks; 1771 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1772 PetscCall(VecView(ranks, viewer)); 1773 PetscCall(VecDestroy(&ranks)); 1774 } 1775 /* Optionally view a label */ 1776 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1777 if (flg) { 1778 DMLabel label; 1779 Vec val; 1780 1781 PetscCall(DMGetLabel(dm, name, &label)); 1782 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1783 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1784 PetscCall(VecView(val, viewer)); 1785 PetscCall(VecDestroy(&val)); 1786 } 1787 PetscFunctionReturn(0); 1788 } 1789 1790 /*@ 1791 DMPlexTopologyView - Saves a DMPlex topology into a file 1792 1793 Collective on DM 1794 1795 Input Parameters: 1796 + dm - The DM whose topology is to be saved 1797 - viewer - The PetscViewer for saving 1798 1799 Level: advanced 1800 1801 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1802 @*/ 1803 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1804 { 1805 PetscBool ishdf5; 1806 1807 PetscFunctionBegin; 1808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1809 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1810 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1811 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1812 if (ishdf5) { 1813 #if defined(PETSC_HAVE_HDF5) 1814 PetscViewerFormat format; 1815 PetscCall(PetscViewerGetFormat(viewer, &format)); 1816 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1817 IS globalPointNumbering; 1818 1819 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1820 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1821 PetscCall(ISDestroy(&globalPointNumbering)); 1822 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1823 #else 1824 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1825 #endif 1826 } 1827 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1828 PetscFunctionReturn(0); 1829 } 1830 1831 /*@ 1832 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1833 1834 Collective on DM 1835 1836 Input Parameters: 1837 + dm - The DM whose coordinates are to be saved 1838 - viewer - The PetscViewer for saving 1839 1840 Level: advanced 1841 1842 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1843 @*/ 1844 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1845 { 1846 PetscBool ishdf5; 1847 1848 PetscFunctionBegin; 1849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1850 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1851 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1852 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1853 if (ishdf5) { 1854 #if defined(PETSC_HAVE_HDF5) 1855 PetscViewerFormat format; 1856 PetscCall(PetscViewerGetFormat(viewer, &format)); 1857 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1858 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1859 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1860 #else 1861 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1862 #endif 1863 } 1864 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1865 PetscFunctionReturn(0); 1866 } 1867 1868 /*@ 1869 DMPlexLabelsView - Saves DMPlex labels into a file 1870 1871 Collective on DM 1872 1873 Input Parameters: 1874 + dm - The DM whose labels are to be saved 1875 - viewer - The PetscViewer for saving 1876 1877 Level: advanced 1878 1879 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1880 @*/ 1881 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1882 { 1883 PetscBool ishdf5; 1884 1885 PetscFunctionBegin; 1886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1887 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1888 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1889 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1890 if (ishdf5) { 1891 #if defined(PETSC_HAVE_HDF5) 1892 IS globalPointNumbering; 1893 PetscViewerFormat format; 1894 1895 PetscCall(PetscViewerGetFormat(viewer, &format)); 1896 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1897 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1898 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1899 PetscCall(ISDestroy(&globalPointNumbering)); 1900 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1901 #else 1902 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1903 #endif 1904 } 1905 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1906 PetscFunctionReturn(0); 1907 } 1908 1909 /*@ 1910 DMPlexSectionView - Saves a section associated with a DMPlex 1911 1912 Collective on DM 1913 1914 Input Parameters: 1915 + dm - The DM that contains the topology on which the section to be saved is defined 1916 . viewer - The PetscViewer for saving 1917 - sectiondm - The DM that contains the section to be saved 1918 1919 Level: advanced 1920 1921 Notes: 1922 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. 1923 1924 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. 1925 1926 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1927 @*/ 1928 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1929 { 1930 PetscBool ishdf5; 1931 1932 PetscFunctionBegin; 1933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1934 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1935 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1936 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1937 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1938 if (ishdf5) { 1939 #if defined(PETSC_HAVE_HDF5) 1940 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1941 #else 1942 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1943 #endif 1944 } 1945 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1946 PetscFunctionReturn(0); 1947 } 1948 1949 /*@ 1950 DMPlexGlobalVectorView - Saves a global vector 1951 1952 Collective on DM 1953 1954 Input Parameters: 1955 + dm - The DM that represents the topology 1956 . viewer - The PetscViewer to save data with 1957 . sectiondm - The DM that contains the global section on which vec is defined 1958 - vec - The global vector to be saved 1959 1960 Level: advanced 1961 1962 Notes: 1963 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. 1964 1965 Typical calling sequence 1966 $ DMCreate(PETSC_COMM_WORLD, &dm); 1967 $ DMSetType(dm, DMPLEX); 1968 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1969 $ DMClone(dm, §iondm); 1970 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1971 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1972 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1973 $ PetscSectionSetChart(section, pStart, pEnd); 1974 $ PetscSectionSetUp(section); 1975 $ DMSetLocalSection(sectiondm, section); 1976 $ PetscSectionDestroy(§ion); 1977 $ DMGetGlobalVector(sectiondm, &vec); 1978 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1979 $ DMPlexTopologyView(dm, viewer); 1980 $ DMPlexSectionView(dm, viewer, sectiondm); 1981 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1982 $ DMRestoreGlobalVector(sectiondm, &vec); 1983 $ DMDestroy(§iondm); 1984 $ DMDestroy(&dm); 1985 1986 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1987 @*/ 1988 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1989 { 1990 PetscBool ishdf5; 1991 1992 PetscFunctionBegin; 1993 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1994 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1995 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1996 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1997 /* Check consistency */ 1998 { 1999 PetscSection section; 2000 PetscBool includesConstraints; 2001 PetscInt m, m1; 2002 2003 PetscCall(VecGetLocalSize(vec, &m1)); 2004 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2005 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2006 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2007 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2008 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2009 } 2010 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2011 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2012 if (ishdf5) { 2013 #if defined(PETSC_HAVE_HDF5) 2014 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2015 #else 2016 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2017 #endif 2018 } 2019 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2020 PetscFunctionReturn(0); 2021 } 2022 2023 /*@ 2024 DMPlexLocalVectorView - Saves a local vector 2025 2026 Collective on DM 2027 2028 Input Parameters: 2029 + dm - The DM that represents the topology 2030 . viewer - The PetscViewer to save data with 2031 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2032 - vec - The local vector to be saved 2033 2034 Level: advanced 2035 2036 Notes: 2037 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. 2038 2039 Typical calling sequence 2040 $ DMCreate(PETSC_COMM_WORLD, &dm); 2041 $ DMSetType(dm, DMPLEX); 2042 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2043 $ DMClone(dm, §iondm); 2044 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2045 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2046 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2047 $ PetscSectionSetChart(section, pStart, pEnd); 2048 $ PetscSectionSetUp(section); 2049 $ DMSetLocalSection(sectiondm, section); 2050 $ DMGetLocalVector(sectiondm, &vec); 2051 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2052 $ DMPlexTopologyView(dm, viewer); 2053 $ DMPlexSectionView(dm, viewer, sectiondm); 2054 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2055 $ DMRestoreLocalVector(sectiondm, &vec); 2056 $ DMDestroy(§iondm); 2057 $ DMDestroy(&dm); 2058 2059 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2060 @*/ 2061 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2062 { 2063 PetscBool ishdf5; 2064 2065 PetscFunctionBegin; 2066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2067 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2068 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2069 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2070 /* Check consistency */ 2071 { 2072 PetscSection section; 2073 PetscBool includesConstraints; 2074 PetscInt m, m1; 2075 2076 PetscCall(VecGetLocalSize(vec, &m1)); 2077 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2078 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2079 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2080 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2081 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2082 } 2083 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2084 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2085 if (ishdf5) { 2086 #if defined(PETSC_HAVE_HDF5) 2087 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2088 #else 2089 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2090 #endif 2091 } 2092 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2093 PetscFunctionReturn(0); 2094 } 2095 2096 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2097 { 2098 PetscBool ishdf5; 2099 2100 PetscFunctionBegin; 2101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2102 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2103 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2104 if (ishdf5) { 2105 #if defined(PETSC_HAVE_HDF5) 2106 PetscViewerFormat format; 2107 PetscCall(PetscViewerGetFormat(viewer, &format)); 2108 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2109 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2110 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2111 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2112 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2113 PetscFunctionReturn(0); 2114 #else 2115 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2116 #endif 2117 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2118 } 2119 2120 /*@ 2121 DMPlexTopologyLoad - Loads a topology into a DMPlex 2122 2123 Collective on DM 2124 2125 Input Parameters: 2126 + dm - The DM into which the topology is loaded 2127 - viewer - The PetscViewer for the saved topology 2128 2129 Output Parameters: 2130 . 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 2131 2132 Level: advanced 2133 2134 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2135 @*/ 2136 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2137 { 2138 PetscBool ishdf5; 2139 2140 PetscFunctionBegin; 2141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2142 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2143 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2144 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2145 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2146 if (ishdf5) { 2147 #if defined(PETSC_HAVE_HDF5) 2148 PetscViewerFormat format; 2149 PetscCall(PetscViewerGetFormat(viewer, &format)); 2150 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2151 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2152 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2153 #else 2154 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2155 #endif 2156 } 2157 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2158 PetscFunctionReturn(0); 2159 } 2160 2161 /*@ 2162 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2163 2164 Collective on DM 2165 2166 Input Parameters: 2167 + dm - The DM into which the coordinates are loaded 2168 . viewer - The PetscViewer for the saved coordinates 2169 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2170 2171 Level: advanced 2172 2173 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2174 @*/ 2175 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2176 { 2177 PetscBool ishdf5; 2178 2179 PetscFunctionBegin; 2180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2181 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2182 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2183 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2184 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2185 if (ishdf5) { 2186 #if defined(PETSC_HAVE_HDF5) 2187 PetscViewerFormat format; 2188 PetscCall(PetscViewerGetFormat(viewer, &format)); 2189 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2190 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2191 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2192 #else 2193 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2194 #endif 2195 } 2196 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2197 PetscFunctionReturn(0); 2198 } 2199 2200 /*@ 2201 DMPlexLabelsLoad - Loads labels into a DMPlex 2202 2203 Collective on DM 2204 2205 Input Parameters: 2206 + dm - The DM into which the labels are loaded 2207 . viewer - The PetscViewer for the saved labels 2208 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2209 2210 Level: advanced 2211 2212 Notes: 2213 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2214 2215 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2216 @*/ 2217 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2218 { 2219 PetscBool ishdf5; 2220 2221 PetscFunctionBegin; 2222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2223 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2224 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2225 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2226 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2227 if (ishdf5) { 2228 #if defined(PETSC_HAVE_HDF5) 2229 PetscViewerFormat format; 2230 2231 PetscCall(PetscViewerGetFormat(viewer, &format)); 2232 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2233 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2234 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2235 #else 2236 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2237 #endif 2238 } 2239 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2240 PetscFunctionReturn(0); 2241 } 2242 2243 /*@ 2244 DMPlexSectionLoad - Loads section into a DMPlex 2245 2246 Collective on DM 2247 2248 Input Parameters: 2249 + dm - The DM that represents the topology 2250 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2251 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2252 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2253 2254 Output Parameters 2255 + 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) 2256 - 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) 2257 2258 Level: advanced 2259 2260 Notes: 2261 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. 2262 2263 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. 2264 2265 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. 2266 2267 Example using 2 processes: 2268 $ NX (number of points on dm): 4 2269 $ sectionA : the on-disk section 2270 $ vecA : a vector associated with sectionA 2271 $ sectionB : sectiondm's local section constructed in this function 2272 $ vecB (local) : a vector associated with sectiondm's local section 2273 $ vecB (global) : a vector associated with sectiondm's global section 2274 $ 2275 $ rank 0 rank 1 2276 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2277 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2278 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2279 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2280 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2281 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2282 $ sectionB->atlasDof : 1 0 1 | 1 3 2283 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2284 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2285 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2286 $ 2287 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2288 2289 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2290 @*/ 2291 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2292 { 2293 PetscBool ishdf5; 2294 2295 PetscFunctionBegin; 2296 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2297 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2298 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2299 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2300 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2301 if (localDofSF) PetscValidPointer(localDofSF, 6); 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2303 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2307 #else 2308 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2309 #endif 2310 } 2311 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2312 PetscFunctionReturn(0); 2313 } 2314 2315 /*@ 2316 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2317 2318 Collective on DM 2319 2320 Input Parameters: 2321 + dm - The DM that represents the topology 2322 . viewer - The PetscViewer that represents the on-disk vector data 2323 . sectiondm - The DM that contains the global section on which vec is defined 2324 . sf - The SF that migrates the on-disk vector data into vec 2325 - vec - The global vector to set values of 2326 2327 Level: advanced 2328 2329 Notes: 2330 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. 2331 2332 Typical calling sequence 2333 $ DMCreate(PETSC_COMM_WORLD, &dm); 2334 $ DMSetType(dm, DMPLEX); 2335 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2336 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2337 $ DMClone(dm, §iondm); 2338 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2339 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2340 $ DMGetGlobalVector(sectiondm, &vec); 2341 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2342 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2343 $ DMRestoreGlobalVector(sectiondm, &vec); 2344 $ PetscSFDestroy(&gsf); 2345 $ PetscSFDestroy(&sfX); 2346 $ DMDestroy(§iondm); 2347 $ DMDestroy(&dm); 2348 2349 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2350 @*/ 2351 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2352 { 2353 PetscBool ishdf5; 2354 2355 PetscFunctionBegin; 2356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2357 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2358 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2359 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2360 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2361 /* Check consistency */ 2362 { 2363 PetscSection section; 2364 PetscBool includesConstraints; 2365 PetscInt m, m1; 2366 2367 PetscCall(VecGetLocalSize(vec, &m1)); 2368 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2369 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2370 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2371 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2372 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2373 } 2374 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2375 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2376 if (ishdf5) { 2377 #if defined(PETSC_HAVE_HDF5) 2378 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2379 #else 2380 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2381 #endif 2382 } 2383 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2384 PetscFunctionReturn(0); 2385 } 2386 2387 /*@ 2388 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2389 2390 Collective on DM 2391 2392 Input Parameters: 2393 + dm - The DM that represents the topology 2394 . viewer - The PetscViewer that represents the on-disk vector data 2395 . sectiondm - The DM that contains the local section on which vec is defined 2396 . sf - The SF that migrates the on-disk vector data into vec 2397 - vec - The local vector to set values of 2398 2399 Level: advanced 2400 2401 Notes: 2402 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. 2403 2404 Typical calling sequence 2405 $ DMCreate(PETSC_COMM_WORLD, &dm); 2406 $ DMSetType(dm, DMPLEX); 2407 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2408 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2409 $ DMClone(dm, §iondm); 2410 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2411 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2412 $ DMGetLocalVector(sectiondm, &vec); 2413 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2414 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2415 $ DMRestoreLocalVector(sectiondm, &vec); 2416 $ PetscSFDestroy(&lsf); 2417 $ PetscSFDestroy(&sfX); 2418 $ DMDestroy(§iondm); 2419 $ DMDestroy(&dm); 2420 2421 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2422 @*/ 2423 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2424 { 2425 PetscBool ishdf5; 2426 2427 PetscFunctionBegin; 2428 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2429 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2430 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2431 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2432 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2433 /* Check consistency */ 2434 { 2435 PetscSection section; 2436 PetscBool includesConstraints; 2437 PetscInt m, m1; 2438 2439 PetscCall(VecGetLocalSize(vec, &m1)); 2440 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2441 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2442 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2443 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2444 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2445 } 2446 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2447 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2448 if (ishdf5) { 2449 #if defined(PETSC_HAVE_HDF5) 2450 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2451 #else 2452 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2453 #endif 2454 } 2455 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2456 PetscFunctionReturn(0); 2457 } 2458 2459 PetscErrorCode DMDestroy_Plex(DM dm) 2460 { 2461 DM_Plex *mesh = (DM_Plex*) dm->data; 2462 2463 PetscFunctionBegin; 2464 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2465 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2466 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2467 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2468 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2469 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2470 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2471 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2472 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2473 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2474 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2475 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 2476 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL)); 2477 if (--mesh->refct > 0) PetscFunctionReturn(0); 2478 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2479 PetscCall(PetscFree(mesh->cones)); 2480 PetscCall(PetscFree(mesh->coneOrientations)); 2481 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2482 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2483 PetscCall(PetscFree(mesh->supports)); 2484 PetscCall(PetscFree(mesh->facesTmp)); 2485 PetscCall(PetscFree(mesh->tetgenOpts)); 2486 PetscCall(PetscFree(mesh->triangleOpts)); 2487 PetscCall(PetscFree(mesh->transformType)); 2488 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2489 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2490 PetscCall(ISDestroy(&mesh->subpointIS)); 2491 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2492 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2493 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2494 PetscCall(ISDestroy(&mesh->anchorIS)); 2495 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2496 PetscCall(PetscFree(mesh->parents)); 2497 PetscCall(PetscFree(mesh->childIDs)); 2498 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2499 PetscCall(PetscFree(mesh->children)); 2500 PetscCall(DMDestroy(&mesh->referenceTree)); 2501 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2502 PetscCall(PetscFree(mesh->neighbors)); 2503 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2504 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2505 PetscCall(PetscFree(mesh)); 2506 PetscFunctionReturn(0); 2507 } 2508 2509 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2510 { 2511 PetscSection sectionGlobal; 2512 PetscInt bs = -1, mbs; 2513 PetscInt localSize, localStart = 0; 2514 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2515 MatType mtype; 2516 ISLocalToGlobalMapping ltog; 2517 2518 PetscFunctionBegin; 2519 PetscCall(MatInitializePackage()); 2520 mtype = dm->mattype; 2521 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2522 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2523 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2524 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2525 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2526 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2527 PetscCall(MatSetType(*J, mtype)); 2528 PetscCall(MatSetFromOptions(*J)); 2529 PetscCall(MatGetBlockSize(*J, &mbs)); 2530 if (mbs > 1) bs = mbs; 2531 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2532 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2533 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2534 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2535 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2536 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2537 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2538 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2539 if (!isShell) { 2540 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2541 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2542 PetscInt pStart, pEnd, p, dof, cdof; 2543 2544 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2545 2546 PetscCall(PetscCalloc1(localSize, &pblocks)); 2547 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2548 for (p = pStart; p < pEnd; ++p) { 2549 PetscInt bdof, offset; 2550 2551 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2552 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2553 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2554 for (PetscInt i=0; i < dof - cdof; i++) 2555 pblocks[offset - localStart + i] = dof - cdof; 2556 dof = dof < 0 ? -(dof+1) : dof; 2557 bdof = cdof && (dof-cdof) ? 1 : dof; 2558 if (dof) { 2559 if (bs < 0) {bs = bdof;} 2560 else if (bs != bdof) {bs = 1;} 2561 } 2562 } 2563 /* Must have same blocksize on all procs (some might have no points) */ 2564 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2565 bsLocal[1] = bs; 2566 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2567 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2568 else bs = bsMinMax[0]; 2569 bs = PetscMax(1,bs); 2570 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2571 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2572 PetscCall(MatSetBlockSize(*J, bs)); 2573 PetscCall(MatSetUp(*J)); 2574 } else { 2575 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2576 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2577 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2578 } 2579 { // Consolidate blocks 2580 PetscInt nblocks = 0; 2581 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2582 if (pblocks[i] == 0) continue; 2583 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2584 for (PetscInt j=1; j<pblocks[i]; j++) { 2585 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]); 2586 } 2587 } 2588 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2589 } 2590 PetscCall(PetscFree(pblocks)); 2591 } 2592 PetscCall(MatSetDM(*J, dm)); 2593 PetscFunctionReturn(0); 2594 } 2595 2596 /*@ 2597 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2598 2599 Not collective 2600 2601 Input Parameter: 2602 . mesh - The DMPlex 2603 2604 Output Parameters: 2605 . subsection - The subdomain section 2606 2607 Level: developer 2608 2609 .seealso: 2610 @*/ 2611 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2612 { 2613 DM_Plex *mesh = (DM_Plex*) dm->data; 2614 2615 PetscFunctionBegin; 2616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2617 if (!mesh->subdomainSection) { 2618 PetscSection section; 2619 PetscSF sf; 2620 2621 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2622 PetscCall(DMGetLocalSection(dm,§ion)); 2623 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2624 PetscCall(PetscSFDestroy(&sf)); 2625 } 2626 *subsection = mesh->subdomainSection; 2627 PetscFunctionReturn(0); 2628 } 2629 2630 /*@ 2631 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2632 2633 Not collective 2634 2635 Input Parameter: 2636 . mesh - The DMPlex 2637 2638 Output Parameters: 2639 + pStart - The first mesh point 2640 - pEnd - The upper bound for mesh points 2641 2642 Level: beginner 2643 2644 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2645 @*/ 2646 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2647 { 2648 DM_Plex *mesh = (DM_Plex*) dm->data; 2649 2650 PetscFunctionBegin; 2651 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2652 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2653 PetscFunctionReturn(0); 2654 } 2655 2656 /*@ 2657 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2658 2659 Not collective 2660 2661 Input Parameters: 2662 + mesh - The DMPlex 2663 . pStart - The first mesh point 2664 - pEnd - The upper bound for mesh points 2665 2666 Output Parameters: 2667 2668 Level: beginner 2669 2670 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2671 @*/ 2672 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2673 { 2674 DM_Plex *mesh = (DM_Plex*) dm->data; 2675 2676 PetscFunctionBegin; 2677 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2678 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2679 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2680 PetscFunctionReturn(0); 2681 } 2682 2683 /*@ 2684 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2685 2686 Not collective 2687 2688 Input Parameters: 2689 + mesh - The DMPlex 2690 - p - The point, which must lie in the chart set with DMPlexSetChart() 2691 2692 Output Parameter: 2693 . size - The cone size for point p 2694 2695 Level: beginner 2696 2697 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2698 @*/ 2699 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2700 { 2701 DM_Plex *mesh = (DM_Plex*) dm->data; 2702 2703 PetscFunctionBegin; 2704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2705 PetscValidIntPointer(size, 3); 2706 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2707 PetscFunctionReturn(0); 2708 } 2709 2710 /*@ 2711 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2712 2713 Not collective 2714 2715 Input Parameters: 2716 + mesh - The DMPlex 2717 . p - The point, which must lie in the chart set with DMPlexSetChart() 2718 - size - The cone size for point p 2719 2720 Output Parameter: 2721 2722 Note: 2723 This should be called after DMPlexSetChart(). 2724 2725 Level: beginner 2726 2727 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2728 @*/ 2729 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2730 { 2731 DM_Plex *mesh = (DM_Plex*) dm->data; 2732 2733 PetscFunctionBegin; 2734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2735 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2736 PetscFunctionReturn(0); 2737 } 2738 2739 /*@ 2740 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2741 2742 Not collective 2743 2744 Input Parameters: 2745 + mesh - The DMPlex 2746 . p - The point, which must lie in the chart set with DMPlexSetChart() 2747 - size - The additional cone size for point p 2748 2749 Output Parameter: 2750 2751 Note: 2752 This should be called after DMPlexSetChart(). 2753 2754 Level: beginner 2755 2756 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2757 @*/ 2758 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2759 { 2760 DM_Plex *mesh = (DM_Plex*) dm->data; 2761 PetscFunctionBegin; 2762 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2763 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2764 PetscFunctionReturn(0); 2765 } 2766 2767 /*@C 2768 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2769 2770 Not collective 2771 2772 Input Parameters: 2773 + dm - The DMPlex 2774 - p - The point, which must lie in the chart set with DMPlexSetChart() 2775 2776 Output Parameter: 2777 . cone - An array of points which are on the in-edges for point p 2778 2779 Level: beginner 2780 2781 Fortran Notes: 2782 Since it returns an array, this routine is only available in Fortran 90, and you must 2783 include petsc.h90 in your code. 2784 You must also call DMPlexRestoreCone() after you finish using the returned array. 2785 DMPlexRestoreCone() is not needed/available in C. 2786 2787 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2788 @*/ 2789 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2790 { 2791 DM_Plex *mesh = (DM_Plex*) dm->data; 2792 PetscInt off; 2793 2794 PetscFunctionBegin; 2795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2796 PetscValidPointer(cone, 3); 2797 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2798 *cone = &mesh->cones[off]; 2799 PetscFunctionReturn(0); 2800 } 2801 2802 /*@C 2803 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2804 2805 Not collective 2806 2807 Input Parameters: 2808 + dm - The DMPlex 2809 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2810 2811 Output Parameters: 2812 + pConesSection - PetscSection describing the layout of pCones 2813 - pCones - An array of points which are on the in-edges for the point set p 2814 2815 Level: intermediate 2816 2817 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2818 @*/ 2819 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2820 { 2821 PetscSection cs, newcs; 2822 PetscInt *cones; 2823 PetscInt *newarr=NULL; 2824 PetscInt n; 2825 2826 PetscFunctionBegin; 2827 PetscCall(DMPlexGetCones(dm, &cones)); 2828 PetscCall(DMPlexGetConeSection(dm, &cs)); 2829 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2830 if (pConesSection) *pConesSection = newcs; 2831 if (pCones) { 2832 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2833 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2834 } 2835 PetscFunctionReturn(0); 2836 } 2837 2838 /*@ 2839 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2840 2841 Not collective 2842 2843 Input Parameters: 2844 + dm - The DMPlex 2845 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2846 2847 Output Parameter: 2848 . expandedPoints - An array of vertices recursively expanded from input points 2849 2850 Level: advanced 2851 2852 Notes: 2853 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2854 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2855 2856 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2857 @*/ 2858 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2859 { 2860 IS *expandedPointsAll; 2861 PetscInt depth; 2862 2863 PetscFunctionBegin; 2864 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2865 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2866 PetscValidPointer(expandedPoints, 3); 2867 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2868 *expandedPoints = expandedPointsAll[0]; 2869 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2870 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2871 PetscFunctionReturn(0); 2872 } 2873 2874 /*@ 2875 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). 2876 2877 Not collective 2878 2879 Input Parameters: 2880 + dm - The DMPlex 2881 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2882 2883 Output Parameters: 2884 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2885 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2886 - sections - (optional) An array of sections which describe mappings from points to their cone points 2887 2888 Level: advanced 2889 2890 Notes: 2891 Like DMPlexGetConeTuple() but recursive. 2892 2893 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. 2894 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2895 2896 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: 2897 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2898 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2899 2900 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2901 @*/ 2902 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2903 { 2904 const PetscInt *arr0=NULL, *cone=NULL; 2905 PetscInt *arr=NULL, *newarr=NULL; 2906 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2907 IS *expandedPoints_; 2908 PetscSection *sections_; 2909 2910 PetscFunctionBegin; 2911 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2912 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2913 if (depth) PetscValidIntPointer(depth, 3); 2914 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2915 if (sections) PetscValidPointer(sections, 5); 2916 PetscCall(ISGetLocalSize(points, &n)); 2917 PetscCall(ISGetIndices(points, &arr0)); 2918 PetscCall(DMPlexGetDepth(dm, &depth_)); 2919 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2920 PetscCall(PetscCalloc1(depth_, §ions_)); 2921 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2922 for (d=depth_-1; d>=0; d--) { 2923 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2924 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2925 for (i=0; i<n; i++) { 2926 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2927 if (arr[i] >= start && arr[i] < end) { 2928 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2929 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2930 } else { 2931 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2932 } 2933 } 2934 PetscCall(PetscSectionSetUp(sections_[d])); 2935 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2936 PetscCall(PetscMalloc1(newn, &newarr)); 2937 for (i=0; i<n; i++) { 2938 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2939 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2940 if (cn > 1) { 2941 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2942 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2943 } else { 2944 newarr[co] = arr[i]; 2945 } 2946 } 2947 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2948 arr = newarr; 2949 n = newn; 2950 } 2951 PetscCall(ISRestoreIndices(points, &arr0)); 2952 *depth = depth_; 2953 if (expandedPoints) *expandedPoints = expandedPoints_; 2954 else { 2955 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2956 PetscCall(PetscFree(expandedPoints_)); 2957 } 2958 if (sections) *sections = sections_; 2959 else { 2960 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2961 PetscCall(PetscFree(sections_)); 2962 } 2963 PetscFunctionReturn(0); 2964 } 2965 2966 /*@ 2967 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2968 2969 Not collective 2970 2971 Input Parameters: 2972 + dm - The DMPlex 2973 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2974 2975 Output Parameters: 2976 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2977 . expandedPoints - (optional) An array of recursively expanded cones 2978 - sections - (optional) An array of sections which describe mappings from points to their cone points 2979 2980 Level: advanced 2981 2982 Notes: 2983 See DMPlexGetConeRecursive() for details. 2984 2985 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2986 @*/ 2987 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2988 { 2989 PetscInt d, depth_; 2990 2991 PetscFunctionBegin; 2992 PetscCall(DMPlexGetDepth(dm, &depth_)); 2993 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2994 if (depth) *depth = 0; 2995 if (expandedPoints) { 2996 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2997 PetscCall(PetscFree(*expandedPoints)); 2998 } 2999 if (sections) { 3000 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3001 PetscCall(PetscFree(*sections)); 3002 } 3003 PetscFunctionReturn(0); 3004 } 3005 3006 /*@ 3007 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 3008 3009 Not collective 3010 3011 Input Parameters: 3012 + mesh - The DMPlex 3013 . p - The point, which must lie in the chart set with DMPlexSetChart() 3014 - cone - An array of points which are on the in-edges for point p 3015 3016 Output Parameter: 3017 3018 Note: 3019 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3020 3021 Level: beginner 3022 3023 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3024 @*/ 3025 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3026 { 3027 DM_Plex *mesh = (DM_Plex*) dm->data; 3028 PetscInt pStart, pEnd; 3029 PetscInt dof, off, c; 3030 3031 PetscFunctionBegin; 3032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3033 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3034 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3035 if (dof) PetscValidIntPointer(cone, 3); 3036 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3037 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); 3038 for (c = 0; c < dof; ++c) { 3039 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); 3040 mesh->cones[off+c] = cone[c]; 3041 } 3042 PetscFunctionReturn(0); 3043 } 3044 3045 /*@C 3046 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3047 3048 Not collective 3049 3050 Input Parameters: 3051 + mesh - The DMPlex 3052 - p - The point, which must lie in the chart set with DMPlexSetChart() 3053 3054 Output Parameter: 3055 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3056 integer giving the prescription for cone traversal. 3057 3058 Level: beginner 3059 3060 Notes: 3061 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3062 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3063 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3064 with the identity. 3065 3066 Fortran Notes: 3067 Since it returns an array, this routine is only available in Fortran 90, and you must 3068 include petsc.h90 in your code. 3069 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3070 DMPlexRestoreConeOrientation() is not needed/available in C. 3071 3072 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3073 @*/ 3074 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3075 { 3076 DM_Plex *mesh = (DM_Plex*) dm->data; 3077 PetscInt off; 3078 3079 PetscFunctionBegin; 3080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3081 if (PetscDefined(USE_DEBUG)) { 3082 PetscInt dof; 3083 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3084 if (dof) PetscValidPointer(coneOrientation, 3); 3085 } 3086 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3087 3088 *coneOrientation = &mesh->coneOrientations[off]; 3089 PetscFunctionReturn(0); 3090 } 3091 3092 /*@ 3093 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3094 3095 Not collective 3096 3097 Input Parameters: 3098 + mesh - The DMPlex 3099 . p - The point, which must lie in the chart set with DMPlexSetChart() 3100 - coneOrientation - An array of orientations 3101 Output Parameter: 3102 3103 Notes: 3104 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3105 3106 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3107 3108 Level: beginner 3109 3110 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3111 @*/ 3112 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3113 { 3114 DM_Plex *mesh = (DM_Plex*) dm->data; 3115 PetscInt pStart, pEnd; 3116 PetscInt dof, off, c; 3117 3118 PetscFunctionBegin; 3119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3120 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3121 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3122 if (dof) PetscValidIntPointer(coneOrientation, 3); 3123 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3124 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); 3125 for (c = 0; c < dof; ++c) { 3126 PetscInt cdof, o = coneOrientation[c]; 3127 3128 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3129 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); 3130 mesh->coneOrientations[off+c] = o; 3131 } 3132 PetscFunctionReturn(0); 3133 } 3134 3135 /*@ 3136 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3137 3138 Not collective 3139 3140 Input Parameters: 3141 + mesh - The DMPlex 3142 . p - The point, which must lie in the chart set with DMPlexSetChart() 3143 . conePos - The local index in the cone where the point should be put 3144 - conePoint - The mesh point to insert 3145 3146 Level: beginner 3147 3148 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3149 @*/ 3150 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3151 { 3152 DM_Plex *mesh = (DM_Plex*) dm->data; 3153 PetscInt pStart, pEnd; 3154 PetscInt dof, off; 3155 3156 PetscFunctionBegin; 3157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3158 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3159 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); 3160 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); 3161 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3162 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3163 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); 3164 mesh->cones[off+conePos] = conePoint; 3165 PetscFunctionReturn(0); 3166 } 3167 3168 /*@ 3169 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3170 3171 Not collective 3172 3173 Input Parameters: 3174 + mesh - The DMPlex 3175 . p - The point, which must lie in the chart set with DMPlexSetChart() 3176 . conePos - The local index in the cone where the point should be put 3177 - coneOrientation - The point orientation to insert 3178 3179 Level: beginner 3180 3181 Notes: 3182 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3183 3184 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3185 @*/ 3186 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3187 { 3188 DM_Plex *mesh = (DM_Plex*) dm->data; 3189 PetscInt pStart, pEnd; 3190 PetscInt dof, off; 3191 3192 PetscFunctionBegin; 3193 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3194 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3195 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); 3196 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3197 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3198 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); 3199 mesh->coneOrientations[off+conePos] = coneOrientation; 3200 PetscFunctionReturn(0); 3201 } 3202 3203 /*@ 3204 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3205 3206 Not collective 3207 3208 Input Parameters: 3209 + mesh - The DMPlex 3210 - p - The point, which must lie in the chart set with DMPlexSetChart() 3211 3212 Output Parameter: 3213 . size - The support size for point p 3214 3215 Level: beginner 3216 3217 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3218 @*/ 3219 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3220 { 3221 DM_Plex *mesh = (DM_Plex*) dm->data; 3222 3223 PetscFunctionBegin; 3224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3225 PetscValidIntPointer(size, 3); 3226 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3227 PetscFunctionReturn(0); 3228 } 3229 3230 /*@ 3231 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3232 3233 Not collective 3234 3235 Input Parameters: 3236 + mesh - The DMPlex 3237 . p - The point, which must lie in the chart set with DMPlexSetChart() 3238 - size - The support size for point p 3239 3240 Output Parameter: 3241 3242 Note: 3243 This should be called after DMPlexSetChart(). 3244 3245 Level: beginner 3246 3247 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3248 @*/ 3249 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3250 { 3251 DM_Plex *mesh = (DM_Plex*) dm->data; 3252 3253 PetscFunctionBegin; 3254 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3255 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3256 PetscFunctionReturn(0); 3257 } 3258 3259 /*@C 3260 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3261 3262 Not collective 3263 3264 Input Parameters: 3265 + mesh - The DMPlex 3266 - p - The point, which must lie in the chart set with DMPlexSetChart() 3267 3268 Output Parameter: 3269 . support - An array of points which are on the out-edges for point p 3270 3271 Level: beginner 3272 3273 Fortran Notes: 3274 Since it returns an array, this routine is only available in Fortran 90, and you must 3275 include petsc.h90 in your code. 3276 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3277 DMPlexRestoreSupport() is not needed/available in C. 3278 3279 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3280 @*/ 3281 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3282 { 3283 DM_Plex *mesh = (DM_Plex*) dm->data; 3284 PetscInt off; 3285 3286 PetscFunctionBegin; 3287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3288 PetscValidPointer(support, 3); 3289 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3290 *support = &mesh->supports[off]; 3291 PetscFunctionReturn(0); 3292 } 3293 3294 /*@ 3295 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3296 3297 Not collective 3298 3299 Input Parameters: 3300 + mesh - The DMPlex 3301 . p - The point, which must lie in the chart set with DMPlexSetChart() 3302 - support - An array of points which are on the out-edges for point p 3303 3304 Output Parameter: 3305 3306 Note: 3307 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3308 3309 Level: beginner 3310 3311 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3312 @*/ 3313 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3314 { 3315 DM_Plex *mesh = (DM_Plex*) dm->data; 3316 PetscInt pStart, pEnd; 3317 PetscInt dof, off, c; 3318 3319 PetscFunctionBegin; 3320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3321 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3322 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3323 if (dof) PetscValidIntPointer(support, 3); 3324 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3325 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); 3326 for (c = 0; c < dof; ++c) { 3327 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); 3328 mesh->supports[off+c] = support[c]; 3329 } 3330 PetscFunctionReturn(0); 3331 } 3332 3333 /*@ 3334 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3335 3336 Not collective 3337 3338 Input Parameters: 3339 + mesh - The DMPlex 3340 . p - The point, which must lie in the chart set with DMPlexSetChart() 3341 . supportPos - The local index in the cone where the point should be put 3342 - supportPoint - The mesh point to insert 3343 3344 Level: beginner 3345 3346 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3347 @*/ 3348 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3349 { 3350 DM_Plex *mesh = (DM_Plex*) dm->data; 3351 PetscInt pStart, pEnd; 3352 PetscInt dof, off; 3353 3354 PetscFunctionBegin; 3355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3356 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3357 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3358 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3359 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); 3360 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); 3361 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); 3362 mesh->supports[off+supportPos] = supportPoint; 3363 PetscFunctionReturn(0); 3364 } 3365 3366 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3367 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3368 { 3369 switch (ct) { 3370 case DM_POLYTOPE_SEGMENT: 3371 if (o == -1) return -2; 3372 break; 3373 case DM_POLYTOPE_TRIANGLE: 3374 if (o == -3) return -1; 3375 if (o == -2) return -3; 3376 if (o == -1) return -2; 3377 break; 3378 case DM_POLYTOPE_QUADRILATERAL: 3379 if (o == -4) return -2; 3380 if (o == -3) return -1; 3381 if (o == -2) return -4; 3382 if (o == -1) return -3; 3383 break; 3384 default: return o; 3385 } 3386 return o; 3387 } 3388 3389 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3390 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3391 { 3392 switch (ct) { 3393 case DM_POLYTOPE_SEGMENT: 3394 if ((o == -2) || (o == 1)) return -1; 3395 if (o == -1) return 0; 3396 break; 3397 case DM_POLYTOPE_TRIANGLE: 3398 if (o == -3) return -2; 3399 if (o == -2) return -1; 3400 if (o == -1) return -3; 3401 break; 3402 case DM_POLYTOPE_QUADRILATERAL: 3403 if (o == -4) return -2; 3404 if (o == -3) return -1; 3405 if (o == -2) return -4; 3406 if (o == -1) return -3; 3407 break; 3408 default: return o; 3409 } 3410 return o; 3411 } 3412 3413 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3414 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3415 { 3416 PetscInt pStart, pEnd, p; 3417 3418 PetscFunctionBegin; 3419 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3420 for (p = pStart; p < pEnd; ++p) { 3421 const PetscInt *cone, *ornt; 3422 PetscInt coneSize, c; 3423 3424 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3425 PetscCall(DMPlexGetCone(dm, p, &cone)); 3426 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3427 for (c = 0; c < coneSize; ++c) { 3428 DMPolytopeType ct; 3429 const PetscInt o = ornt[c]; 3430 3431 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3432 switch (ct) { 3433 case DM_POLYTOPE_SEGMENT: 3434 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3435 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3436 break; 3437 case DM_POLYTOPE_TRIANGLE: 3438 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3439 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3440 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3441 break; 3442 case DM_POLYTOPE_QUADRILATERAL: 3443 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3444 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3445 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3446 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3447 break; 3448 default: break; 3449 } 3450 } 3451 } 3452 PetscFunctionReturn(0); 3453 } 3454 3455 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3456 { 3457 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3458 PetscInt *closure; 3459 const PetscInt *tmp = NULL, *tmpO = NULL; 3460 PetscInt off = 0, tmpSize, t; 3461 3462 PetscFunctionBeginHot; 3463 if (ornt) { 3464 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3465 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3466 } 3467 if (*points) { 3468 closure = *points; 3469 } else { 3470 PetscInt maxConeSize, maxSupportSize; 3471 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3472 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3473 } 3474 if (useCone) { 3475 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3476 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3477 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3478 } else { 3479 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3480 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3481 } 3482 if (ct == DM_POLYTOPE_UNKNOWN) { 3483 closure[off++] = p; 3484 closure[off++] = 0; 3485 for (t = 0; t < tmpSize; ++t) { 3486 closure[off++] = tmp[t]; 3487 closure[off++] = tmpO ? tmpO[t] : 0; 3488 } 3489 } else { 3490 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3491 3492 /* We assume that cells with a valid type have faces with a valid type */ 3493 closure[off++] = p; 3494 closure[off++] = ornt; 3495 for (t = 0; t < tmpSize; ++t) { 3496 DMPolytopeType ft; 3497 3498 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3499 closure[off++] = tmp[arr[t]]; 3500 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3501 } 3502 } 3503 if (numPoints) *numPoints = tmpSize+1; 3504 if (points) *points = closure; 3505 PetscFunctionReturn(0); 3506 } 3507 3508 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3509 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3510 { 3511 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3512 const PetscInt *cone, *ornt; 3513 PetscInt *pts, *closure = NULL; 3514 DMPolytopeType ft; 3515 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3516 PetscInt dim, coneSize, c, d, clSize, cl; 3517 3518 PetscFunctionBeginHot; 3519 PetscCall(DMGetDimension(dm, &dim)); 3520 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3521 PetscCall(DMPlexGetCone(dm, point, &cone)); 3522 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3523 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3524 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3525 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3526 maxSize = PetscMax(coneSeries, supportSeries); 3527 if (*points) {pts = *points;} 3528 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3529 c = 0; 3530 pts[c++] = point; 3531 pts[c++] = o; 3532 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3533 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3534 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3535 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3536 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3537 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3538 for (d = 2; d < coneSize; ++d) { 3539 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3540 pts[c++] = cone[arr[d*2+0]]; 3541 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3542 } 3543 if (dim >= 3) { 3544 for (d = 2; d < coneSize; ++d) { 3545 const PetscInt fpoint = cone[arr[d*2+0]]; 3546 const PetscInt *fcone, *fornt; 3547 PetscInt fconeSize, fc, i; 3548 3549 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3550 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3551 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3552 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3553 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3554 for (fc = 0; fc < fconeSize; ++fc) { 3555 const PetscInt cp = fcone[farr[fc*2+0]]; 3556 const PetscInt co = farr[fc*2+1]; 3557 3558 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3559 if (i == c) { 3560 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3561 pts[c++] = cp; 3562 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3563 } 3564 } 3565 } 3566 } 3567 *numPoints = c/2; 3568 *points = pts; 3569 PetscFunctionReturn(0); 3570 } 3571 3572 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3573 { 3574 DMPolytopeType ct; 3575 PetscInt *closure, *fifo; 3576 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3577 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3578 PetscInt depth, maxSize; 3579 3580 PetscFunctionBeginHot; 3581 PetscCall(DMPlexGetDepth(dm, &depth)); 3582 if (depth == 1) { 3583 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3584 PetscFunctionReturn(0); 3585 } 3586 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3587 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3588 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3589 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3590 PetscFunctionReturn(0); 3591 } 3592 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3593 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3594 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3595 maxSize = PetscMax(coneSeries, supportSeries); 3596 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3597 if (*points) {closure = *points;} 3598 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3599 closure[closureSize++] = p; 3600 closure[closureSize++] = ornt; 3601 fifo[fifoSize++] = p; 3602 fifo[fifoSize++] = ornt; 3603 fifo[fifoSize++] = ct; 3604 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3605 while (fifoSize - fifoStart) { 3606 const PetscInt q = fifo[fifoStart++]; 3607 const PetscInt o = fifo[fifoStart++]; 3608 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3609 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3610 const PetscInt *tmp, *tmpO; 3611 PetscInt tmpSize, t; 3612 3613 if (PetscDefined(USE_DEBUG)) { 3614 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3615 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); 3616 } 3617 if (useCone) { 3618 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3619 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3620 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3621 } else { 3622 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3623 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3624 tmpO = NULL; 3625 } 3626 for (t = 0; t < tmpSize; ++t) { 3627 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3628 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3629 const PetscInt cp = tmp[ip]; 3630 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3631 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3632 PetscInt c; 3633 3634 /* Check for duplicate */ 3635 for (c = 0; c < closureSize; c += 2) { 3636 if (closure[c] == cp) break; 3637 } 3638 if (c == closureSize) { 3639 closure[closureSize++] = cp; 3640 closure[closureSize++] = co; 3641 fifo[fifoSize++] = cp; 3642 fifo[fifoSize++] = co; 3643 fifo[fifoSize++] = ct; 3644 } 3645 } 3646 } 3647 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3648 if (numPoints) *numPoints = closureSize/2; 3649 if (points) *points = closure; 3650 PetscFunctionReturn(0); 3651 } 3652 3653 /*@C 3654 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3655 3656 Not collective 3657 3658 Input Parameters: 3659 + dm - The DMPlex 3660 . p - The mesh point 3661 - useCone - PETSC_TRUE for the closure, otherwise return the star 3662 3663 Input/Output Parameter: 3664 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3665 if NULL on input, internal storage will be returned, otherwise the provided array is used 3666 3667 Output Parameter: 3668 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3669 3670 Note: 3671 If using internal storage (points is NULL on input), each call overwrites the last output. 3672 3673 Fortran Notes: 3674 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3675 3676 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3677 3678 Level: beginner 3679 3680 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3681 @*/ 3682 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3683 { 3684 PetscFunctionBeginHot; 3685 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3686 if (numPoints) PetscValidIntPointer(numPoints, 4); 3687 if (points) PetscValidPointer(points, 5); 3688 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3689 PetscFunctionReturn(0); 3690 } 3691 3692 /*@C 3693 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3694 3695 Not collective 3696 3697 Input Parameters: 3698 + dm - The DMPlex 3699 . p - The mesh point 3700 . useCone - PETSC_TRUE for the closure, otherwise return the star 3701 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3702 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3703 3704 Note: 3705 If not using internal storage (points is not NULL on input), this call is unnecessary 3706 3707 Fortran Notes: 3708 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3709 3710 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3711 3712 Level: beginner 3713 3714 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3715 @*/ 3716 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3717 { 3718 PetscFunctionBeginHot; 3719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3720 if (numPoints) *numPoints = 0; 3721 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3722 PetscFunctionReturn(0); 3723 } 3724 3725 /*@ 3726 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3727 3728 Not collective 3729 3730 Input Parameter: 3731 . mesh - The DMPlex 3732 3733 Output Parameters: 3734 + maxConeSize - The maximum number of in-edges 3735 - maxSupportSize - The maximum number of out-edges 3736 3737 Level: beginner 3738 3739 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3740 @*/ 3741 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3742 { 3743 DM_Plex *mesh = (DM_Plex*) dm->data; 3744 3745 PetscFunctionBegin; 3746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3747 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3748 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3749 PetscFunctionReturn(0); 3750 } 3751 3752 PetscErrorCode DMSetUp_Plex(DM dm) 3753 { 3754 DM_Plex *mesh = (DM_Plex*) dm->data; 3755 PetscInt size, maxSupportSize; 3756 3757 PetscFunctionBegin; 3758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3759 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3760 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3761 PetscCall(PetscMalloc1(size, &mesh->cones)); 3762 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3763 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3764 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3765 if (maxSupportSize) { 3766 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3767 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3768 PetscCall(PetscMalloc1(size, &mesh->supports)); 3769 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3770 } 3771 PetscFunctionReturn(0); 3772 } 3773 3774 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3775 { 3776 PetscFunctionBegin; 3777 if (subdm) PetscCall(DMClone(dm, subdm)); 3778 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3779 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3780 if (dm->useNatural && dm->sfMigration) { 3781 PetscSF sfMigrationInv,sfNatural; 3782 PetscSection section, sectionSeq; 3783 3784 (*subdm)->sfMigration = dm->sfMigration; 3785 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3786 PetscCall(DMGetLocalSection((*subdm), §ion)); 3787 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3788 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3789 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3790 3791 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3792 (*subdm)->sfNatural = sfNatural; 3793 PetscCall(PetscSectionDestroy(§ionSeq)); 3794 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3795 } 3796 PetscFunctionReturn(0); 3797 } 3798 3799 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3800 { 3801 PetscInt i = 0; 3802 3803 PetscFunctionBegin; 3804 PetscCall(DMClone(dms[0], superdm)); 3805 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3806 (*superdm)->useNatural = PETSC_FALSE; 3807 for (i = 0; i < len; i++) { 3808 if (dms[i]->useNatural && dms[i]->sfMigration) { 3809 PetscSF sfMigrationInv,sfNatural; 3810 PetscSection section, sectionSeq; 3811 3812 (*superdm)->sfMigration = dms[i]->sfMigration; 3813 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3814 (*superdm)->useNatural = PETSC_TRUE; 3815 PetscCall(DMGetLocalSection((*superdm), §ion)); 3816 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3817 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3818 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3819 3820 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3821 (*superdm)->sfNatural = sfNatural; 3822 PetscCall(PetscSectionDestroy(§ionSeq)); 3823 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3824 break; 3825 } 3826 } 3827 PetscFunctionReturn(0); 3828 } 3829 3830 /*@ 3831 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3832 3833 Not collective 3834 3835 Input Parameter: 3836 . mesh - The DMPlex 3837 3838 Output Parameter: 3839 3840 Note: 3841 This should be called after all calls to DMPlexSetCone() 3842 3843 Level: beginner 3844 3845 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3846 @*/ 3847 PetscErrorCode DMPlexSymmetrize(DM dm) 3848 { 3849 DM_Plex *mesh = (DM_Plex*) dm->data; 3850 PetscInt *offsets; 3851 PetscInt supportSize; 3852 PetscInt pStart, pEnd, p; 3853 3854 PetscFunctionBegin; 3855 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3856 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3857 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3858 /* Calculate support sizes */ 3859 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3860 for (p = pStart; p < pEnd; ++p) { 3861 PetscInt dof, off, c; 3862 3863 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3864 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3865 for (c = off; c < off+dof; ++c) { 3866 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3867 } 3868 } 3869 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3870 /* Calculate supports */ 3871 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3872 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3873 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3874 for (p = pStart; p < pEnd; ++p) { 3875 PetscInt dof, off, c; 3876 3877 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3878 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3879 for (c = off; c < off+dof; ++c) { 3880 const PetscInt q = mesh->cones[c]; 3881 PetscInt offS; 3882 3883 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3884 3885 mesh->supports[offS+offsets[q]] = p; 3886 ++offsets[q]; 3887 } 3888 } 3889 PetscCall(PetscFree(offsets)); 3890 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3891 PetscFunctionReturn(0); 3892 } 3893 3894 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3895 { 3896 IS stratumIS; 3897 3898 PetscFunctionBegin; 3899 if (pStart >= pEnd) PetscFunctionReturn(0); 3900 if (PetscDefined(USE_DEBUG)) { 3901 PetscInt qStart, qEnd, numLevels, level; 3902 PetscBool overlap = PETSC_FALSE; 3903 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3904 for (level = 0; level < numLevels; level++) { 3905 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3906 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3907 } 3908 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); 3909 } 3910 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3911 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3912 PetscCall(ISDestroy(&stratumIS)); 3913 PetscFunctionReturn(0); 3914 } 3915 3916 /*@ 3917 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3918 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3919 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3920 the DAG. 3921 3922 Collective on dm 3923 3924 Input Parameter: 3925 . mesh - The DMPlex 3926 3927 Output Parameter: 3928 3929 Notes: 3930 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3931 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3932 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3933 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3934 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3935 3936 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3937 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3938 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 3939 to interpolate only that one (e0), so that 3940 $ cone(c0) = {e0, v2} 3941 $ cone(e0) = {v0, v1} 3942 If DMPlexStratify() is run on this mesh, it will give depths 3943 $ depth 0 = {v0, v1, v2} 3944 $ depth 1 = {e0, c0} 3945 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3946 3947 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3948 3949 Level: beginner 3950 3951 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3952 @*/ 3953 PetscErrorCode DMPlexStratify(DM dm) 3954 { 3955 DM_Plex *mesh = (DM_Plex*) dm->data; 3956 DMLabel label; 3957 PetscInt pStart, pEnd, p; 3958 PetscInt numRoots = 0, numLeaves = 0; 3959 3960 PetscFunctionBegin; 3961 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3962 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3963 3964 /* Create depth label */ 3965 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3966 PetscCall(DMCreateLabel(dm, "depth")); 3967 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3968 3969 { 3970 /* Initialize roots and count leaves */ 3971 PetscInt sMin = PETSC_MAX_INT; 3972 PetscInt sMax = PETSC_MIN_INT; 3973 PetscInt coneSize, supportSize; 3974 3975 for (p = pStart; p < pEnd; ++p) { 3976 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3977 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3978 if (!coneSize && supportSize) { 3979 sMin = PetscMin(p, sMin); 3980 sMax = PetscMax(p, sMax); 3981 ++numRoots; 3982 } else if (!supportSize && coneSize) { 3983 ++numLeaves; 3984 } else if (!supportSize && !coneSize) { 3985 /* Isolated points */ 3986 sMin = PetscMin(p, sMin); 3987 sMax = PetscMax(p, sMax); 3988 } 3989 } 3990 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3991 } 3992 3993 if (numRoots + numLeaves == (pEnd - pStart)) { 3994 PetscInt sMin = PETSC_MAX_INT; 3995 PetscInt sMax = PETSC_MIN_INT; 3996 PetscInt coneSize, supportSize; 3997 3998 for (p = pStart; p < pEnd; ++p) { 3999 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4000 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4001 if (!supportSize && coneSize) { 4002 sMin = PetscMin(p, sMin); 4003 sMax = PetscMax(p, sMax); 4004 } 4005 } 4006 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 4007 } else { 4008 PetscInt level = 0; 4009 PetscInt qStart, qEnd, q; 4010 4011 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4012 while (qEnd > qStart) { 4013 PetscInt sMin = PETSC_MAX_INT; 4014 PetscInt sMax = PETSC_MIN_INT; 4015 4016 for (q = qStart; q < qEnd; ++q) { 4017 const PetscInt *support; 4018 PetscInt supportSize, s; 4019 4020 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4021 PetscCall(DMPlexGetSupport(dm, q, &support)); 4022 for (s = 0; s < supportSize; ++s) { 4023 sMin = PetscMin(support[s], sMin); 4024 sMax = PetscMax(support[s], sMax); 4025 } 4026 } 4027 PetscCall(DMLabelGetNumValues(label, &level)); 4028 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4029 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4030 } 4031 } 4032 { /* just in case there is an empty process */ 4033 PetscInt numValues, maxValues = 0, v; 4034 4035 PetscCall(DMLabelGetNumValues(label, &numValues)); 4036 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4037 for (v = numValues; v < maxValues; v++) { 4038 PetscCall(DMLabelAddStratum(label, v)); 4039 } 4040 } 4041 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4042 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4043 PetscFunctionReturn(0); 4044 } 4045 4046 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4047 { 4048 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4049 PetscInt dim, depth, pheight, coneSize; 4050 4051 PetscFunctionBeginHot; 4052 PetscCall(DMGetDimension(dm, &dim)); 4053 PetscCall(DMPlexGetDepth(dm, &depth)); 4054 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4055 pheight = depth - pdepth; 4056 if (depth <= 1) { 4057 switch (pdepth) { 4058 case 0: ct = DM_POLYTOPE_POINT;break; 4059 case 1: 4060 switch (coneSize) { 4061 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4062 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4063 case 4: 4064 switch (dim) { 4065 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4066 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4067 default: break; 4068 } 4069 break; 4070 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4071 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4072 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4073 default: break; 4074 } 4075 } 4076 } else { 4077 if (pdepth == 0) { 4078 ct = DM_POLYTOPE_POINT; 4079 } else if (pheight == 0) { 4080 switch (dim) { 4081 case 1: 4082 switch (coneSize) { 4083 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4084 default: break; 4085 } 4086 break; 4087 case 2: 4088 switch (coneSize) { 4089 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4090 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4091 default: break; 4092 } 4093 break; 4094 case 3: 4095 switch (coneSize) { 4096 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4097 case 5: 4098 { 4099 const PetscInt *cone; 4100 PetscInt faceConeSize; 4101 4102 PetscCall(DMPlexGetCone(dm, p, &cone)); 4103 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4104 switch (faceConeSize) { 4105 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4106 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4107 } 4108 } 4109 break; 4110 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4111 default: break; 4112 } 4113 break; 4114 default: break; 4115 } 4116 } else if (pheight > 0) { 4117 switch (coneSize) { 4118 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4119 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4120 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4121 default: break; 4122 } 4123 } 4124 } 4125 *pt = ct; 4126 PetscFunctionReturn(0); 4127 } 4128 4129 /*@ 4130 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4131 4132 Collective on dm 4133 4134 Input Parameter: 4135 . mesh - The DMPlex 4136 4137 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4138 4139 Level: developer 4140 4141 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4142 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4143 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4144 4145 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4146 @*/ 4147 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4148 { 4149 DM_Plex *mesh; 4150 DMLabel ctLabel; 4151 PetscInt pStart, pEnd, p; 4152 4153 PetscFunctionBegin; 4154 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4155 mesh = (DM_Plex *) dm->data; 4156 PetscCall(DMCreateLabel(dm, "celltype")); 4157 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4158 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4159 for (p = pStart; p < pEnd; ++p) { 4160 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4161 PetscInt pdepth; 4162 4163 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4164 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4165 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4166 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4167 } 4168 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4169 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4170 PetscFunctionReturn(0); 4171 } 4172 4173 /*@C 4174 DMPlexGetJoin - Get an array for the join of the set of points 4175 4176 Not Collective 4177 4178 Input Parameters: 4179 + dm - The DMPlex object 4180 . numPoints - The number of input points for the join 4181 - points - The input points 4182 4183 Output Parameters: 4184 + numCoveredPoints - The number of points in the join 4185 - coveredPoints - The points in the join 4186 4187 Level: intermediate 4188 4189 Note: Currently, this is restricted to a single level join 4190 4191 Fortran Notes: 4192 Since it returns an array, this routine is only available in Fortran 90, and you must 4193 include petsc.h90 in your code. 4194 4195 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4196 4197 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4198 @*/ 4199 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4200 { 4201 DM_Plex *mesh = (DM_Plex*) dm->data; 4202 PetscInt *join[2]; 4203 PetscInt joinSize, i = 0; 4204 PetscInt dof, off, p, c, m; 4205 PetscInt maxSupportSize; 4206 4207 PetscFunctionBegin; 4208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4209 PetscValidIntPointer(points, 3); 4210 PetscValidIntPointer(numCoveredPoints, 4); 4211 PetscValidPointer(coveredPoints, 5); 4212 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4213 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4214 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4215 /* Copy in support of first point */ 4216 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4217 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4218 for (joinSize = 0; joinSize < dof; ++joinSize) { 4219 join[i][joinSize] = mesh->supports[off+joinSize]; 4220 } 4221 /* Check each successive support */ 4222 for (p = 1; p < numPoints; ++p) { 4223 PetscInt newJoinSize = 0; 4224 4225 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4226 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4227 for (c = 0; c < dof; ++c) { 4228 const PetscInt point = mesh->supports[off+c]; 4229 4230 for (m = 0; m < joinSize; ++m) { 4231 if (point == join[i][m]) { 4232 join[1-i][newJoinSize++] = point; 4233 break; 4234 } 4235 } 4236 } 4237 joinSize = newJoinSize; 4238 i = 1-i; 4239 } 4240 *numCoveredPoints = joinSize; 4241 *coveredPoints = join[i]; 4242 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4243 PetscFunctionReturn(0); 4244 } 4245 4246 /*@C 4247 DMPlexRestoreJoin - Restore an array for the join of the set of points 4248 4249 Not Collective 4250 4251 Input Parameters: 4252 + dm - The DMPlex object 4253 . numPoints - The number of input points for the join 4254 - points - The input points 4255 4256 Output Parameters: 4257 + numCoveredPoints - The number of points in the join 4258 - coveredPoints - The points in the join 4259 4260 Fortran Notes: 4261 Since it returns an array, this routine is only available in Fortran 90, and you must 4262 include petsc.h90 in your code. 4263 4264 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4265 4266 Level: intermediate 4267 4268 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4269 @*/ 4270 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4271 { 4272 PetscFunctionBegin; 4273 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4274 if (points) PetscValidIntPointer(points,3); 4275 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4276 PetscValidPointer(coveredPoints, 5); 4277 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4278 if (numCoveredPoints) *numCoveredPoints = 0; 4279 PetscFunctionReturn(0); 4280 } 4281 4282 /*@C 4283 DMPlexGetFullJoin - Get an array for the join of the set of points 4284 4285 Not Collective 4286 4287 Input Parameters: 4288 + dm - The DMPlex object 4289 . numPoints - The number of input points for the join 4290 - points - The input points 4291 4292 Output Parameters: 4293 + numCoveredPoints - The number of points in the join 4294 - coveredPoints - The points in the join 4295 4296 Fortran Notes: 4297 Since it returns an array, this routine is only available in Fortran 90, and you must 4298 include petsc.h90 in your code. 4299 4300 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4301 4302 Level: intermediate 4303 4304 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4305 @*/ 4306 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4307 { 4308 PetscInt *offsets, **closures; 4309 PetscInt *join[2]; 4310 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4311 PetscInt p, d, c, m, ms; 4312 4313 PetscFunctionBegin; 4314 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4315 PetscValidIntPointer(points, 3); 4316 PetscValidIntPointer(numCoveredPoints, 4); 4317 PetscValidPointer(coveredPoints, 5); 4318 4319 PetscCall(DMPlexGetDepth(dm, &depth)); 4320 PetscCall(PetscCalloc1(numPoints, &closures)); 4321 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4322 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4323 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4324 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4325 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4326 4327 for (p = 0; p < numPoints; ++p) { 4328 PetscInt closureSize; 4329 4330 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4331 4332 offsets[p*(depth+2)+0] = 0; 4333 for (d = 0; d < depth+1; ++d) { 4334 PetscInt pStart, pEnd, i; 4335 4336 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4337 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4338 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4339 offsets[p*(depth+2)+d+1] = i; 4340 break; 4341 } 4342 } 4343 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4344 } 4345 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); 4346 } 4347 for (d = 0; d < depth+1; ++d) { 4348 PetscInt dof; 4349 4350 /* Copy in support of first point */ 4351 dof = offsets[d+1] - offsets[d]; 4352 for (joinSize = 0; joinSize < dof; ++joinSize) { 4353 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4354 } 4355 /* Check each successive cone */ 4356 for (p = 1; p < numPoints && joinSize; ++p) { 4357 PetscInt newJoinSize = 0; 4358 4359 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4360 for (c = 0; c < dof; ++c) { 4361 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4362 4363 for (m = 0; m < joinSize; ++m) { 4364 if (point == join[i][m]) { 4365 join[1-i][newJoinSize++] = point; 4366 break; 4367 } 4368 } 4369 } 4370 joinSize = newJoinSize; 4371 i = 1-i; 4372 } 4373 if (joinSize) break; 4374 } 4375 *numCoveredPoints = joinSize; 4376 *coveredPoints = join[i]; 4377 for (p = 0; p < numPoints; ++p) { 4378 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4379 } 4380 PetscCall(PetscFree(closures)); 4381 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4382 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4383 PetscFunctionReturn(0); 4384 } 4385 4386 /*@C 4387 DMPlexGetMeet - Get an array for the meet of the set of points 4388 4389 Not Collective 4390 4391 Input Parameters: 4392 + dm - The DMPlex object 4393 . numPoints - The number of input points for the meet 4394 - points - The input points 4395 4396 Output Parameters: 4397 + numCoveredPoints - The number of points in the meet 4398 - coveredPoints - The points in the meet 4399 4400 Level: intermediate 4401 4402 Note: Currently, this is restricted to a single level meet 4403 4404 Fortran Notes: 4405 Since it returns an array, this routine is only available in Fortran 90, and you must 4406 include petsc.h90 in your code. 4407 4408 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4409 4410 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4411 @*/ 4412 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4413 { 4414 DM_Plex *mesh = (DM_Plex*) dm->data; 4415 PetscInt *meet[2]; 4416 PetscInt meetSize, i = 0; 4417 PetscInt dof, off, p, c, m; 4418 PetscInt maxConeSize; 4419 4420 PetscFunctionBegin; 4421 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4422 PetscValidIntPointer(points, 3); 4423 PetscValidIntPointer(numCoveringPoints, 4); 4424 PetscValidPointer(coveringPoints, 5); 4425 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4426 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4427 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4428 /* Copy in cone of first point */ 4429 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4430 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4431 for (meetSize = 0; meetSize < dof; ++meetSize) { 4432 meet[i][meetSize] = mesh->cones[off+meetSize]; 4433 } 4434 /* Check each successive cone */ 4435 for (p = 1; p < numPoints; ++p) { 4436 PetscInt newMeetSize = 0; 4437 4438 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4439 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4440 for (c = 0; c < dof; ++c) { 4441 const PetscInt point = mesh->cones[off+c]; 4442 4443 for (m = 0; m < meetSize; ++m) { 4444 if (point == meet[i][m]) { 4445 meet[1-i][newMeetSize++] = point; 4446 break; 4447 } 4448 } 4449 } 4450 meetSize = newMeetSize; 4451 i = 1-i; 4452 } 4453 *numCoveringPoints = meetSize; 4454 *coveringPoints = meet[i]; 4455 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4456 PetscFunctionReturn(0); 4457 } 4458 4459 /*@C 4460 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4461 4462 Not Collective 4463 4464 Input Parameters: 4465 + dm - The DMPlex object 4466 . numPoints - The number of input points for the meet 4467 - points - The input points 4468 4469 Output Parameters: 4470 + numCoveredPoints - The number of points in the meet 4471 - coveredPoints - The points in the meet 4472 4473 Level: intermediate 4474 4475 Fortran Notes: 4476 Since it returns an array, this routine is only available in Fortran 90, and you must 4477 include petsc.h90 in your code. 4478 4479 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4480 4481 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4482 @*/ 4483 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4484 { 4485 PetscFunctionBegin; 4486 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4487 if (points) PetscValidIntPointer(points,3); 4488 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4489 PetscValidPointer(coveredPoints,5); 4490 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4491 if (numCoveredPoints) *numCoveredPoints = 0; 4492 PetscFunctionReturn(0); 4493 } 4494 4495 /*@C 4496 DMPlexGetFullMeet - Get an array for the meet of the set of points 4497 4498 Not Collective 4499 4500 Input Parameters: 4501 + dm - The DMPlex object 4502 . numPoints - The number of input points for the meet 4503 - points - The input points 4504 4505 Output Parameters: 4506 + numCoveredPoints - The number of points in the meet 4507 - coveredPoints - The points in the meet 4508 4509 Level: intermediate 4510 4511 Fortran Notes: 4512 Since it returns an array, this routine is only available in Fortran 90, and you must 4513 include petsc.h90 in your code. 4514 4515 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4516 4517 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4518 @*/ 4519 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4520 { 4521 PetscInt *offsets, **closures; 4522 PetscInt *meet[2]; 4523 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4524 PetscInt p, h, c, m, mc; 4525 4526 PetscFunctionBegin; 4527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4528 PetscValidIntPointer(points, 3); 4529 PetscValidIntPointer(numCoveredPoints, 4); 4530 PetscValidPointer(coveredPoints, 5); 4531 4532 PetscCall(DMPlexGetDepth(dm, &height)); 4533 PetscCall(PetscMalloc1(numPoints, &closures)); 4534 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4535 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4536 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4537 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4538 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4539 4540 for (p = 0; p < numPoints; ++p) { 4541 PetscInt closureSize; 4542 4543 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4544 4545 offsets[p*(height+2)+0] = 0; 4546 for (h = 0; h < height+1; ++h) { 4547 PetscInt pStart, pEnd, i; 4548 4549 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4550 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4551 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4552 offsets[p*(height+2)+h+1] = i; 4553 break; 4554 } 4555 } 4556 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4557 } 4558 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); 4559 } 4560 for (h = 0; h < height+1; ++h) { 4561 PetscInt dof; 4562 4563 /* Copy in cone of first point */ 4564 dof = offsets[h+1] - offsets[h]; 4565 for (meetSize = 0; meetSize < dof; ++meetSize) { 4566 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4567 } 4568 /* Check each successive cone */ 4569 for (p = 1; p < numPoints && meetSize; ++p) { 4570 PetscInt newMeetSize = 0; 4571 4572 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4573 for (c = 0; c < dof; ++c) { 4574 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4575 4576 for (m = 0; m < meetSize; ++m) { 4577 if (point == meet[i][m]) { 4578 meet[1-i][newMeetSize++] = point; 4579 break; 4580 } 4581 } 4582 } 4583 meetSize = newMeetSize; 4584 i = 1-i; 4585 } 4586 if (meetSize) break; 4587 } 4588 *numCoveredPoints = meetSize; 4589 *coveredPoints = meet[i]; 4590 for (p = 0; p < numPoints; ++p) { 4591 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4592 } 4593 PetscCall(PetscFree(closures)); 4594 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4595 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4596 PetscFunctionReturn(0); 4597 } 4598 4599 /*@C 4600 DMPlexEqual - Determine if two DMs have the same topology 4601 4602 Not Collective 4603 4604 Input Parameters: 4605 + dmA - A DMPlex object 4606 - dmB - A DMPlex object 4607 4608 Output Parameters: 4609 . equal - PETSC_TRUE if the topologies are identical 4610 4611 Level: intermediate 4612 4613 Notes: 4614 We are not solving graph isomorphism, so we do not permutation. 4615 4616 .seealso: `DMPlexGetCone()` 4617 @*/ 4618 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4619 { 4620 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4621 4622 PetscFunctionBegin; 4623 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4624 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4625 PetscValidBoolPointer(equal, 3); 4626 4627 *equal = PETSC_FALSE; 4628 PetscCall(DMPlexGetDepth(dmA, &depth)); 4629 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4630 if (depth != depthB) PetscFunctionReturn(0); 4631 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4632 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4633 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4634 for (p = pStart; p < pEnd; ++p) { 4635 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4636 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4637 4638 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4639 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4640 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4641 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4642 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4643 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4644 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4645 for (c = 0; c < coneSize; ++c) { 4646 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4647 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4648 } 4649 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4650 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4651 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4652 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4653 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4654 for (s = 0; s < supportSize; ++s) { 4655 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4656 } 4657 } 4658 *equal = PETSC_TRUE; 4659 PetscFunctionReturn(0); 4660 } 4661 4662 /*@C 4663 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4664 4665 Not Collective 4666 4667 Input Parameters: 4668 + dm - The DMPlex 4669 . cellDim - The cell dimension 4670 - numCorners - The number of vertices on a cell 4671 4672 Output Parameters: 4673 . numFaceVertices - The number of vertices on a face 4674 4675 Level: developer 4676 4677 Notes: 4678 Of course this can only work for a restricted set of symmetric shapes 4679 4680 .seealso: `DMPlexGetCone()` 4681 @*/ 4682 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4683 { 4684 MPI_Comm comm; 4685 4686 PetscFunctionBegin; 4687 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4688 PetscValidIntPointer(numFaceVertices,4); 4689 switch (cellDim) { 4690 case 0: 4691 *numFaceVertices = 0; 4692 break; 4693 case 1: 4694 *numFaceVertices = 1; 4695 break; 4696 case 2: 4697 switch (numCorners) { 4698 case 3: /* triangle */ 4699 *numFaceVertices = 2; /* Edge has 2 vertices */ 4700 break; 4701 case 4: /* quadrilateral */ 4702 *numFaceVertices = 2; /* Edge has 2 vertices */ 4703 break; 4704 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4705 *numFaceVertices = 3; /* Edge has 3 vertices */ 4706 break; 4707 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4708 *numFaceVertices = 3; /* Edge has 3 vertices */ 4709 break; 4710 default: 4711 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4712 } 4713 break; 4714 case 3: 4715 switch (numCorners) { 4716 case 4: /* tetradehdron */ 4717 *numFaceVertices = 3; /* Face has 3 vertices */ 4718 break; 4719 case 6: /* tet cohesive cells */ 4720 *numFaceVertices = 4; /* Face has 4 vertices */ 4721 break; 4722 case 8: /* hexahedron */ 4723 *numFaceVertices = 4; /* Face has 4 vertices */ 4724 break; 4725 case 9: /* tet cohesive Lagrange cells */ 4726 *numFaceVertices = 6; /* Face has 6 vertices */ 4727 break; 4728 case 10: /* quadratic tetrahedron */ 4729 *numFaceVertices = 6; /* Face has 6 vertices */ 4730 break; 4731 case 12: /* hex cohesive Lagrange cells */ 4732 *numFaceVertices = 6; /* Face has 6 vertices */ 4733 break; 4734 case 18: /* quadratic tet cohesive Lagrange cells */ 4735 *numFaceVertices = 6; /* Face has 6 vertices */ 4736 break; 4737 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4738 *numFaceVertices = 9; /* Face has 9 vertices */ 4739 break; 4740 default: 4741 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4742 } 4743 break; 4744 default: 4745 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4746 } 4747 PetscFunctionReturn(0); 4748 } 4749 4750 /*@ 4751 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4752 4753 Not Collective 4754 4755 Input Parameter: 4756 . dm - The DMPlex object 4757 4758 Output Parameter: 4759 . depthLabel - The DMLabel recording point depth 4760 4761 Level: developer 4762 4763 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4764 @*/ 4765 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4766 { 4767 PetscFunctionBegin; 4768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4769 PetscValidPointer(depthLabel, 2); 4770 *depthLabel = dm->depthLabel; 4771 PetscFunctionReturn(0); 4772 } 4773 4774 /*@ 4775 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4776 4777 Not Collective 4778 4779 Input Parameter: 4780 . dm - The DMPlex object 4781 4782 Output Parameter: 4783 . depth - The number of strata (breadth first levels) in the DAG 4784 4785 Level: developer 4786 4787 Notes: 4788 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4789 The point depth is described more in detail in DMPlexGetDepthStratum(). 4790 An empty mesh gives -1. 4791 4792 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4793 @*/ 4794 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4795 { 4796 DMLabel label; 4797 PetscInt d = 0; 4798 4799 PetscFunctionBegin; 4800 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4801 PetscValidIntPointer(depth, 2); 4802 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4803 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4804 *depth = d-1; 4805 PetscFunctionReturn(0); 4806 } 4807 4808 /*@ 4809 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4810 4811 Not Collective 4812 4813 Input Parameters: 4814 + dm - The DMPlex object 4815 - depth - The requested depth 4816 4817 Output Parameters: 4818 + start - The first point at this depth 4819 - end - One beyond the last point at this depth 4820 4821 Notes: 4822 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4823 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4824 higher dimension, e.g., "edges". 4825 4826 Level: developer 4827 4828 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4829 @*/ 4830 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4831 { 4832 DMLabel label; 4833 PetscInt pStart, pEnd; 4834 4835 PetscFunctionBegin; 4836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4837 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4838 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4839 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4840 if (pStart == pEnd) PetscFunctionReturn(0); 4841 if (depth < 0) { 4842 if (start) *start = pStart; 4843 if (end) *end = pEnd; 4844 PetscFunctionReturn(0); 4845 } 4846 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4847 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4848 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4849 PetscFunctionReturn(0); 4850 } 4851 4852 /*@ 4853 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4854 4855 Not Collective 4856 4857 Input Parameters: 4858 + dm - The DMPlex object 4859 - height - The requested height 4860 4861 Output Parameters: 4862 + start - The first point at this height 4863 - end - One beyond the last point at this height 4864 4865 Notes: 4866 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4867 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4868 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4869 4870 Level: developer 4871 4872 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4873 @*/ 4874 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4875 { 4876 DMLabel label; 4877 PetscInt depth, pStart, pEnd; 4878 4879 PetscFunctionBegin; 4880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4881 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4882 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4883 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4884 if (pStart == pEnd) PetscFunctionReturn(0); 4885 if (height < 0) { 4886 if (start) *start = pStart; 4887 if (end) *end = pEnd; 4888 PetscFunctionReturn(0); 4889 } 4890 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4891 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4892 PetscCall(DMLabelGetNumValues(label, &depth)); 4893 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4894 PetscFunctionReturn(0); 4895 } 4896 4897 /*@ 4898 DMPlexGetPointDepth - Get the depth of a given point 4899 4900 Not Collective 4901 4902 Input Parameters: 4903 + dm - The DMPlex object 4904 - point - The point 4905 4906 Output Parameter: 4907 . depth - The depth of the point 4908 4909 Level: intermediate 4910 4911 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4912 @*/ 4913 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4914 { 4915 PetscFunctionBegin; 4916 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4917 PetscValidIntPointer(depth, 3); 4918 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4919 PetscFunctionReturn(0); 4920 } 4921 4922 /*@ 4923 DMPlexGetPointHeight - Get the height of a given point 4924 4925 Not Collective 4926 4927 Input Parameters: 4928 + dm - The DMPlex object 4929 - point - The point 4930 4931 Output Parameter: 4932 . height - The height of the point 4933 4934 Level: intermediate 4935 4936 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4937 @*/ 4938 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4939 { 4940 PetscInt n, pDepth; 4941 4942 PetscFunctionBegin; 4943 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4944 PetscValidIntPointer(height, 3); 4945 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4946 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4947 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4948 PetscFunctionReturn(0); 4949 } 4950 4951 /*@ 4952 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4953 4954 Not Collective 4955 4956 Input Parameter: 4957 . dm - The DMPlex object 4958 4959 Output Parameter: 4960 . celltypeLabel - The DMLabel recording cell polytope type 4961 4962 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4963 DMCreateLabel(dm, "celltype") beforehand. 4964 4965 Level: developer 4966 4967 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4968 @*/ 4969 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4970 { 4971 PetscFunctionBegin; 4972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4973 PetscValidPointer(celltypeLabel, 2); 4974 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4975 *celltypeLabel = dm->celltypeLabel; 4976 PetscFunctionReturn(0); 4977 } 4978 4979 /*@ 4980 DMPlexGetCellType - Get the polytope type of a given cell 4981 4982 Not Collective 4983 4984 Input Parameters: 4985 + dm - The DMPlex object 4986 - cell - The cell 4987 4988 Output Parameter: 4989 . celltype - The polytope type of the cell 4990 4991 Level: intermediate 4992 4993 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4994 @*/ 4995 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4996 { 4997 DMLabel label; 4998 PetscInt ct; 4999 5000 PetscFunctionBegin; 5001 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5002 PetscValidPointer(celltype, 3); 5003 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5004 PetscCall(DMLabelGetValue(label, cell, &ct)); 5005 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5006 *celltype = (DMPolytopeType) ct; 5007 PetscFunctionReturn(0); 5008 } 5009 5010 /*@ 5011 DMPlexSetCellType - Set the polytope type of a given cell 5012 5013 Not Collective 5014 5015 Input Parameters: 5016 + dm - The DMPlex object 5017 . cell - The cell 5018 - celltype - The polytope type of the cell 5019 5020 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5021 is executed. This function will override the computed type. However, if automatic classification will not succeed 5022 and a user wants to manually specify all types, the classification must be disabled by calling 5023 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5024 5025 Level: advanced 5026 5027 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5028 @*/ 5029 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5030 { 5031 DMLabel label; 5032 5033 PetscFunctionBegin; 5034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5035 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5036 PetscCall(DMLabelSetValue(label, cell, celltype)); 5037 PetscFunctionReturn(0); 5038 } 5039 5040 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5041 { 5042 PetscSection section, s; 5043 Mat m; 5044 PetscInt maxHeight; 5045 5046 PetscFunctionBegin; 5047 PetscCall(DMClone(dm, cdm)); 5048 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5049 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5050 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5051 PetscCall(DMSetLocalSection(*cdm, section)); 5052 PetscCall(PetscSectionDestroy(§ion)); 5053 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5054 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5055 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5056 PetscCall(PetscSectionDestroy(&s)); 5057 PetscCall(MatDestroy(&m)); 5058 5059 PetscCall(DMSetNumFields(*cdm, 1)); 5060 PetscCall(DMCreateDS(*cdm)); 5061 PetscFunctionReturn(0); 5062 } 5063 5064 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5065 { 5066 Vec coordsLocal, cellCoordsLocal; 5067 DM coordsDM, cellCoordsDM; 5068 5069 PetscFunctionBegin; 5070 *field = NULL; 5071 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5072 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5073 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5074 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5075 if (coordsLocal && coordsDM) { 5076 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5077 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5078 } 5079 PetscFunctionReturn(0); 5080 } 5081 5082 /*@C 5083 DMPlexGetConeSection - Return a section which describes the layout of cone data 5084 5085 Not Collective 5086 5087 Input Parameters: 5088 . dm - The DMPlex object 5089 5090 Output Parameter: 5091 . section - The PetscSection object 5092 5093 Level: developer 5094 5095 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5096 @*/ 5097 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5098 { 5099 DM_Plex *mesh = (DM_Plex*) dm->data; 5100 5101 PetscFunctionBegin; 5102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5103 if (section) *section = mesh->coneSection; 5104 PetscFunctionReturn(0); 5105 } 5106 5107 /*@C 5108 DMPlexGetSupportSection - Return a section which describes the layout of support data 5109 5110 Not Collective 5111 5112 Input Parameters: 5113 . dm - The DMPlex object 5114 5115 Output Parameter: 5116 . section - The PetscSection object 5117 5118 Level: developer 5119 5120 .seealso: `DMPlexGetConeSection()` 5121 @*/ 5122 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5123 { 5124 DM_Plex *mesh = (DM_Plex*) dm->data; 5125 5126 PetscFunctionBegin; 5127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5128 if (section) *section = mesh->supportSection; 5129 PetscFunctionReturn(0); 5130 } 5131 5132 /*@C 5133 DMPlexGetCones - Return cone data 5134 5135 Not Collective 5136 5137 Input Parameters: 5138 . dm - The DMPlex object 5139 5140 Output Parameter: 5141 . cones - The cone for each point 5142 5143 Level: developer 5144 5145 .seealso: `DMPlexGetConeSection()` 5146 @*/ 5147 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5148 { 5149 DM_Plex *mesh = (DM_Plex*) dm->data; 5150 5151 PetscFunctionBegin; 5152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5153 if (cones) *cones = mesh->cones; 5154 PetscFunctionReturn(0); 5155 } 5156 5157 /*@C 5158 DMPlexGetConeOrientations - Return cone orientation data 5159 5160 Not Collective 5161 5162 Input Parameters: 5163 . dm - The DMPlex object 5164 5165 Output Parameter: 5166 . coneOrientations - The array of cone orientations for all points 5167 5168 Level: developer 5169 5170 Notes: 5171 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5172 5173 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5174 5175 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5176 @*/ 5177 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5178 { 5179 DM_Plex *mesh = (DM_Plex*) dm->data; 5180 5181 PetscFunctionBegin; 5182 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5183 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5184 PetscFunctionReturn(0); 5185 } 5186 5187 /******************************** FEM Support **********************************/ 5188 5189 /* 5190 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5191 representing a line in the section. 5192 */ 5193 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5194 { 5195 PetscFunctionBeginHot; 5196 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5197 if (line < 0) { 5198 *k = 0; 5199 *Nc = 0; 5200 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5201 *k = 1; 5202 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5203 /* An order k SEM disc has k-1 dofs on an edge */ 5204 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5205 *k = *k / *Nc + 1; 5206 } 5207 PetscFunctionReturn(0); 5208 } 5209 5210 /*@ 5211 5212 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5213 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5214 section provided (or the section of the DM). 5215 5216 Input Parameters: 5217 + dm - The DM 5218 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5219 - section - The PetscSection to reorder, or NULL for the default section 5220 5221 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5222 degree of the basis. 5223 5224 Example: 5225 A typical interpolated single-quad mesh might order points as 5226 .vb 5227 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5228 5229 v4 -- e6 -- v3 5230 | | 5231 e7 c0 e8 5232 | | 5233 v1 -- e5 -- v2 5234 .ve 5235 5236 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5237 dofs in the order of points, e.g., 5238 .vb 5239 c0 -> [0,1,2,3] 5240 v1 -> [4] 5241 ... 5242 e5 -> [8, 9] 5243 .ve 5244 5245 which corresponds to the dofs 5246 .vb 5247 6 10 11 7 5248 13 2 3 15 5249 12 0 1 14 5250 4 8 9 5 5251 .ve 5252 5253 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5254 .vb 5255 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5256 .ve 5257 5258 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5259 .vb 5260 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5261 .ve 5262 5263 Level: developer 5264 5265 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5266 @*/ 5267 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5268 { 5269 DMLabel label; 5270 PetscInt dim, depth = -1, eStart = -1, Nf; 5271 PetscBool vertexchart; 5272 5273 PetscFunctionBegin; 5274 PetscCall(DMGetDimension(dm, &dim)); 5275 if (dim < 1) PetscFunctionReturn(0); 5276 if (point < 0) { 5277 PetscInt sStart,sEnd; 5278 5279 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5280 point = sEnd-sStart ? sStart : point; 5281 } 5282 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5283 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5284 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5285 if (depth == 1) {eStart = point;} 5286 else if (depth == dim) { 5287 const PetscInt *cone; 5288 5289 PetscCall(DMPlexGetCone(dm, point, &cone)); 5290 if (dim == 2) eStart = cone[0]; 5291 else if (dim == 3) { 5292 const PetscInt *cone2; 5293 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5294 eStart = cone2[0]; 5295 } 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); 5296 } 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); 5297 { /* Determine whether the chart covers all points or just vertices. */ 5298 PetscInt pStart,pEnd,cStart,cEnd; 5299 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5300 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5301 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5302 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5303 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5304 } 5305 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5306 for (PetscInt d=1; d<=dim; d++) { 5307 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5308 PetscInt *perm; 5309 5310 for (f = 0; f < Nf; ++f) { 5311 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5312 size += PetscPowInt(k+1, d)*Nc; 5313 } 5314 PetscCall(PetscMalloc1(size, &perm)); 5315 for (f = 0; f < Nf; ++f) { 5316 switch (d) { 5317 case 1: 5318 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5319 /* 5320 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5321 We want [ vtx0; edge of length k-1; vtx1 ] 5322 */ 5323 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5324 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5325 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5326 foffset = offset; 5327 break; 5328 case 2: 5329 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5330 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5331 /* The SEM order is 5332 5333 v_lb, {e_b}, v_rb, 5334 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5335 v_lt, reverse {e_t}, v_rt 5336 */ 5337 { 5338 const PetscInt of = 0; 5339 const PetscInt oeb = of + PetscSqr(k-1); 5340 const PetscInt oer = oeb + (k-1); 5341 const PetscInt oet = oer + (k-1); 5342 const PetscInt oel = oet + (k-1); 5343 const PetscInt ovlb = oel + (k-1); 5344 const PetscInt ovrb = ovlb + 1; 5345 const PetscInt ovrt = ovrb + 1; 5346 const PetscInt ovlt = ovrt + 1; 5347 PetscInt o; 5348 5349 /* bottom */ 5350 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5351 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5352 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5353 /* middle */ 5354 for (i = 0; i < k-1; ++i) { 5355 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5356 for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5357 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5358 } 5359 /* top */ 5360 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5361 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5362 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5363 foffset = offset; 5364 } 5365 break; 5366 case 3: 5367 /* The original hex closure is 5368 5369 {c, 5370 f_b, f_t, f_f, f_b, f_r, f_l, 5371 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5372 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5373 */ 5374 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5375 /* The SEM order is 5376 Bottom Slice 5377 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5378 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5379 v_blb, {e_bb}, v_brb, 5380 5381 Middle Slice (j) 5382 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5383 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5384 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5385 5386 Top Slice 5387 v_tlf, {e_tf}, v_trf, 5388 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5389 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5390 */ 5391 { 5392 const PetscInt oc = 0; 5393 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5394 const PetscInt oft = ofb + PetscSqr(k-1); 5395 const PetscInt off = oft + PetscSqr(k-1); 5396 const PetscInt ofk = off + PetscSqr(k-1); 5397 const PetscInt ofr = ofk + PetscSqr(k-1); 5398 const PetscInt ofl = ofr + PetscSqr(k-1); 5399 const PetscInt oebl = ofl + PetscSqr(k-1); 5400 const PetscInt oebb = oebl + (k-1); 5401 const PetscInt oebr = oebb + (k-1); 5402 const PetscInt oebf = oebr + (k-1); 5403 const PetscInt oetf = oebf + (k-1); 5404 const PetscInt oetr = oetf + (k-1); 5405 const PetscInt oetb = oetr + (k-1); 5406 const PetscInt oetl = oetb + (k-1); 5407 const PetscInt oerf = oetl + (k-1); 5408 const PetscInt oelf = oerf + (k-1); 5409 const PetscInt oelb = oelf + (k-1); 5410 const PetscInt oerb = oelb + (k-1); 5411 const PetscInt ovblf = oerb + (k-1); 5412 const PetscInt ovblb = ovblf + 1; 5413 const PetscInt ovbrb = ovblb + 1; 5414 const PetscInt ovbrf = ovbrb + 1; 5415 const PetscInt ovtlf = ovbrf + 1; 5416 const PetscInt ovtrf = ovtlf + 1; 5417 const PetscInt ovtrb = ovtrf + 1; 5418 const PetscInt ovtlb = ovtrb + 1; 5419 PetscInt o, n; 5420 5421 /* Bottom Slice */ 5422 /* bottom */ 5423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5424 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5426 /* middle */ 5427 for (i = 0; i < k-1; ++i) { 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5429 for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;} 5430 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5431 } 5432 /* top */ 5433 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5434 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5436 5437 /* Middle Slice */ 5438 for (j = 0; j < k-1; ++j) { 5439 /* bottom */ 5440 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5441 for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5442 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5443 /* middle */ 5444 for (i = 0; i < k-1; ++i) { 5445 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5446 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset; 5447 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5448 } 5449 /* top */ 5450 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5451 for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5452 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5453 } 5454 5455 /* Top Slice */ 5456 /* bottom */ 5457 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5458 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5459 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5460 /* middle */ 5461 for (i = 0; i < k-1; ++i) { 5462 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5463 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5464 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5465 } 5466 /* top */ 5467 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5468 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5469 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5470 5471 foffset = offset; 5472 } 5473 break; 5474 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5475 } 5476 } 5477 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5478 /* Check permutation */ 5479 { 5480 PetscInt *check; 5481 5482 PetscCall(PetscMalloc1(size, &check)); 5483 for (i = 0; i < size; ++i) { 5484 check[i] = -1; 5485 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5486 } 5487 for (i = 0; i < size; ++i) check[perm[i]] = i; 5488 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5489 PetscCall(PetscFree(check)); 5490 } 5491 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5492 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5493 PetscInt *loc_perm; 5494 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5495 for (PetscInt i=0; i<size; i++) { 5496 loc_perm[i] = perm[i]; 5497 loc_perm[size+i] = size + perm[i]; 5498 } 5499 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5500 } 5501 } 5502 PetscFunctionReturn(0); 5503 } 5504 5505 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5506 { 5507 PetscDS prob; 5508 PetscInt depth, Nf, h; 5509 DMLabel label; 5510 5511 PetscFunctionBeginHot; 5512 PetscCall(DMGetDS(dm, &prob)); 5513 Nf = prob->Nf; 5514 label = dm->depthLabel; 5515 *dspace = NULL; 5516 if (field < Nf) { 5517 PetscObject disc = prob->disc[field]; 5518 5519 if (disc->classid == PETSCFE_CLASSID) { 5520 PetscDualSpace dsp; 5521 5522 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5523 PetscCall(DMLabelGetNumValues(label,&depth)); 5524 PetscCall(DMLabelGetValue(label,point,&h)); 5525 h = depth - 1 - h; 5526 if (h) { 5527 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5528 } else { 5529 *dspace = dsp; 5530 } 5531 } 5532 } 5533 PetscFunctionReturn(0); 5534 } 5535 5536 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5537 { 5538 PetscScalar *array; 5539 const PetscScalar *vArray; 5540 const PetscInt *cone, *coneO; 5541 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5542 5543 PetscFunctionBeginHot; 5544 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5545 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5546 PetscCall(DMPlexGetCone(dm, point, &cone)); 5547 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5548 if (!values || !*values) { 5549 if ((point >= pStart) && (point < pEnd)) { 5550 PetscInt dof; 5551 5552 PetscCall(PetscSectionGetDof(section, point, &dof)); 5553 size += dof; 5554 } 5555 for (p = 0; p < numPoints; ++p) { 5556 const PetscInt cp = cone[p]; 5557 PetscInt dof; 5558 5559 if ((cp < pStart) || (cp >= pEnd)) continue; 5560 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5561 size += dof; 5562 } 5563 if (!values) { 5564 if (csize) *csize = size; 5565 PetscFunctionReturn(0); 5566 } 5567 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5568 } else { 5569 array = *values; 5570 } 5571 size = 0; 5572 PetscCall(VecGetArrayRead(v, &vArray)); 5573 if ((point >= pStart) && (point < pEnd)) { 5574 PetscInt dof, off, d; 5575 const PetscScalar *varr; 5576 5577 PetscCall(PetscSectionGetDof(section, point, &dof)); 5578 PetscCall(PetscSectionGetOffset(section, point, &off)); 5579 varr = &vArray[off]; 5580 for (d = 0; d < dof; ++d, ++offset) { 5581 array[offset] = varr[d]; 5582 } 5583 size += dof; 5584 } 5585 for (p = 0; p < numPoints; ++p) { 5586 const PetscInt cp = cone[p]; 5587 PetscInt o = coneO[p]; 5588 PetscInt dof, off, d; 5589 const PetscScalar *varr; 5590 5591 if ((cp < pStart) || (cp >= pEnd)) continue; 5592 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5593 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5594 varr = &vArray[off]; 5595 if (o >= 0) { 5596 for (d = 0; d < dof; ++d, ++offset) { 5597 array[offset] = varr[d]; 5598 } 5599 } else { 5600 for (d = dof-1; d >= 0; --d, ++offset) { 5601 array[offset] = varr[d]; 5602 } 5603 } 5604 size += dof; 5605 } 5606 PetscCall(VecRestoreArrayRead(v, &vArray)); 5607 if (!*values) { 5608 if (csize) *csize = size; 5609 *values = array; 5610 } else { 5611 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5612 *csize = size; 5613 } 5614 PetscFunctionReturn(0); 5615 } 5616 5617 /* Compress out points not in the section */ 5618 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5619 { 5620 const PetscInt np = *numPoints; 5621 PetscInt pStart, pEnd, p, q; 5622 5623 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5624 for (p = 0, q = 0; p < np; ++p) { 5625 const PetscInt r = points[p*2]; 5626 if ((r >= pStart) && (r < pEnd)) { 5627 points[q*2] = r; 5628 points[q*2+1] = points[p*2+1]; 5629 ++q; 5630 } 5631 } 5632 *numPoints = q; 5633 return 0; 5634 } 5635 5636 /* Compressed closure does not apply closure permutation */ 5637 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5638 { 5639 const PetscInt *cla = NULL; 5640 PetscInt np, *pts = NULL; 5641 5642 PetscFunctionBeginHot; 5643 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5644 if (*clPoints) { 5645 PetscInt dof, off; 5646 5647 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5648 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5649 PetscCall(ISGetIndices(*clPoints, &cla)); 5650 np = dof/2; 5651 pts = (PetscInt *) &cla[off]; 5652 } else { 5653 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5654 PetscCall(CompressPoints_Private(section, &np, pts)); 5655 } 5656 *numPoints = np; 5657 *points = pts; 5658 *clp = cla; 5659 PetscFunctionReturn(0); 5660 } 5661 5662 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5663 { 5664 PetscFunctionBeginHot; 5665 if (!*clPoints) { 5666 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5667 } else { 5668 PetscCall(ISRestoreIndices(*clPoints, clp)); 5669 } 5670 *numPoints = 0; 5671 *points = NULL; 5672 *clSec = NULL; 5673 *clPoints = NULL; 5674 *clp = NULL; 5675 PetscFunctionReturn(0); 5676 } 5677 5678 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5679 { 5680 PetscInt offset = 0, p; 5681 const PetscInt **perms = NULL; 5682 const PetscScalar **flips = NULL; 5683 5684 PetscFunctionBeginHot; 5685 *size = 0; 5686 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5687 for (p = 0; p < numPoints; p++) { 5688 const PetscInt point = points[2*p]; 5689 const PetscInt *perm = perms ? perms[p] : NULL; 5690 const PetscScalar *flip = flips ? flips[p] : NULL; 5691 PetscInt dof, off, d; 5692 const PetscScalar *varr; 5693 5694 PetscCall(PetscSectionGetDof(section, point, &dof)); 5695 PetscCall(PetscSectionGetOffset(section, point, &off)); 5696 varr = &vArray[off]; 5697 if (clperm) { 5698 if (perm) { 5699 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5700 } else { 5701 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5702 } 5703 if (flip) { 5704 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5705 } 5706 } else { 5707 if (perm) { 5708 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5709 } else { 5710 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5711 } 5712 if (flip) { 5713 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5714 } 5715 } 5716 offset += dof; 5717 } 5718 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5719 *size = offset; 5720 PetscFunctionReturn(0); 5721 } 5722 5723 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[]) 5724 { 5725 PetscInt offset = 0, f; 5726 5727 PetscFunctionBeginHot; 5728 *size = 0; 5729 for (f = 0; f < numFields; ++f) { 5730 PetscInt p; 5731 const PetscInt **perms = NULL; 5732 const PetscScalar **flips = NULL; 5733 5734 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5735 for (p = 0; p < numPoints; p++) { 5736 const PetscInt point = points[2*p]; 5737 PetscInt fdof, foff, b; 5738 const PetscScalar *varr; 5739 const PetscInt *perm = perms ? perms[p] : NULL; 5740 const PetscScalar *flip = flips ? flips[p] : NULL; 5741 5742 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5743 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5744 varr = &vArray[foff]; 5745 if (clperm) { 5746 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5747 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5748 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5749 } else { 5750 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5751 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5752 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5753 } 5754 offset += fdof; 5755 } 5756 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5757 } 5758 *size = offset; 5759 PetscFunctionReturn(0); 5760 } 5761 5762 /*@C 5763 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5764 5765 Not collective 5766 5767 Input Parameters: 5768 + dm - The DM 5769 . section - The section describing the layout in v, or NULL to use the default section 5770 . v - The local vector 5771 - point - The point in the DM 5772 5773 Input/Output Parameters: 5774 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5775 - values - An array to use for the values, or NULL to have it allocated automatically; 5776 if the user provided NULL, it is a borrowed array and should not be freed 5777 5778 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5779 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5780 $ assembly function, and a user may already have allocated storage for this operation. 5781 $ 5782 $ A typical use could be 5783 $ 5784 $ values = NULL; 5785 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5786 $ for (cl = 0; cl < clSize; ++cl) { 5787 $ <Compute on closure> 5788 $ } 5789 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5790 $ 5791 $ or 5792 $ 5793 $ PetscMalloc1(clMaxSize, &values); 5794 $ for (p = pStart; p < pEnd; ++p) { 5795 $ clSize = clMaxSize; 5796 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5797 $ for (cl = 0; cl < clSize; ++cl) { 5798 $ <Compute on closure> 5799 $ } 5800 $ } 5801 $ PetscFree(values); 5802 5803 Fortran Notes: 5804 Since it returns an array, this routine is only available in Fortran 90, and you must 5805 include petsc.h90 in your code. 5806 5807 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5808 5809 Level: intermediate 5810 5811 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5812 @*/ 5813 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5814 { 5815 PetscSection clSection; 5816 IS clPoints; 5817 PetscInt *points = NULL; 5818 const PetscInt *clp, *perm; 5819 PetscInt depth, numFields, numPoints, asize; 5820 5821 PetscFunctionBeginHot; 5822 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5823 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5824 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5825 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5826 PetscCall(DMPlexGetDepth(dm, &depth)); 5827 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5828 if (depth == 1 && numFields < 2) { 5829 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5830 PetscFunctionReturn(0); 5831 } 5832 /* Get points */ 5833 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5834 /* Get sizes */ 5835 asize = 0; 5836 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5837 PetscInt dof; 5838 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5839 asize += dof; 5840 } 5841 if (values) { 5842 const PetscScalar *vArray; 5843 PetscInt size; 5844 5845 if (*values) { 5846 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); 5847 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5848 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5849 PetscCall(VecGetArrayRead(v, &vArray)); 5850 /* Get values */ 5851 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5852 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5853 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5854 /* Cleanup array */ 5855 PetscCall(VecRestoreArrayRead(v, &vArray)); 5856 } 5857 if (csize) *csize = asize; 5858 /* Cleanup points */ 5859 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5860 PetscFunctionReturn(0); 5861 } 5862 5863 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5864 { 5865 DMLabel depthLabel; 5866 PetscSection clSection; 5867 IS clPoints; 5868 PetscScalar *array; 5869 const PetscScalar *vArray; 5870 PetscInt *points = NULL; 5871 const PetscInt *clp, *perm = NULL; 5872 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5873 5874 PetscFunctionBeginHot; 5875 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5876 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5877 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5878 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5879 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5880 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5881 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5882 if (mdepth == 1 && numFields < 2) { 5883 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5884 PetscFunctionReturn(0); 5885 } 5886 /* Get points */ 5887 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5888 for (clsize=0,p=0; p<Np; p++) { 5889 PetscInt dof; 5890 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5891 clsize += dof; 5892 } 5893 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5894 /* Filter points */ 5895 for (p = 0; p < numPoints*2; p += 2) { 5896 PetscInt dep; 5897 5898 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5899 if (dep != depth) continue; 5900 points[Np*2+0] = points[p]; 5901 points[Np*2+1] = points[p+1]; 5902 ++Np; 5903 } 5904 /* Get array */ 5905 if (!values || !*values) { 5906 PetscInt asize = 0, dof; 5907 5908 for (p = 0; p < Np*2; p += 2) { 5909 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5910 asize += dof; 5911 } 5912 if (!values) { 5913 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5914 if (csize) *csize = asize; 5915 PetscFunctionReturn(0); 5916 } 5917 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5918 } else { 5919 array = *values; 5920 } 5921 PetscCall(VecGetArrayRead(v, &vArray)); 5922 /* Get values */ 5923 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5924 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5925 /* Cleanup points */ 5926 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5927 /* Cleanup array */ 5928 PetscCall(VecRestoreArrayRead(v, &vArray)); 5929 if (!*values) { 5930 if (csize) *csize = size; 5931 *values = array; 5932 } else { 5933 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5934 *csize = size; 5935 } 5936 PetscFunctionReturn(0); 5937 } 5938 5939 /*@C 5940 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5941 5942 Not collective 5943 5944 Input Parameters: 5945 + dm - The DM 5946 . section - The section describing the layout in v, or NULL to use the default section 5947 . v - The local vector 5948 . point - The point in the DM 5949 . csize - The number of values in the closure, or NULL 5950 - values - The array of values, which is a borrowed array and should not be freed 5951 5952 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5953 5954 Fortran Notes: 5955 Since it returns an array, this routine is only available in Fortran 90, and you must 5956 include petsc.h90 in your code. 5957 5958 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5959 5960 Level: intermediate 5961 5962 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5963 @*/ 5964 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5965 { 5966 PetscInt size = 0; 5967 5968 PetscFunctionBegin; 5969 /* Should work without recalculating size */ 5970 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5971 *values = NULL; 5972 PetscFunctionReturn(0); 5973 } 5974 5975 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5976 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5977 5978 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[]) 5979 { 5980 PetscInt cdof; /* The number of constraints on this point */ 5981 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5982 PetscScalar *a; 5983 PetscInt off, cind = 0, k; 5984 5985 PetscFunctionBegin; 5986 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5987 PetscCall(PetscSectionGetOffset(section, point, &off)); 5988 a = &array[off]; 5989 if (!cdof || setBC) { 5990 if (clperm) { 5991 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5992 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5993 } else { 5994 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5995 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5996 } 5997 } else { 5998 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5999 if (clperm) { 6000 if (perm) {for (k = 0; k < dof; ++k) { 6001 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6002 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6003 } 6004 } else { 6005 for (k = 0; k < dof; ++k) { 6006 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6007 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6008 } 6009 } 6010 } else { 6011 if (perm) { 6012 for (k = 0; k < dof; ++k) { 6013 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6014 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6015 } 6016 } else { 6017 for (k = 0; k < dof; ++k) { 6018 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6019 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6020 } 6021 } 6022 } 6023 } 6024 PetscFunctionReturn(0); 6025 } 6026 6027 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[]) 6028 { 6029 PetscInt cdof; /* The number of constraints on this point */ 6030 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6031 PetscScalar *a; 6032 PetscInt off, cind = 0, k; 6033 6034 PetscFunctionBegin; 6035 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6036 PetscCall(PetscSectionGetOffset(section, point, &off)); 6037 a = &array[off]; 6038 if (cdof) { 6039 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6040 if (clperm) { 6041 if (perm) { 6042 for (k = 0; k < dof; ++k) { 6043 if ((cind < cdof) && (k == cdofs[cind])) { 6044 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6045 cind++; 6046 } 6047 } 6048 } else { 6049 for (k = 0; k < dof; ++k) { 6050 if ((cind < cdof) && (k == cdofs[cind])) { 6051 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6052 cind++; 6053 } 6054 } 6055 } 6056 } else { 6057 if (perm) { 6058 for (k = 0; k < dof; ++k) { 6059 if ((cind < cdof) && (k == cdofs[cind])) { 6060 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6061 cind++; 6062 } 6063 } 6064 } else { 6065 for (k = 0; k < dof; ++k) { 6066 if ((cind < cdof) && (k == cdofs[cind])) { 6067 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6068 cind++; 6069 } 6070 } 6071 } 6072 } 6073 } 6074 PetscFunctionReturn(0); 6075 } 6076 6077 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[]) 6078 { 6079 PetscScalar *a; 6080 PetscInt fdof, foff, fcdof, foffset = *offset; 6081 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6082 PetscInt cind = 0, b; 6083 6084 PetscFunctionBegin; 6085 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6086 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6087 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6088 a = &array[foff]; 6089 if (!fcdof || setBC) { 6090 if (clperm) { 6091 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6092 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6093 } else { 6094 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6095 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6096 } 6097 } else { 6098 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6099 if (clperm) { 6100 if (perm) { 6101 for (b = 0; b < fdof; b++) { 6102 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6103 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6104 } 6105 } else { 6106 for (b = 0; b < fdof; b++) { 6107 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6108 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6109 } 6110 } 6111 } else { 6112 if (perm) { 6113 for (b = 0; b < fdof; b++) { 6114 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6115 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6116 } 6117 } else { 6118 for (b = 0; b < fdof; b++) { 6119 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6120 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6121 } 6122 } 6123 } 6124 } 6125 *offset += fdof; 6126 PetscFunctionReturn(0); 6127 } 6128 6129 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[]) 6130 { 6131 PetscScalar *a; 6132 PetscInt fdof, foff, fcdof, foffset = *offset; 6133 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6134 PetscInt Nc, cind = 0, ncind = 0, b; 6135 PetscBool ncSet, fcSet; 6136 6137 PetscFunctionBegin; 6138 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6139 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6140 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6141 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6142 a = &array[foff]; 6143 if (fcdof) { 6144 /* We just override fcdof and fcdofs with Ncc and comps */ 6145 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6146 if (clperm) { 6147 if (perm) { 6148 if (comps) { 6149 for (b = 0; b < fdof; b++) { 6150 ncSet = fcSet = PETSC_FALSE; 6151 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6152 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6153 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6154 } 6155 } else { 6156 for (b = 0; b < fdof; b++) { 6157 if ((cind < fcdof) && (b == fcdofs[cind])) { 6158 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6159 ++cind; 6160 } 6161 } 6162 } 6163 } else { 6164 if (comps) { 6165 for (b = 0; b < fdof; b++) { 6166 ncSet = fcSet = PETSC_FALSE; 6167 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6168 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6169 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6170 } 6171 } else { 6172 for (b = 0; b < fdof; b++) { 6173 if ((cind < fcdof) && (b == fcdofs[cind])) { 6174 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6175 ++cind; 6176 } 6177 } 6178 } 6179 } 6180 } else { 6181 if (perm) { 6182 if (comps) { 6183 for (b = 0; b < fdof; b++) { 6184 ncSet = fcSet = PETSC_FALSE; 6185 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6186 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6187 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6188 } 6189 } else { 6190 for (b = 0; b < fdof; b++) { 6191 if ((cind < fcdof) && (b == fcdofs[cind])) { 6192 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6193 ++cind; 6194 } 6195 } 6196 } 6197 } else { 6198 if (comps) { 6199 for (b = 0; b < fdof; b++) { 6200 ncSet = fcSet = PETSC_FALSE; 6201 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6202 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6203 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6204 } 6205 } else { 6206 for (b = 0; b < fdof; b++) { 6207 if ((cind < fcdof) && (b == fcdofs[cind])) { 6208 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6209 ++cind; 6210 } 6211 } 6212 } 6213 } 6214 } 6215 } 6216 *offset += fdof; 6217 PetscFunctionReturn(0); 6218 } 6219 6220 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6221 { 6222 PetscScalar *array; 6223 const PetscInt *cone, *coneO; 6224 PetscInt pStart, pEnd, p, numPoints, off, dof; 6225 6226 PetscFunctionBeginHot; 6227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6228 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6229 PetscCall(DMPlexGetCone(dm, point, &cone)); 6230 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6231 PetscCall(VecGetArray(v, &array)); 6232 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6233 const PetscInt cp = !p ? point : cone[p-1]; 6234 const PetscInt o = !p ? 0 : coneO[p-1]; 6235 6236 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6237 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6238 /* ADD_VALUES */ 6239 { 6240 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6241 PetscScalar *a; 6242 PetscInt cdof, coff, cind = 0, k; 6243 6244 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6245 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6246 a = &array[coff]; 6247 if (!cdof) { 6248 if (o >= 0) { 6249 for (k = 0; k < dof; ++k) { 6250 a[k] += values[off+k]; 6251 } 6252 } else { 6253 for (k = 0; k < dof; ++k) { 6254 a[k] += values[off+dof-k-1]; 6255 } 6256 } 6257 } else { 6258 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6259 if (o >= 0) { 6260 for (k = 0; k < dof; ++k) { 6261 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6262 a[k] += values[off+k]; 6263 } 6264 } else { 6265 for (k = 0; k < dof; ++k) { 6266 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6267 a[k] += values[off+dof-k-1]; 6268 } 6269 } 6270 } 6271 } 6272 } 6273 PetscCall(VecRestoreArray(v, &array)); 6274 PetscFunctionReturn(0); 6275 } 6276 6277 /*@C 6278 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6279 6280 Not collective 6281 6282 Input Parameters: 6283 + dm - The DM 6284 . section - The section describing the layout in v, or NULL to use the default section 6285 . v - The local vector 6286 . point - The point in the DM 6287 . values - The array of values 6288 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6289 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6290 6291 Fortran Notes: 6292 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6293 6294 Level: intermediate 6295 6296 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6297 @*/ 6298 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6299 { 6300 PetscSection clSection; 6301 IS clPoints; 6302 PetscScalar *array; 6303 PetscInt *points = NULL; 6304 const PetscInt *clp, *clperm = NULL; 6305 PetscInt depth, numFields, numPoints, p, clsize; 6306 6307 PetscFunctionBeginHot; 6308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6309 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6310 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6311 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6312 PetscCall(DMPlexGetDepth(dm, &depth)); 6313 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6314 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6315 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6316 PetscFunctionReturn(0); 6317 } 6318 /* Get points */ 6319 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6320 for (clsize=0,p=0; p<numPoints; p++) { 6321 PetscInt dof; 6322 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6323 clsize += dof; 6324 } 6325 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6326 /* Get array */ 6327 PetscCall(VecGetArray(v, &array)); 6328 /* Get values */ 6329 if (numFields > 0) { 6330 PetscInt offset = 0, f; 6331 for (f = 0; f < numFields; ++f) { 6332 const PetscInt **perms = NULL; 6333 const PetscScalar **flips = NULL; 6334 6335 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6336 switch (mode) { 6337 case INSERT_VALUES: 6338 for (p = 0; p < numPoints; p++) { 6339 const PetscInt point = points[2*p]; 6340 const PetscInt *perm = perms ? perms[p] : NULL; 6341 const PetscScalar *flip = flips ? flips[p] : NULL; 6342 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6343 } break; 6344 case INSERT_ALL_VALUES: 6345 for (p = 0; p < numPoints; p++) { 6346 const PetscInt point = points[2*p]; 6347 const PetscInt *perm = perms ? perms[p] : NULL; 6348 const PetscScalar *flip = flips ? flips[p] : NULL; 6349 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6350 } break; 6351 case INSERT_BC_VALUES: 6352 for (p = 0; p < numPoints; p++) { 6353 const PetscInt point = points[2*p]; 6354 const PetscInt *perm = perms ? perms[p] : NULL; 6355 const PetscScalar *flip = flips ? flips[p] : NULL; 6356 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6357 } break; 6358 case ADD_VALUES: 6359 for (p = 0; p < numPoints; p++) { 6360 const PetscInt point = points[2*p]; 6361 const PetscInt *perm = perms ? perms[p] : NULL; 6362 const PetscScalar *flip = flips ? flips[p] : NULL; 6363 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6364 } break; 6365 case ADD_ALL_VALUES: 6366 for (p = 0; p < numPoints; p++) { 6367 const PetscInt point = points[2*p]; 6368 const PetscInt *perm = perms ? perms[p] : NULL; 6369 const PetscScalar *flip = flips ? flips[p] : NULL; 6370 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6371 } break; 6372 case ADD_BC_VALUES: 6373 for (p = 0; p < numPoints; p++) { 6374 const PetscInt point = points[2*p]; 6375 const PetscInt *perm = perms ? perms[p] : NULL; 6376 const PetscScalar *flip = flips ? flips[p] : NULL; 6377 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6378 } break; 6379 default: 6380 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6381 } 6382 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6383 } 6384 } else { 6385 PetscInt dof, off; 6386 const PetscInt **perms = NULL; 6387 const PetscScalar **flips = NULL; 6388 6389 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6390 switch (mode) { 6391 case INSERT_VALUES: 6392 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6393 const PetscInt point = points[2*p]; 6394 const PetscInt *perm = perms ? perms[p] : NULL; 6395 const PetscScalar *flip = flips ? flips[p] : NULL; 6396 PetscCall(PetscSectionGetDof(section, point, &dof)); 6397 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6398 } break; 6399 case INSERT_ALL_VALUES: 6400 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6401 const PetscInt point = points[2*p]; 6402 const PetscInt *perm = perms ? perms[p] : NULL; 6403 const PetscScalar *flip = flips ? flips[p] : NULL; 6404 PetscCall(PetscSectionGetDof(section, point, &dof)); 6405 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6406 } break; 6407 case INSERT_BC_VALUES: 6408 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6409 const PetscInt point = points[2*p]; 6410 const PetscInt *perm = perms ? perms[p] : NULL; 6411 const PetscScalar *flip = flips ? flips[p] : NULL; 6412 PetscCall(PetscSectionGetDof(section, point, &dof)); 6413 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6414 } break; 6415 case ADD_VALUES: 6416 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6417 const PetscInt point = points[2*p]; 6418 const PetscInt *perm = perms ? perms[p] : NULL; 6419 const PetscScalar *flip = flips ? flips[p] : NULL; 6420 PetscCall(PetscSectionGetDof(section, point, &dof)); 6421 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6422 } break; 6423 case ADD_ALL_VALUES: 6424 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6425 const PetscInt point = points[2*p]; 6426 const PetscInt *perm = perms ? perms[p] : NULL; 6427 const PetscScalar *flip = flips ? flips[p] : NULL; 6428 PetscCall(PetscSectionGetDof(section, point, &dof)); 6429 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6430 } break; 6431 case ADD_BC_VALUES: 6432 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6433 const PetscInt point = points[2*p]; 6434 const PetscInt *perm = perms ? perms[p] : NULL; 6435 const PetscScalar *flip = flips ? flips[p] : NULL; 6436 PetscCall(PetscSectionGetDof(section, point, &dof)); 6437 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6438 } break; 6439 default: 6440 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6441 } 6442 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6443 } 6444 /* Cleanup points */ 6445 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6446 /* Cleanup array */ 6447 PetscCall(VecRestoreArray(v, &array)); 6448 PetscFunctionReturn(0); 6449 } 6450 6451 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6452 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6453 { 6454 PetscFunctionBegin; 6455 if (label) { 6456 PetscBool contains; 6457 PetscInt fdof; 6458 6459 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6460 if (!contains) { 6461 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6462 *offset += fdof; 6463 PetscFunctionReturn(1); 6464 } 6465 } 6466 PetscFunctionReturn(0); 6467 } 6468 6469 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6470 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) 6471 { 6472 PetscSection clSection; 6473 IS clPoints; 6474 PetscScalar *array; 6475 PetscInt *points = NULL; 6476 const PetscInt *clp; 6477 PetscInt numFields, numPoints, p; 6478 PetscInt offset = 0, f; 6479 6480 PetscFunctionBeginHot; 6481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6482 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6483 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6484 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6485 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6486 /* Get points */ 6487 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6488 /* Get array */ 6489 PetscCall(VecGetArray(v, &array)); 6490 /* Get values */ 6491 for (f = 0; f < numFields; ++f) { 6492 const PetscInt **perms = NULL; 6493 const PetscScalar **flips = NULL; 6494 6495 if (!fieldActive[f]) { 6496 for (p = 0; p < numPoints*2; p += 2) { 6497 PetscInt fdof; 6498 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6499 offset += fdof; 6500 } 6501 continue; 6502 } 6503 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6504 switch (mode) { 6505 case INSERT_VALUES: 6506 for (p = 0; p < numPoints; p++) { 6507 const PetscInt point = points[2*p]; 6508 const PetscInt *perm = perms ? perms[p] : NULL; 6509 const PetscScalar *flip = flips ? flips[p] : NULL; 6510 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6511 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6512 } break; 6513 case INSERT_ALL_VALUES: 6514 for (p = 0; p < numPoints; p++) { 6515 const PetscInt point = points[2*p]; 6516 const PetscInt *perm = perms ? perms[p] : NULL; 6517 const PetscScalar *flip = flips ? flips[p] : NULL; 6518 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6519 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6520 } break; 6521 case INSERT_BC_VALUES: 6522 for (p = 0; p < numPoints; p++) { 6523 const PetscInt point = points[2*p]; 6524 const PetscInt *perm = perms ? perms[p] : NULL; 6525 const PetscScalar *flip = flips ? flips[p] : NULL; 6526 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6527 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6528 } break; 6529 case ADD_VALUES: 6530 for (p = 0; p < numPoints; p++) { 6531 const PetscInt point = points[2*p]; 6532 const PetscInt *perm = perms ? perms[p] : NULL; 6533 const PetscScalar *flip = flips ? flips[p] : NULL; 6534 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6535 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6536 } break; 6537 case ADD_ALL_VALUES: 6538 for (p = 0; p < numPoints; p++) { 6539 const PetscInt point = points[2*p]; 6540 const PetscInt *perm = perms ? perms[p] : NULL; 6541 const PetscScalar *flip = flips ? flips[p] : NULL; 6542 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6543 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6544 } break; 6545 default: 6546 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6547 } 6548 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6549 } 6550 /* Cleanup points */ 6551 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6552 /* Cleanup array */ 6553 PetscCall(VecRestoreArray(v, &array)); 6554 PetscFunctionReturn(0); 6555 } 6556 6557 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6558 { 6559 PetscMPIInt rank; 6560 PetscInt i, j; 6561 6562 PetscFunctionBegin; 6563 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6564 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6565 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6566 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6567 numCIndices = numCIndices ? numCIndices : numRIndices; 6568 if (!values) PetscFunctionReturn(0); 6569 for (i = 0; i < numRIndices; i++) { 6570 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6571 for (j = 0; j < numCIndices; j++) { 6572 #if defined(PETSC_USE_COMPLEX) 6573 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6574 #else 6575 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6576 #endif 6577 } 6578 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6579 } 6580 PetscFunctionReturn(0); 6581 } 6582 6583 /* 6584 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6585 6586 Input Parameters: 6587 + section - The section for this data layout 6588 . islocal - Is the section (and thus indices being requested) local or global? 6589 . point - The point contributing dofs with these indices 6590 . off - The global offset of this point 6591 . loff - The local offset of each field 6592 . setBC - The flag determining whether to include indices of boundary values 6593 . perm - A permutation of the dofs on this point, or NULL 6594 - indperm - A permutation of the entire indices array, or NULL 6595 6596 Output Parameter: 6597 . indices - Indices for dofs on this point 6598 6599 Level: developer 6600 6601 Note: The indices could be local or global, depending on the value of 'off'. 6602 */ 6603 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6604 { 6605 PetscInt dof; /* The number of unknowns on this point */ 6606 PetscInt cdof; /* The number of constraints on this point */ 6607 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6608 PetscInt cind = 0, k; 6609 6610 PetscFunctionBegin; 6611 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6612 PetscCall(PetscSectionGetDof(section, point, &dof)); 6613 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6614 if (!cdof || setBC) { 6615 for (k = 0; k < dof; ++k) { 6616 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6617 const PetscInt ind = indperm ? indperm[preind] : preind; 6618 6619 indices[ind] = off + k; 6620 } 6621 } else { 6622 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6623 for (k = 0; k < dof; ++k) { 6624 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6625 const PetscInt ind = indperm ? indperm[preind] : preind; 6626 6627 if ((cind < cdof) && (k == cdofs[cind])) { 6628 /* Insert check for returning constrained indices */ 6629 indices[ind] = -(off+k+1); 6630 ++cind; 6631 } else { 6632 indices[ind] = off + k - (islocal ? 0 : cind); 6633 } 6634 } 6635 } 6636 *loff += dof; 6637 PetscFunctionReturn(0); 6638 } 6639 6640 /* 6641 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6642 6643 Input Parameters: 6644 + section - a section (global or local) 6645 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6646 . point - point within section 6647 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6648 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6649 . setBC - identify constrained (boundary condition) points via involution. 6650 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6651 . permsoff - offset 6652 - indperm - index permutation 6653 6654 Output Parameter: 6655 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6656 . indices - array to hold indices (as defined by section) of each dof associated with point 6657 6658 Notes: 6659 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6660 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6661 in the local vector. 6662 6663 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6664 significant). It is invalid to call with a global section and setBC=true. 6665 6666 Developer Note: 6667 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6668 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6669 offset could be obtained from the section instead of passing it explicitly as we do now. 6670 6671 Example: 6672 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6673 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6674 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6675 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. 6676 6677 Level: developer 6678 */ 6679 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[]) 6680 { 6681 PetscInt numFields, foff, f; 6682 6683 PetscFunctionBegin; 6684 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6685 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6686 for (f = 0, foff = 0; f < numFields; ++f) { 6687 PetscInt fdof, cfdof; 6688 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6689 PetscInt cind = 0, b; 6690 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6691 6692 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6693 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6694 if (!cfdof || setBC) { 6695 for (b = 0; b < fdof; ++b) { 6696 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6697 const PetscInt ind = indperm ? indperm[preind] : preind; 6698 6699 indices[ind] = off+foff+b; 6700 } 6701 } else { 6702 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6703 for (b = 0; b < fdof; ++b) { 6704 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6705 const PetscInt ind = indperm ? indperm[preind] : preind; 6706 6707 if ((cind < cfdof) && (b == fcdofs[cind])) { 6708 indices[ind] = -(off+foff+b+1); 6709 ++cind; 6710 } else { 6711 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6712 } 6713 } 6714 } 6715 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6716 foffs[f] += fdof; 6717 } 6718 PetscFunctionReturn(0); 6719 } 6720 6721 /* 6722 This version believes the globalSection offsets for each field, rather than just the point offset 6723 6724 . foffs - The offset into 'indices' for each field, since it is segregated by field 6725 6726 Notes: 6727 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6728 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6729 */ 6730 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6731 { 6732 PetscInt numFields, foff, f; 6733 6734 PetscFunctionBegin; 6735 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6736 for (f = 0; f < numFields; ++f) { 6737 PetscInt fdof, cfdof; 6738 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6739 PetscInt cind = 0, b; 6740 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6741 6742 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6743 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6744 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6745 if (!cfdof) { 6746 for (b = 0; b < fdof; ++b) { 6747 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6748 const PetscInt ind = indperm ? indperm[preind] : preind; 6749 6750 indices[ind] = foff+b; 6751 } 6752 } else { 6753 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6754 for (b = 0; b < fdof; ++b) { 6755 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6756 const PetscInt ind = indperm ? indperm[preind] : preind; 6757 6758 if ((cind < cfdof) && (b == fcdofs[cind])) { 6759 indices[ind] = -(foff+b+1); 6760 ++cind; 6761 } else { 6762 indices[ind] = foff+b-cind; 6763 } 6764 } 6765 } 6766 foffs[f] += fdof; 6767 } 6768 PetscFunctionReturn(0); 6769 } 6770 6771 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) 6772 { 6773 Mat cMat; 6774 PetscSection aSec, cSec; 6775 IS aIS; 6776 PetscInt aStart = -1, aEnd = -1; 6777 const PetscInt *anchors; 6778 PetscInt numFields, f, p, q, newP = 0; 6779 PetscInt newNumPoints = 0, newNumIndices = 0; 6780 PetscInt *newPoints, *indices, *newIndices; 6781 PetscInt maxAnchor, maxDof; 6782 PetscInt newOffsets[32]; 6783 PetscInt *pointMatOffsets[32]; 6784 PetscInt *newPointOffsets[32]; 6785 PetscScalar *pointMat[32]; 6786 PetscScalar *newValues=NULL,*tmpValues; 6787 PetscBool anyConstrained = PETSC_FALSE; 6788 6789 PetscFunctionBegin; 6790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6791 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6792 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6793 6794 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6795 /* if there are point-to-point constraints */ 6796 if (aSec) { 6797 PetscCall(PetscArrayzero(newOffsets, 32)); 6798 PetscCall(ISGetIndices(aIS,&anchors)); 6799 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6800 /* figure out how many points are going to be in the new element matrix 6801 * (we allow double counting, because it's all just going to be summed 6802 * into the global matrix anyway) */ 6803 for (p = 0; p < 2*numPoints; p+=2) { 6804 PetscInt b = points[p]; 6805 PetscInt bDof = 0, bSecDof; 6806 6807 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6808 if (!bSecDof) { 6809 continue; 6810 } 6811 if (b >= aStart && b < aEnd) { 6812 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6813 } 6814 if (bDof) { 6815 /* this point is constrained */ 6816 /* it is going to be replaced by its anchors */ 6817 PetscInt bOff, q; 6818 6819 anyConstrained = PETSC_TRUE; 6820 newNumPoints += bDof; 6821 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6822 for (q = 0; q < bDof; q++) { 6823 PetscInt a = anchors[bOff + q]; 6824 PetscInt aDof; 6825 6826 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6827 newNumIndices += aDof; 6828 for (f = 0; f < numFields; ++f) { 6829 PetscInt fDof; 6830 6831 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6832 newOffsets[f+1] += fDof; 6833 } 6834 } 6835 } 6836 else { 6837 /* this point is not constrained */ 6838 newNumPoints++; 6839 newNumIndices += bSecDof; 6840 for (f = 0; f < numFields; ++f) { 6841 PetscInt fDof; 6842 6843 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6844 newOffsets[f+1] += fDof; 6845 } 6846 } 6847 } 6848 } 6849 if (!anyConstrained) { 6850 if (outNumPoints) *outNumPoints = 0; 6851 if (outNumIndices) *outNumIndices = 0; 6852 if (outPoints) *outPoints = NULL; 6853 if (outValues) *outValues = NULL; 6854 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6855 PetscFunctionReturn(0); 6856 } 6857 6858 if (outNumPoints) *outNumPoints = newNumPoints; 6859 if (outNumIndices) *outNumIndices = newNumIndices; 6860 6861 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6862 6863 if (!outPoints && !outValues) { 6864 if (offsets) { 6865 for (f = 0; f <= numFields; f++) { 6866 offsets[f] = newOffsets[f]; 6867 } 6868 } 6869 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6870 PetscFunctionReturn(0); 6871 } 6872 6873 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6874 6875 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6876 6877 /* workspaces */ 6878 if (numFields) { 6879 for (f = 0; f < numFields; f++) { 6880 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6881 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6882 } 6883 } 6884 else { 6885 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6886 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6887 } 6888 6889 /* get workspaces for the point-to-point matrices */ 6890 if (numFields) { 6891 PetscInt totalOffset, totalMatOffset; 6892 6893 for (p = 0; p < numPoints; p++) { 6894 PetscInt b = points[2*p]; 6895 PetscInt bDof = 0, bSecDof; 6896 6897 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6898 if (!bSecDof) { 6899 for (f = 0; f < numFields; f++) { 6900 newPointOffsets[f][p + 1] = 0; 6901 pointMatOffsets[f][p + 1] = 0; 6902 } 6903 continue; 6904 } 6905 if (b >= aStart && b < aEnd) { 6906 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6907 } 6908 if (bDof) { 6909 for (f = 0; f < numFields; f++) { 6910 PetscInt fDof, q, bOff, allFDof = 0; 6911 6912 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6913 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6914 for (q = 0; q < bDof; q++) { 6915 PetscInt a = anchors[bOff + q]; 6916 PetscInt aFDof; 6917 6918 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6919 allFDof += aFDof; 6920 } 6921 newPointOffsets[f][p+1] = allFDof; 6922 pointMatOffsets[f][p+1] = fDof * allFDof; 6923 } 6924 } 6925 else { 6926 for (f = 0; f < numFields; f++) { 6927 PetscInt fDof; 6928 6929 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6930 newPointOffsets[f][p+1] = fDof; 6931 pointMatOffsets[f][p+1] = 0; 6932 } 6933 } 6934 } 6935 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6936 newPointOffsets[f][0] = totalOffset; 6937 pointMatOffsets[f][0] = totalMatOffset; 6938 for (p = 0; p < numPoints; p++) { 6939 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6940 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6941 } 6942 totalOffset = newPointOffsets[f][numPoints]; 6943 totalMatOffset = pointMatOffsets[f][numPoints]; 6944 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6945 } 6946 } 6947 else { 6948 for (p = 0; p < numPoints; p++) { 6949 PetscInt b = points[2*p]; 6950 PetscInt bDof = 0, bSecDof; 6951 6952 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6953 if (!bSecDof) { 6954 newPointOffsets[0][p + 1] = 0; 6955 pointMatOffsets[0][p + 1] = 0; 6956 continue; 6957 } 6958 if (b >= aStart && b < aEnd) { 6959 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6960 } 6961 if (bDof) { 6962 PetscInt bOff, q, allDof = 0; 6963 6964 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6965 for (q = 0; q < bDof; q++) { 6966 PetscInt a = anchors[bOff + q], aDof; 6967 6968 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6969 allDof += aDof; 6970 } 6971 newPointOffsets[0][p+1] = allDof; 6972 pointMatOffsets[0][p+1] = bSecDof * allDof; 6973 } 6974 else { 6975 newPointOffsets[0][p+1] = bSecDof; 6976 pointMatOffsets[0][p+1] = 0; 6977 } 6978 } 6979 newPointOffsets[0][0] = 0; 6980 pointMatOffsets[0][0] = 0; 6981 for (p = 0; p < numPoints; p++) { 6982 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6983 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6984 } 6985 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6986 } 6987 6988 /* output arrays */ 6989 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6990 6991 /* get the point-to-point matrices; construct newPoints */ 6992 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6993 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6994 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6995 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6996 if (numFields) { 6997 for (p = 0, newP = 0; p < numPoints; p++) { 6998 PetscInt b = points[2*p]; 6999 PetscInt o = points[2*p+1]; 7000 PetscInt bDof = 0, bSecDof; 7001 7002 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7003 if (!bSecDof) { 7004 continue; 7005 } 7006 if (b >= aStart && b < aEnd) { 7007 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7008 } 7009 if (bDof) { 7010 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7011 7012 fStart[0] = 0; 7013 fEnd[0] = 0; 7014 for (f = 0; f < numFields; f++) { 7015 PetscInt fDof; 7016 7017 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7018 fStart[f+1] = fStart[f] + fDof; 7019 fEnd[f+1] = fStart[f+1]; 7020 } 7021 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7022 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7023 7024 fAnchorStart[0] = 0; 7025 fAnchorEnd[0] = 0; 7026 for (f = 0; f < numFields; f++) { 7027 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7028 7029 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7030 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7031 } 7032 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7033 for (q = 0; q < bDof; q++) { 7034 PetscInt a = anchors[bOff + q], aOff; 7035 7036 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7037 newPoints[2*(newP + q)] = a; 7038 newPoints[2*(newP + q) + 1] = 0; 7039 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7040 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7041 } 7042 newP += bDof; 7043 7044 if (outValues) { 7045 /* get the point-to-point submatrix */ 7046 for (f = 0; f < numFields; f++) { 7047 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7048 } 7049 } 7050 } 7051 else { 7052 newPoints[2 * newP] = b; 7053 newPoints[2 * newP + 1] = o; 7054 newP++; 7055 } 7056 } 7057 } else { 7058 for (p = 0; p < numPoints; p++) { 7059 PetscInt b = points[2*p]; 7060 PetscInt o = points[2*p+1]; 7061 PetscInt bDof = 0, bSecDof; 7062 7063 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7064 if (!bSecDof) { 7065 continue; 7066 } 7067 if (b >= aStart && b < aEnd) { 7068 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7069 } 7070 if (bDof) { 7071 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7072 7073 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7074 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7075 7076 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7077 for (q = 0; q < bDof; q++) { 7078 PetscInt a = anchors[bOff + q], aOff; 7079 7080 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7081 7082 newPoints[2*(newP + q)] = a; 7083 newPoints[2*(newP + q) + 1] = 0; 7084 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7085 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7086 } 7087 newP += bDof; 7088 7089 /* get the point-to-point submatrix */ 7090 if (outValues) { 7091 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7092 } 7093 } 7094 else { 7095 newPoints[2 * newP] = b; 7096 newPoints[2 * newP + 1] = o; 7097 newP++; 7098 } 7099 } 7100 } 7101 7102 if (outValues) { 7103 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7104 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7105 /* multiply constraints on the right */ 7106 if (numFields) { 7107 for (f = 0; f < numFields; f++) { 7108 PetscInt oldOff = offsets[f]; 7109 7110 for (p = 0; p < numPoints; p++) { 7111 PetscInt cStart = newPointOffsets[f][p]; 7112 PetscInt b = points[2 * p]; 7113 PetscInt c, r, k; 7114 PetscInt dof; 7115 7116 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7117 if (!dof) { 7118 continue; 7119 } 7120 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7121 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7122 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7123 7124 for (r = 0; r < numIndices; r++) { 7125 for (c = 0; c < nCols; c++) { 7126 for (k = 0; k < dof; k++) { 7127 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7128 } 7129 } 7130 } 7131 } 7132 else { 7133 /* copy this column as is */ 7134 for (r = 0; r < numIndices; r++) { 7135 for (c = 0; c < dof; c++) { 7136 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7137 } 7138 } 7139 } 7140 oldOff += dof; 7141 } 7142 } 7143 } 7144 else { 7145 PetscInt oldOff = 0; 7146 for (p = 0; p < numPoints; p++) { 7147 PetscInt cStart = newPointOffsets[0][p]; 7148 PetscInt b = points[2 * p]; 7149 PetscInt c, r, k; 7150 PetscInt dof; 7151 7152 PetscCall(PetscSectionGetDof(section,b,&dof)); 7153 if (!dof) { 7154 continue; 7155 } 7156 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7157 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7158 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7159 7160 for (r = 0; r < numIndices; r++) { 7161 for (c = 0; c < nCols; c++) { 7162 for (k = 0; k < dof; k++) { 7163 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7164 } 7165 } 7166 } 7167 } 7168 else { 7169 /* copy this column as is */ 7170 for (r = 0; r < numIndices; r++) { 7171 for (c = 0; c < dof; c++) { 7172 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7173 } 7174 } 7175 } 7176 oldOff += dof; 7177 } 7178 } 7179 7180 if (multiplyLeft) { 7181 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7182 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7183 /* multiply constraints transpose on the left */ 7184 if (numFields) { 7185 for (f = 0; f < numFields; f++) { 7186 PetscInt oldOff = offsets[f]; 7187 7188 for (p = 0; p < numPoints; p++) { 7189 PetscInt rStart = newPointOffsets[f][p]; 7190 PetscInt b = points[2 * p]; 7191 PetscInt c, r, k; 7192 PetscInt dof; 7193 7194 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7195 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7196 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7197 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7198 7199 for (r = 0; r < nRows; r++) { 7200 for (c = 0; c < newNumIndices; c++) { 7201 for (k = 0; k < dof; k++) { 7202 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7203 } 7204 } 7205 } 7206 } 7207 else { 7208 /* copy this row as is */ 7209 for (r = 0; r < dof; r++) { 7210 for (c = 0; c < newNumIndices; c++) { 7211 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7212 } 7213 } 7214 } 7215 oldOff += dof; 7216 } 7217 } 7218 } 7219 else { 7220 PetscInt oldOff = 0; 7221 7222 for (p = 0; p < numPoints; p++) { 7223 PetscInt rStart = newPointOffsets[0][p]; 7224 PetscInt b = points[2 * p]; 7225 PetscInt c, r, k; 7226 PetscInt dof; 7227 7228 PetscCall(PetscSectionGetDof(section,b,&dof)); 7229 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7230 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7231 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7232 7233 for (r = 0; r < nRows; r++) { 7234 for (c = 0; c < newNumIndices; c++) { 7235 for (k = 0; k < dof; k++) { 7236 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7237 } 7238 } 7239 } 7240 } 7241 else { 7242 /* copy this row as is */ 7243 for (r = 0; r < dof; r++) { 7244 for (c = 0; c < newNumIndices; c++) { 7245 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7246 } 7247 } 7248 } 7249 oldOff += dof; 7250 } 7251 } 7252 7253 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7254 } 7255 else { 7256 newValues = tmpValues; 7257 } 7258 } 7259 7260 /* clean up */ 7261 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7262 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7263 7264 if (numFields) { 7265 for (f = 0; f < numFields; f++) { 7266 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7267 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7268 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7269 } 7270 } 7271 else { 7272 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7273 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7274 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7275 } 7276 PetscCall(ISRestoreIndices(aIS,&anchors)); 7277 7278 /* output */ 7279 if (outPoints) { 7280 *outPoints = newPoints; 7281 } 7282 else { 7283 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7284 } 7285 if (outValues) { 7286 *outValues = newValues; 7287 } 7288 for (f = 0; f <= numFields; f++) { 7289 offsets[f] = newOffsets[f]; 7290 } 7291 PetscFunctionReturn(0); 7292 } 7293 7294 /*@C 7295 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7296 7297 Not collective 7298 7299 Input Parameters: 7300 + dm - The DM 7301 . section - The PetscSection describing the points (a local section) 7302 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7303 . point - The point defining the closure 7304 - useClPerm - Use the closure point permutation if available 7305 7306 Output Parameters: 7307 + numIndices - The number of dof indices in the closure of point with the input sections 7308 . indices - The dof indices 7309 . outOffsets - Array to write the field offsets into, or NULL 7310 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7311 7312 Notes: 7313 Must call DMPlexRestoreClosureIndices() to free allocated memory 7314 7315 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7316 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7317 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7318 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7319 indices (with the above semantics) are implied. 7320 7321 Level: advanced 7322 7323 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7324 @*/ 7325 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7326 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7327 { 7328 /* Closure ordering */ 7329 PetscSection clSection; 7330 IS clPoints; 7331 const PetscInt *clp; 7332 PetscInt *points; 7333 const PetscInt *clperm = NULL; 7334 /* Dof permutation and sign flips */ 7335 const PetscInt **perms[32] = {NULL}; 7336 const PetscScalar **flips[32] = {NULL}; 7337 PetscScalar *valCopy = NULL; 7338 /* Hanging node constraints */ 7339 PetscInt *pointsC = NULL; 7340 PetscScalar *valuesC = NULL; 7341 PetscInt NclC, NiC; 7342 7343 PetscInt *idx; 7344 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7345 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7346 7347 PetscFunctionBeginHot; 7348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7349 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7350 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7351 if (numIndices) PetscValidIntPointer(numIndices, 6); 7352 if (indices) PetscValidPointer(indices, 7); 7353 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7354 if (values) PetscValidPointer(values, 9); 7355 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7356 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7357 PetscCall(PetscArrayzero(offsets, 32)); 7358 /* 1) Get points in closure */ 7359 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7360 if (useClPerm) { 7361 PetscInt depth, clsize; 7362 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7363 for (clsize=0,p=0; p<Ncl; p++) { 7364 PetscInt dof; 7365 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7366 clsize += dof; 7367 } 7368 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7369 } 7370 /* 2) Get number of indices on these points and field offsets from section */ 7371 for (p = 0; p < Ncl*2; p += 2) { 7372 PetscInt dof, fdof; 7373 7374 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7375 for (f = 0; f < Nf; ++f) { 7376 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7377 offsets[f+1] += fdof; 7378 } 7379 Ni += dof; 7380 } 7381 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7382 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7383 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7384 for (f = 0; f < PetscMax(1, Nf); ++f) { 7385 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7386 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7387 /* may need to apply sign changes to the element matrix */ 7388 if (values && flips[f]) { 7389 PetscInt foffset = offsets[f]; 7390 7391 for (p = 0; p < Ncl; ++p) { 7392 PetscInt pnt = points[2*p], fdof; 7393 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7394 7395 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7396 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7397 if (flip) { 7398 PetscInt i, j, k; 7399 7400 if (!valCopy) { 7401 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7402 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7403 *values = valCopy; 7404 } 7405 for (i = 0; i < fdof; ++i) { 7406 PetscScalar fval = flip[i]; 7407 7408 for (k = 0; k < Ni; ++k) { 7409 valCopy[Ni * (foffset + i) + k] *= fval; 7410 valCopy[Ni * k + (foffset + i)] *= fval; 7411 } 7412 } 7413 } 7414 foffset += fdof; 7415 } 7416 } 7417 } 7418 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7419 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7420 if (NclC) { 7421 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7422 for (f = 0; f < PetscMax(1, Nf); ++f) { 7423 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7424 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7425 } 7426 for (f = 0; f < PetscMax(1, Nf); ++f) { 7427 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7428 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7429 } 7430 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7431 Ncl = NclC; 7432 Ni = NiC; 7433 points = pointsC; 7434 if (values) *values = valuesC; 7435 } 7436 /* 5) Calculate indices */ 7437 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7438 if (Nf) { 7439 PetscInt idxOff; 7440 PetscBool useFieldOffsets; 7441 7442 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7443 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7444 if (useFieldOffsets) { 7445 for (p = 0; p < Ncl; ++p) { 7446 const PetscInt pnt = points[p*2]; 7447 7448 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7449 } 7450 } else { 7451 for (p = 0; p < Ncl; ++p) { 7452 const PetscInt pnt = points[p*2]; 7453 7454 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7455 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7456 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7457 * global section. */ 7458 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7459 } 7460 } 7461 } else { 7462 PetscInt off = 0, idxOff; 7463 7464 for (p = 0; p < Ncl; ++p) { 7465 const PetscInt pnt = points[p*2]; 7466 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7467 7468 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7469 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7470 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7471 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7472 } 7473 } 7474 /* 6) Cleanup */ 7475 for (f = 0; f < PetscMax(1, Nf); ++f) { 7476 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7477 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7478 } 7479 if (NclC) { 7480 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7481 } else { 7482 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7483 } 7484 7485 if (numIndices) *numIndices = Ni; 7486 if (indices) *indices = idx; 7487 PetscFunctionReturn(0); 7488 } 7489 7490 /*@C 7491 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7492 7493 Not collective 7494 7495 Input Parameters: 7496 + dm - The DM 7497 . section - The PetscSection describing the points (a local section) 7498 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7499 . point - The point defining the closure 7500 - useClPerm - Use the closure point permutation if available 7501 7502 Output Parameters: 7503 + numIndices - The number of dof indices in the closure of point with the input sections 7504 . indices - The dof indices 7505 . outOffsets - Array to write the field offsets into, or NULL 7506 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7507 7508 Notes: 7509 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7510 7511 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7512 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7513 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7514 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7515 indices (with the above semantics) are implied. 7516 7517 Level: advanced 7518 7519 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7520 @*/ 7521 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7522 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7523 { 7524 PetscFunctionBegin; 7525 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7526 PetscValidPointer(indices, 7); 7527 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7528 PetscFunctionReturn(0); 7529 } 7530 7531 /*@C 7532 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7533 7534 Not collective 7535 7536 Input Parameters: 7537 + dm - The DM 7538 . section - The section describing the layout in v, or NULL to use the default section 7539 . globalSection - The section describing the layout in v, or NULL to use the default global section 7540 . A - The matrix 7541 . point - The point in the DM 7542 . values - The array of values 7543 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7544 7545 Fortran Notes: 7546 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7547 7548 Level: intermediate 7549 7550 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7551 @*/ 7552 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7553 { 7554 DM_Plex *mesh = (DM_Plex*) dm->data; 7555 PetscInt *indices; 7556 PetscInt numIndices; 7557 const PetscScalar *valuesOrig = values; 7558 PetscErrorCode ierr; 7559 7560 PetscFunctionBegin; 7561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7562 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7563 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7564 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7565 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7566 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7567 7568 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7569 7570 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7571 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7572 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7573 if (ierr) { 7574 PetscMPIInt rank; 7575 7576 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7577 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7578 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7579 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7580 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7581 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7582 } 7583 if (mesh->printFEM > 1) { 7584 PetscInt i; 7585 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7586 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7587 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7588 } 7589 7590 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7591 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7592 PetscFunctionReturn(0); 7593 } 7594 7595 /*@C 7596 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7597 7598 Not collective 7599 7600 Input Parameters: 7601 + dmRow - The DM for the row fields 7602 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7603 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7604 . dmCol - The DM for the column fields 7605 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7606 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7607 . A - The matrix 7608 . point - The point in the DMs 7609 . values - The array of values 7610 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7611 7612 Level: intermediate 7613 7614 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7615 @*/ 7616 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7617 { 7618 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7619 PetscInt *indicesRow, *indicesCol; 7620 PetscInt numIndicesRow, numIndicesCol; 7621 const PetscScalar *valuesOrig = values; 7622 PetscErrorCode ierr; 7623 7624 PetscFunctionBegin; 7625 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7626 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7627 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7628 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7629 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7630 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7631 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7632 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7633 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7634 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7635 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7636 7637 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7638 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7639 7640 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7641 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7642 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7643 if (ierr) { 7644 PetscMPIInt rank; 7645 7646 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7647 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7648 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7649 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7650 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7651 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7652 } 7653 7654 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7655 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7656 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7657 PetscFunctionReturn(0); 7658 } 7659 7660 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7661 { 7662 DM_Plex *mesh = (DM_Plex*) dmf->data; 7663 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7664 PetscInt *cpoints = NULL; 7665 PetscInt *findices, *cindices; 7666 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7667 PetscInt foffsets[32], coffsets[32]; 7668 DMPolytopeType ct; 7669 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7670 PetscErrorCode ierr; 7671 7672 PetscFunctionBegin; 7673 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7674 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7675 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7676 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7677 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7678 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7679 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7680 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7681 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7682 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7683 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7684 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7685 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7686 PetscCall(PetscArrayzero(foffsets, 32)); 7687 PetscCall(PetscArrayzero(coffsets, 32)); 7688 /* Column indices */ 7689 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7690 maxFPoints = numCPoints; 7691 /* Compress out points not in the section */ 7692 /* TODO: Squeeze out points with 0 dof as well */ 7693 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7694 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7695 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7696 cpoints[q*2] = cpoints[p]; 7697 cpoints[q*2+1] = cpoints[p+1]; 7698 ++q; 7699 } 7700 } 7701 numCPoints = q; 7702 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7703 PetscInt fdof; 7704 7705 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7706 if (!dof) continue; 7707 for (f = 0; f < numFields; ++f) { 7708 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7709 coffsets[f+1] += fdof; 7710 } 7711 numCIndices += dof; 7712 } 7713 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7714 /* Row indices */ 7715 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7716 { 7717 DMPlexTransform tr; 7718 DMPolytopeType *rct; 7719 PetscInt *rsize, *rcone, *rornt, Nt; 7720 7721 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7722 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7723 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7724 numSubcells = rsize[Nt-1]; 7725 PetscCall(DMPlexTransformDestroy(&tr)); 7726 } 7727 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7728 for (r = 0, q = 0; r < numSubcells; ++r) { 7729 /* TODO Map from coarse to fine cells */ 7730 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7731 /* Compress out points not in the section */ 7732 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7733 for (p = 0; p < numFPoints*2; p += 2) { 7734 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7735 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7736 if (!dof) continue; 7737 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7738 if (s < q) continue; 7739 ftotpoints[q*2] = fpoints[p]; 7740 ftotpoints[q*2+1] = fpoints[p+1]; 7741 ++q; 7742 } 7743 } 7744 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7745 } 7746 numFPoints = q; 7747 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7748 PetscInt fdof; 7749 7750 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7751 if (!dof) continue; 7752 for (f = 0; f < numFields; ++f) { 7753 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7754 foffsets[f+1] += fdof; 7755 } 7756 numFIndices += dof; 7757 } 7758 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7759 7760 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7761 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7762 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7763 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7764 if (numFields) { 7765 const PetscInt **permsF[32] = {NULL}; 7766 const PetscInt **permsC[32] = {NULL}; 7767 7768 for (f = 0; f < numFields; f++) { 7769 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7770 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7771 } 7772 for (p = 0; p < numFPoints; p++) { 7773 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7774 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7775 } 7776 for (p = 0; p < numCPoints; p++) { 7777 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7778 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7779 } 7780 for (f = 0; f < numFields; f++) { 7781 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7782 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7783 } 7784 } else { 7785 const PetscInt **permsF = NULL; 7786 const PetscInt **permsC = NULL; 7787 7788 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7789 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7790 for (p = 0, off = 0; p < numFPoints; p++) { 7791 const PetscInt *perm = permsF ? permsF[p] : NULL; 7792 7793 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7794 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7795 } 7796 for (p = 0, off = 0; p < numCPoints; p++) { 7797 const PetscInt *perm = permsC ? permsC[p] : NULL; 7798 7799 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7800 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7801 } 7802 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7803 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7804 } 7805 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7806 /* TODO: flips */ 7807 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7808 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7809 if (ierr) { 7810 PetscMPIInt rank; 7811 7812 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7813 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7814 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7815 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7816 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7817 } 7818 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7819 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7820 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7821 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7822 PetscFunctionReturn(0); 7823 } 7824 7825 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7826 { 7827 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7828 PetscInt *cpoints = NULL; 7829 PetscInt foffsets[32], coffsets[32]; 7830 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7831 DMPolytopeType ct; 7832 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7833 7834 PetscFunctionBegin; 7835 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7836 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7837 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7838 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7839 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7840 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7841 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7842 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7843 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7844 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7845 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7846 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7847 PetscCall(PetscArrayzero(foffsets, 32)); 7848 PetscCall(PetscArrayzero(coffsets, 32)); 7849 /* Column indices */ 7850 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7851 maxFPoints = numCPoints; 7852 /* Compress out points not in the section */ 7853 /* TODO: Squeeze out points with 0 dof as well */ 7854 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7855 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7856 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7857 cpoints[q*2] = cpoints[p]; 7858 cpoints[q*2+1] = cpoints[p+1]; 7859 ++q; 7860 } 7861 } 7862 numCPoints = q; 7863 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7864 PetscInt fdof; 7865 7866 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7867 if (!dof) continue; 7868 for (f = 0; f < numFields; ++f) { 7869 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7870 coffsets[f+1] += fdof; 7871 } 7872 numCIndices += dof; 7873 } 7874 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7875 /* Row indices */ 7876 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7877 { 7878 DMPlexTransform tr; 7879 DMPolytopeType *rct; 7880 PetscInt *rsize, *rcone, *rornt, Nt; 7881 7882 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7883 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7884 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7885 numSubcells = rsize[Nt-1]; 7886 PetscCall(DMPlexTransformDestroy(&tr)); 7887 } 7888 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7889 for (r = 0, q = 0; r < numSubcells; ++r) { 7890 /* TODO Map from coarse to fine cells */ 7891 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7892 /* Compress out points not in the section */ 7893 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7894 for (p = 0; p < numFPoints*2; p += 2) { 7895 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7896 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7897 if (!dof) continue; 7898 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7899 if (s < q) continue; 7900 ftotpoints[q*2] = fpoints[p]; 7901 ftotpoints[q*2+1] = fpoints[p+1]; 7902 ++q; 7903 } 7904 } 7905 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7906 } 7907 numFPoints = q; 7908 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7909 PetscInt fdof; 7910 7911 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7912 if (!dof) continue; 7913 for (f = 0; f < numFields; ++f) { 7914 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7915 foffsets[f+1] += fdof; 7916 } 7917 numFIndices += dof; 7918 } 7919 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7920 7921 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7922 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7923 if (numFields) { 7924 const PetscInt **permsF[32] = {NULL}; 7925 const PetscInt **permsC[32] = {NULL}; 7926 7927 for (f = 0; f < numFields; f++) { 7928 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7929 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7930 } 7931 for (p = 0; p < numFPoints; p++) { 7932 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7933 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7934 } 7935 for (p = 0; p < numCPoints; p++) { 7936 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7937 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7938 } 7939 for (f = 0; f < numFields; f++) { 7940 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7941 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7942 } 7943 } else { 7944 const PetscInt **permsF = NULL; 7945 const PetscInt **permsC = NULL; 7946 7947 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7948 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7949 for (p = 0, off = 0; p < numFPoints; p++) { 7950 const PetscInt *perm = permsF ? permsF[p] : NULL; 7951 7952 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7953 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7954 } 7955 for (p = 0, off = 0; p < numCPoints; p++) { 7956 const PetscInt *perm = permsC ? permsC[p] : NULL; 7957 7958 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7959 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7960 } 7961 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7962 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7963 } 7964 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7965 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7966 PetscFunctionReturn(0); 7967 } 7968 7969 /*@C 7970 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7971 7972 Input Parameter: 7973 . dm - The DMPlex object 7974 7975 Output Parameter: 7976 . cellHeight - The height of a cell 7977 7978 Level: developer 7979 7980 .seealso `DMPlexSetVTKCellHeight()` 7981 @*/ 7982 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7983 { 7984 DM_Plex *mesh = (DM_Plex*) dm->data; 7985 7986 PetscFunctionBegin; 7987 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7988 PetscValidIntPointer(cellHeight, 2); 7989 *cellHeight = mesh->vtkCellHeight; 7990 PetscFunctionReturn(0); 7991 } 7992 7993 /*@C 7994 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7995 7996 Input Parameters: 7997 + dm - The DMPlex object 7998 - cellHeight - The height of a cell 7999 8000 Level: developer 8001 8002 .seealso `DMPlexGetVTKCellHeight()` 8003 @*/ 8004 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8005 { 8006 DM_Plex *mesh = (DM_Plex*) dm->data; 8007 8008 PetscFunctionBegin; 8009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8010 mesh->vtkCellHeight = cellHeight; 8011 PetscFunctionReturn(0); 8012 } 8013 8014 /*@ 8015 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8016 8017 Input Parameter: 8018 . dm - The DMPlex object 8019 8020 Output Parameters: 8021 + gcStart - The first ghost cell, or NULL 8022 - gcEnd - The upper bound on ghost cells, or NULL 8023 8024 Level: advanced 8025 8026 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8027 @*/ 8028 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8029 { 8030 DMLabel ctLabel; 8031 8032 PetscFunctionBegin; 8033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8034 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8035 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8036 // Reset label for fast lookup 8037 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8038 PetscFunctionReturn(0); 8039 } 8040 8041 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8042 { 8043 PetscSection section, globalSection; 8044 PetscInt *numbers, p; 8045 8046 PetscFunctionBegin; 8047 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8048 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8049 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8050 for (p = pStart; p < pEnd; ++p) { 8051 PetscCall(PetscSectionSetDof(section, p, 1)); 8052 } 8053 PetscCall(PetscSectionSetUp(section)); 8054 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8055 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8056 for (p = pStart; p < pEnd; ++p) { 8057 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8058 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8059 else numbers[p-pStart] += shift; 8060 } 8061 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8062 if (globalSize) { 8063 PetscLayout layout; 8064 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8065 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8066 PetscCall(PetscLayoutDestroy(&layout)); 8067 } 8068 PetscCall(PetscSectionDestroy(§ion)); 8069 PetscCall(PetscSectionDestroy(&globalSection)); 8070 PetscFunctionReturn(0); 8071 } 8072 8073 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8074 { 8075 PetscInt cellHeight, cStart, cEnd; 8076 8077 PetscFunctionBegin; 8078 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8079 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8080 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8081 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8082 PetscFunctionReturn(0); 8083 } 8084 8085 /*@ 8086 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8087 8088 Input Parameter: 8089 . dm - The DMPlex object 8090 8091 Output Parameter: 8092 . globalCellNumbers - Global cell numbers for all cells on this process 8093 8094 Level: developer 8095 8096 .seealso `DMPlexGetVertexNumbering()` 8097 @*/ 8098 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8099 { 8100 DM_Plex *mesh = (DM_Plex*) dm->data; 8101 8102 PetscFunctionBegin; 8103 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8104 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8105 *globalCellNumbers = mesh->globalCellNumbers; 8106 PetscFunctionReturn(0); 8107 } 8108 8109 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8110 { 8111 PetscInt vStart, vEnd; 8112 8113 PetscFunctionBegin; 8114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8115 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8116 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8117 PetscFunctionReturn(0); 8118 } 8119 8120 /*@ 8121 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8122 8123 Input Parameter: 8124 . dm - The DMPlex object 8125 8126 Output Parameter: 8127 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8128 8129 Level: developer 8130 8131 .seealso `DMPlexGetCellNumbering()` 8132 @*/ 8133 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8134 { 8135 DM_Plex *mesh = (DM_Plex*) dm->data; 8136 8137 PetscFunctionBegin; 8138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8139 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8140 *globalVertexNumbers = mesh->globalVertexNumbers; 8141 PetscFunctionReturn(0); 8142 } 8143 8144 /*@ 8145 DMPlexCreatePointNumbering - Create a global numbering for all points. 8146 8147 Collective on dm 8148 8149 Input Parameter: 8150 . dm - The DMPlex object 8151 8152 Output Parameter: 8153 . globalPointNumbers - Global numbers for all points on this process 8154 8155 Notes: 8156 8157 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8158 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8159 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8160 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8161 8162 The partitioned mesh is 8163 ``` 8164 (2)--0--(3)--1--(4) (1)--0--(2) 8165 ``` 8166 and its global numbering is 8167 ``` 8168 (3)--0--(4)--1--(5)--2--(6) 8169 ``` 8170 Then the global numbering is provided as 8171 ``` 8172 [0] Number of indices in set 5 8173 [0] 0 0 8174 [0] 1 1 8175 [0] 2 3 8176 [0] 3 4 8177 [0] 4 -6 8178 [1] Number of indices in set 3 8179 [1] 0 2 8180 [1] 1 5 8181 [1] 2 6 8182 ``` 8183 8184 Level: developer 8185 8186 .seealso `DMPlexGetCellNumbering()` 8187 @*/ 8188 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8189 { 8190 IS nums[4]; 8191 PetscInt depths[4], gdepths[4], starts[4]; 8192 PetscInt depth, d, shift = 0; 8193 8194 PetscFunctionBegin; 8195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8196 PetscCall(DMPlexGetDepth(dm, &depth)); 8197 /* For unstratified meshes use dim instead of depth */ 8198 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8199 for (d = 0; d <= depth; ++d) { 8200 PetscInt end; 8201 8202 depths[d] = depth-d; 8203 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8204 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8205 } 8206 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8207 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8208 for (d = 0; d <= depth; ++d) { 8209 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]); 8210 } 8211 for (d = 0; d <= depth; ++d) { 8212 PetscInt pStart, pEnd, gsize; 8213 8214 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8215 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8216 shift += gsize; 8217 } 8218 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8219 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8220 PetscFunctionReturn(0); 8221 } 8222 8223 /*@ 8224 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8225 8226 Input Parameter: 8227 . dm - The DMPlex object 8228 8229 Output Parameter: 8230 . ranks - The rank field 8231 8232 Options Database Keys: 8233 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8234 8235 Level: intermediate 8236 8237 .seealso: `DMView()` 8238 @*/ 8239 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8240 { 8241 DM rdm; 8242 PetscFE fe; 8243 PetscScalar *r; 8244 PetscMPIInt rank; 8245 DMPolytopeType ct; 8246 PetscInt dim, cStart, cEnd, c; 8247 PetscBool simplex; 8248 8249 PetscFunctionBeginUser; 8250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8251 PetscValidPointer(ranks, 2); 8252 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8253 PetscCall(DMClone(dm, &rdm)); 8254 PetscCall(DMGetDimension(rdm, &dim)); 8255 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8256 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8257 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8258 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8259 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8260 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8261 PetscCall(PetscFEDestroy(&fe)); 8262 PetscCall(DMCreateDS(rdm)); 8263 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8264 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8265 PetscCall(VecGetArray(*ranks, &r)); 8266 for (c = cStart; c < cEnd; ++c) { 8267 PetscScalar *lr; 8268 8269 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8270 if (lr) *lr = rank; 8271 } 8272 PetscCall(VecRestoreArray(*ranks, &r)); 8273 PetscCall(DMDestroy(&rdm)); 8274 PetscFunctionReturn(0); 8275 } 8276 8277 /*@ 8278 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8279 8280 Input Parameters: 8281 + dm - The DMPlex 8282 - label - The DMLabel 8283 8284 Output Parameter: 8285 . val - The label value field 8286 8287 Options Database Keys: 8288 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8289 8290 Level: intermediate 8291 8292 .seealso: `DMView()` 8293 @*/ 8294 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8295 { 8296 DM rdm; 8297 PetscFE fe; 8298 PetscScalar *v; 8299 PetscInt dim, cStart, cEnd, c; 8300 8301 PetscFunctionBeginUser; 8302 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8303 PetscValidPointer(label, 2); 8304 PetscValidPointer(val, 3); 8305 PetscCall(DMClone(dm, &rdm)); 8306 PetscCall(DMGetDimension(rdm, &dim)); 8307 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8308 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8309 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8310 PetscCall(PetscFEDestroy(&fe)); 8311 PetscCall(DMCreateDS(rdm)); 8312 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8313 PetscCall(DMCreateGlobalVector(rdm, val)); 8314 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8315 PetscCall(VecGetArray(*val, &v)); 8316 for (c = cStart; c < cEnd; ++c) { 8317 PetscScalar *lv; 8318 PetscInt cval; 8319 8320 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8321 PetscCall(DMLabelGetValue(label, c, &cval)); 8322 *lv = cval; 8323 } 8324 PetscCall(VecRestoreArray(*val, &v)); 8325 PetscCall(DMDestroy(&rdm)); 8326 PetscFunctionReturn(0); 8327 } 8328 8329 /*@ 8330 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8331 8332 Input Parameter: 8333 . dm - The DMPlex object 8334 8335 Notes: 8336 This is a useful diagnostic when creating meshes programmatically. 8337 8338 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8339 8340 Level: developer 8341 8342 .seealso: `DMCreate()`, `DMSetFromOptions()` 8343 @*/ 8344 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8345 { 8346 PetscSection coneSection, supportSection; 8347 const PetscInt *cone, *support; 8348 PetscInt coneSize, c, supportSize, s; 8349 PetscInt pStart, pEnd, p, pp, csize, ssize; 8350 PetscBool storagecheck = PETSC_TRUE; 8351 8352 PetscFunctionBegin; 8353 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8354 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8355 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8356 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8357 /* Check that point p is found in the support of its cone points, and vice versa */ 8358 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8359 for (p = pStart; p < pEnd; ++p) { 8360 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8361 PetscCall(DMPlexGetCone(dm, p, &cone)); 8362 for (c = 0; c < coneSize; ++c) { 8363 PetscBool dup = PETSC_FALSE; 8364 PetscInt d; 8365 for (d = c-1; d >= 0; --d) { 8366 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8367 } 8368 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8369 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8370 for (s = 0; s < supportSize; ++s) { 8371 if (support[s] == p) break; 8372 } 8373 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8374 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8375 for (s = 0; s < coneSize; ++s) { 8376 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8377 } 8378 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8379 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8380 for (s = 0; s < supportSize; ++s) { 8381 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8382 } 8383 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8384 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]); 8385 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8386 } 8387 } 8388 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8389 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8390 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8391 PetscCall(DMPlexGetSupport(dm, p, &support)); 8392 for (s = 0; s < supportSize; ++s) { 8393 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8394 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8395 for (c = 0; c < coneSize; ++c) { 8396 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8397 if (cone[c] != pp) { c = 0; break; } 8398 if (cone[c] == p) break; 8399 } 8400 if (c >= coneSize) { 8401 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8402 for (c = 0; c < supportSize; ++c) { 8403 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8404 } 8405 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8406 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8407 for (c = 0; c < coneSize; ++c) { 8408 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8409 } 8410 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8411 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8412 } 8413 } 8414 } 8415 if (storagecheck) { 8416 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8417 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8418 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8419 } 8420 PetscFunctionReturn(0); 8421 } 8422 8423 /* 8424 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. 8425 */ 8426 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8427 { 8428 DMPolytopeType cct; 8429 PetscInt ptpoints[4]; 8430 const PetscInt *cone, *ccone, *ptcone; 8431 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8432 8433 PetscFunctionBegin; 8434 *unsplit = 0; 8435 switch (ct) { 8436 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8437 ptpoints[npt++] = c; 8438 break; 8439 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8440 PetscCall(DMPlexGetCone(dm, c, &cone)); 8441 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8442 for (cp = 0; cp < coneSize; ++cp) { 8443 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8444 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8445 } 8446 break; 8447 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8448 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8449 PetscCall(DMPlexGetCone(dm, c, &cone)); 8450 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8451 for (cp = 0; cp < coneSize; ++cp) { 8452 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8453 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8454 for (ccp = 0; ccp < cconeSize; ++ccp) { 8455 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8456 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8457 PetscInt p; 8458 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8459 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8460 } 8461 } 8462 } 8463 break; 8464 default: break; 8465 } 8466 for (pt = 0; pt < npt; ++pt) { 8467 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8468 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8469 } 8470 PetscFunctionReturn(0); 8471 } 8472 8473 /*@ 8474 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8475 8476 Input Parameters: 8477 + dm - The DMPlex object 8478 - cellHeight - Normally 0 8479 8480 Notes: 8481 This is a useful diagnostic when creating meshes programmatically. 8482 Currently applicable only to homogeneous simplex or tensor meshes. 8483 8484 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8485 8486 Level: developer 8487 8488 .seealso: `DMCreate()`, `DMSetFromOptions()` 8489 @*/ 8490 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8491 { 8492 DMPlexInterpolatedFlag interp; 8493 DMPolytopeType ct; 8494 PetscInt vStart, vEnd, cStart, cEnd, c; 8495 8496 PetscFunctionBegin; 8497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8498 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8499 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8500 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8501 for (c = cStart; c < cEnd; ++c) { 8502 PetscInt *closure = NULL; 8503 PetscInt coneSize, closureSize, cl, Nv = 0; 8504 8505 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8506 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8507 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8508 if (interp == DMPLEX_INTERPOLATED_FULL) { 8509 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8510 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)); 8511 } 8512 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8513 for (cl = 0; cl < closureSize*2; cl += 2) { 8514 const PetscInt p = closure[cl]; 8515 if ((p >= vStart) && (p < vEnd)) ++Nv; 8516 } 8517 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8518 /* Special Case: Tensor faces with identified vertices */ 8519 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8520 PetscInt unsplit; 8521 8522 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8523 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8524 } 8525 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)); 8526 } 8527 PetscFunctionReturn(0); 8528 } 8529 8530 /*@ 8531 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8532 8533 Collective 8534 8535 Input Parameters: 8536 + dm - The DMPlex object 8537 - cellHeight - Normally 0 8538 8539 Notes: 8540 This is a useful diagnostic when creating meshes programmatically. 8541 This routine is only relevant for meshes that are fully interpolated across all ranks. 8542 It will error out if a partially interpolated mesh is given on some rank. 8543 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8544 8545 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8546 8547 Level: developer 8548 8549 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8550 @*/ 8551 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8552 { 8553 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8554 DMPlexInterpolatedFlag interpEnum; 8555 8556 PetscFunctionBegin; 8557 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8558 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8559 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8560 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8561 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8562 PetscFunctionReturn(0); 8563 } 8564 8565 PetscCall(DMGetDimension(dm, &dim)); 8566 PetscCall(DMPlexGetDepth(dm, &depth)); 8567 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8568 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8569 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8570 for (c = cStart; c < cEnd; ++c) { 8571 const PetscInt *cone, *ornt, *faceSizes, *faces; 8572 const DMPolytopeType *faceTypes; 8573 DMPolytopeType ct; 8574 PetscInt numFaces, coneSize, f; 8575 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8576 8577 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8578 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8579 if (unsplit) continue; 8580 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8581 PetscCall(DMPlexGetCone(dm, c, &cone)); 8582 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8583 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8584 for (cl = 0; cl < closureSize*2; cl += 2) { 8585 const PetscInt p = closure[cl]; 8586 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8587 } 8588 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8589 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); 8590 for (f = 0; f < numFaces; ++f) { 8591 DMPolytopeType fct; 8592 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8593 8594 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8595 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8596 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8597 const PetscInt p = fclosure[cl]; 8598 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8599 } 8600 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]); 8601 for (v = 0; v < fnumCorners; ++v) { 8602 if (fclosure[v] != faces[fOff+v]) { 8603 PetscInt v1; 8604 8605 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8606 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8607 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8608 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8609 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8610 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]); 8611 } 8612 } 8613 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8614 fOff += faceSizes[f]; 8615 } 8616 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8617 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8618 } 8619 } 8620 PetscFunctionReturn(0); 8621 } 8622 8623 /*@ 8624 DMPlexCheckGeometry - Check the geometry of mesh cells 8625 8626 Input Parameter: 8627 . dm - The DMPlex object 8628 8629 Notes: 8630 This is a useful diagnostic when creating meshes programmatically. 8631 8632 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8633 8634 Level: developer 8635 8636 .seealso: `DMCreate()`, `DMSetFromOptions()` 8637 @*/ 8638 PetscErrorCode DMPlexCheckGeometry(DM dm) 8639 { 8640 Vec coordinates; 8641 PetscReal detJ, J[9], refVol = 1.0; 8642 PetscReal vol; 8643 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8644 8645 PetscFunctionBegin; 8646 PetscCall(DMGetDimension(dm, &dim)); 8647 PetscCall(DMGetCoordinateDim(dm, &dE)); 8648 if (dim != dE) PetscFunctionReturn(0); 8649 PetscCall(DMPlexGetDepth(dm, &depth)); 8650 for (d = 0; d < dim; ++d) refVol *= 2.0; 8651 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8652 /* Make sure local coordinates are created, because that step is collective */ 8653 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8654 for (c = cStart; c < cEnd; ++c) { 8655 DMPolytopeType ct; 8656 PetscInt unsplit; 8657 PetscBool ignoreZeroVol = PETSC_FALSE; 8658 8659 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8660 switch (ct) { 8661 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8662 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8663 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8664 ignoreZeroVol = PETSC_TRUE; break; 8665 default: break; 8666 } 8667 switch (ct) { 8668 case DM_POLYTOPE_TRI_PRISM: 8669 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8670 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8671 case DM_POLYTOPE_PYRAMID: 8672 continue; 8673 default: break; 8674 } 8675 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8676 if (unsplit) continue; 8677 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8678 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); 8679 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8680 /* This should work with periodicity since DG coordinates should be used */ 8681 if (depth > 1) { 8682 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8683 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); 8684 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8685 } 8686 } 8687 PetscFunctionReturn(0); 8688 } 8689 8690 /*@ 8691 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8692 8693 Collective 8694 8695 Input Parameters: 8696 + dm - The DMPlex object 8697 - pointSF - The Point SF, or NULL for Point SF attached to DM 8698 8699 Notes: 8700 This is mainly intended for debugging/testing purposes. 8701 8702 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8703 8704 Level: developer 8705 8706 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8707 @*/ 8708 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8709 { 8710 PetscInt l, nleaves, nroots, overlap; 8711 const PetscInt *locals; 8712 const PetscSFNode *remotes; 8713 PetscBool distributed; 8714 MPI_Comm comm; 8715 PetscMPIInt rank; 8716 8717 PetscFunctionBegin; 8718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8719 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8720 else pointSF = dm->sf; 8721 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8722 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8723 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8724 { 8725 PetscMPIInt mpiFlag; 8726 8727 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8728 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8729 } 8730 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8731 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8732 if (!distributed) { 8733 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); 8734 PetscFunctionReturn(0); 8735 } 8736 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); 8737 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8738 8739 /* Check SF graph is compatible with DMPlex chart */ 8740 { 8741 PetscInt pStart, pEnd, maxLeaf; 8742 8743 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8744 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8745 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8746 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8747 } 8748 8749 /* Check Point SF has no local points referenced */ 8750 for (l = 0; l < nleaves; l++) { 8751 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); 8752 } 8753 8754 /* Check there are no cells in interface */ 8755 if (!overlap) { 8756 PetscInt cellHeight, cStart, cEnd; 8757 8758 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8759 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8760 for (l = 0; l < nleaves; ++l) { 8761 const PetscInt point = locals ? locals[l] : l; 8762 8763 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8764 } 8765 } 8766 8767 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8768 { 8769 const PetscInt *rootdegree; 8770 8771 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8772 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8773 for (l = 0; l < nleaves; ++l) { 8774 const PetscInt point = locals ? locals[l] : l; 8775 const PetscInt *cone; 8776 PetscInt coneSize, c, idx; 8777 8778 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8779 PetscCall(DMPlexGetCone(dm, point, &cone)); 8780 for (c = 0; c < coneSize; ++c) { 8781 if (!rootdegree[cone[c]]) { 8782 if (locals) { 8783 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8784 } else { 8785 idx = (cone[c] < nleaves) ? cone[c] : -1; 8786 } 8787 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8788 } 8789 } 8790 } 8791 } 8792 PetscFunctionReturn(0); 8793 } 8794 8795 /*@ 8796 DMPlexCheck - Perform various checks of Plex sanity 8797 8798 Input Parameter: 8799 . dm - The DMPlex object 8800 8801 Notes: 8802 This is a useful diagnostic when creating meshes programmatically. 8803 8804 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8805 8806 Currently does not include DMPlexCheckCellShape(). 8807 8808 Level: developer 8809 8810 .seealso: DMCreate(), DMSetFromOptions() 8811 @*/ 8812 PetscErrorCode DMPlexCheck(DM dm) 8813 { 8814 PetscInt cellHeight; 8815 8816 PetscFunctionBegin; 8817 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8818 PetscCall(DMPlexCheckSymmetry(dm)); 8819 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8820 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8821 PetscCall(DMPlexCheckGeometry(dm)); 8822 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8823 PetscCall(DMPlexCheckInterfaceCones(dm)); 8824 PetscFunctionReturn(0); 8825 } 8826 8827 typedef struct cell_stats 8828 { 8829 PetscReal min, max, sum, squaresum; 8830 PetscInt count; 8831 } cell_stats_t; 8832 8833 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8834 { 8835 PetscInt i, N = *len; 8836 8837 for (i = 0; i < N; i++) { 8838 cell_stats_t *A = (cell_stats_t *) a; 8839 cell_stats_t *B = (cell_stats_t *) b; 8840 8841 B->min = PetscMin(A->min,B->min); 8842 B->max = PetscMax(A->max,B->max); 8843 B->sum += A->sum; 8844 B->squaresum += A->squaresum; 8845 B->count += A->count; 8846 } 8847 } 8848 8849 /*@ 8850 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8851 8852 Collective on dm 8853 8854 Input Parameters: 8855 + dm - The DMPlex object 8856 . output - If true, statistics will be displayed on stdout 8857 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8858 8859 Notes: 8860 This is mainly intended for debugging/testing purposes. 8861 8862 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8863 8864 Level: developer 8865 8866 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8867 @*/ 8868 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8869 { 8870 DM dmCoarse; 8871 cell_stats_t stats, globalStats; 8872 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8873 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8874 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8875 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8876 PetscMPIInt rank,size; 8877 8878 PetscFunctionBegin; 8879 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8880 stats.min = PETSC_MAX_REAL; 8881 stats.max = PETSC_MIN_REAL; 8882 stats.sum = stats.squaresum = 0.; 8883 stats.count = 0; 8884 8885 PetscCallMPI(MPI_Comm_size(comm, &size)); 8886 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8887 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8888 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8889 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8890 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8891 for (c = cStart; c < cEnd; c++) { 8892 PetscInt i; 8893 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8894 8895 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8896 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8897 for (i = 0; i < PetscSqr(cdim); ++i) { 8898 frobJ += J[i] * J[i]; 8899 frobInvJ += invJ[i] * invJ[i]; 8900 } 8901 cond2 = frobJ * frobInvJ; 8902 cond = PetscSqrtReal(cond2); 8903 8904 stats.min = PetscMin(stats.min,cond); 8905 stats.max = PetscMax(stats.max,cond); 8906 stats.sum += cond; 8907 stats.squaresum += cond2; 8908 stats.count++; 8909 if (output && cond > limit) { 8910 PetscSection coordSection; 8911 Vec coordsLocal; 8912 PetscScalar *coords = NULL; 8913 PetscInt Nv, d, clSize, cl, *closure = NULL; 8914 8915 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8916 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8917 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8918 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8919 for (i = 0; i < Nv/cdim; ++i) { 8920 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8921 for (d = 0; d < cdim; ++d) { 8922 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8923 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8924 } 8925 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8926 } 8927 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8928 for (cl = 0; cl < clSize*2; cl += 2) { 8929 const PetscInt edge = closure[cl]; 8930 8931 if ((edge >= eStart) && (edge < eEnd)) { 8932 PetscReal len; 8933 8934 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8935 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8936 } 8937 } 8938 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8939 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8940 } 8941 } 8942 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8943 8944 if (size > 1) { 8945 PetscMPIInt blockLengths[2] = {4,1}; 8946 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8947 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8948 MPI_Op statReduce; 8949 8950 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8951 PetscCallMPI(MPI_Type_commit(&statType)); 8952 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8953 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8954 PetscCallMPI(MPI_Op_free(&statReduce)); 8955 PetscCallMPI(MPI_Type_free(&statType)); 8956 } else { 8957 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8958 } 8959 if (rank == 0) { 8960 count = globalStats.count; 8961 min = globalStats.min; 8962 max = globalStats.max; 8963 mean = globalStats.sum / globalStats.count; 8964 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8965 } 8966 8967 if (output) { 8968 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)); 8969 } 8970 PetscCall(PetscFree2(J,invJ)); 8971 8972 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8973 if (dmCoarse) { 8974 PetscBool isplex; 8975 8976 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8977 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8978 } 8979 PetscFunctionReturn(0); 8980 } 8981 8982 /*@ 8983 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8984 orthogonal quality below given tolerance. 8985 8986 Collective on dm 8987 8988 Input Parameters: 8989 + dm - The DMPlex object 8990 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8991 - atol - [0, 1] Absolute tolerance for tagging cells. 8992 8993 Output Parameters: 8994 + OrthQual - Vec containing orthogonal quality per cell 8995 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8996 8997 Options Database Keys: 8998 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8999 supported. 9000 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9001 9002 Notes: 9003 Orthogonal quality is given by the following formula: 9004 9005 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 9006 9007 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 9008 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9009 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9010 calculating the cosine of the angle between these vectors. 9011 9012 Orthogonal quality ranges from 1 (best) to 0 (worst). 9013 9014 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 9015 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9016 9017 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9018 9019 Level: intermediate 9020 9021 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 9022 @*/ 9023 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9024 { 9025 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9026 PetscInt *idx; 9027 PetscScalar *oqVals; 9028 const PetscScalar *cellGeomArr, *faceGeomArr; 9029 PetscReal *ci, *fi, *Ai; 9030 MPI_Comm comm; 9031 Vec cellgeom, facegeom; 9032 DM dmFace, dmCell; 9033 IS glob; 9034 ISLocalToGlobalMapping ltog; 9035 PetscViewer vwr; 9036 9037 PetscFunctionBegin; 9038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9039 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 9040 PetscValidPointer(OrthQual, 4); 9041 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 9042 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 9043 PetscCall(DMGetDimension(dm, &nc)); 9044 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9045 { 9046 DMPlexInterpolatedFlag interpFlag; 9047 9048 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9049 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9050 PetscMPIInt rank; 9051 9052 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9053 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9054 } 9055 } 9056 if (OrthQualLabel) { 9057 PetscValidPointer(OrthQualLabel, 5); 9058 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9059 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9060 } else {*OrthQualLabel = NULL;} 9061 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9062 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9063 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9064 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9065 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9066 PetscCall(VecCreate(comm, OrthQual)); 9067 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9068 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9069 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9070 PetscCall(VecSetUp(*OrthQual)); 9071 PetscCall(ISDestroy(&glob)); 9072 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9073 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9074 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9075 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9076 PetscCall(VecGetDM(cellgeom, &dmCell)); 9077 PetscCall(VecGetDM(facegeom, &dmFace)); 9078 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9079 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9080 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9081 PetscInt cellarr[2], *adj = NULL; 9082 PetscScalar *cArr, *fArr; 9083 PetscReal minvalc = 1.0, minvalf = 1.0; 9084 PetscFVCellGeom *cg; 9085 9086 idx[cellIter] = cell-cStart; 9087 cellarr[0] = cell; 9088 /* Make indexing into cellGeom easier */ 9089 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9090 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9091 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9092 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9093 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9094 PetscInt i; 9095 const PetscInt neigh = adj[cellneigh]; 9096 PetscReal normci = 0, normfi = 0, normai = 0; 9097 PetscFVCellGeom *cgneigh; 9098 PetscFVFaceGeom *fg; 9099 9100 /* Don't count ourselves in the neighbor list */ 9101 if (neigh == cell) continue; 9102 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9103 cellarr[1] = neigh; 9104 { 9105 PetscInt numcovpts; 9106 const PetscInt *covpts; 9107 9108 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9109 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9110 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9111 } 9112 9113 /* Compute c_i, f_i and their norms */ 9114 for (i = 0; i < nc; i++) { 9115 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9116 fi[i] = fg->centroid[i] - cg->centroid[i]; 9117 Ai[i] = fg->normal[i]; 9118 normci += PetscPowReal(ci[i], 2); 9119 normfi += PetscPowReal(fi[i], 2); 9120 normai += PetscPowReal(Ai[i], 2); 9121 } 9122 normci = PetscSqrtReal(normci); 9123 normfi = PetscSqrtReal(normfi); 9124 normai = PetscSqrtReal(normai); 9125 9126 /* Normalize and compute for each face-cell-normal pair */ 9127 for (i = 0; i < nc; i++) { 9128 ci[i] = ci[i]/normci; 9129 fi[i] = fi[i]/normfi; 9130 Ai[i] = Ai[i]/normai; 9131 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9132 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9133 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9134 } 9135 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9136 minvalc = PetscRealPart(cArr[cellneighiter]); 9137 } 9138 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9139 minvalf = PetscRealPart(fArr[cellneighiter]); 9140 } 9141 } 9142 PetscCall(PetscFree(adj)); 9143 PetscCall(PetscFree2(cArr, fArr)); 9144 /* Defer to cell if they're equal */ 9145 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9146 if (OrthQualLabel) { 9147 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9148 } 9149 } 9150 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9151 PetscCall(VecAssemblyBegin(*OrthQual)); 9152 PetscCall(VecAssemblyEnd(*OrthQual)); 9153 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9154 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9155 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9156 if (OrthQualLabel) { 9157 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9158 } 9159 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9160 PetscCall(PetscViewerDestroy(&vwr)); 9161 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9162 PetscFunctionReturn(0); 9163 } 9164 9165 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9166 * interpolator construction */ 9167 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9168 { 9169 PetscSection section, newSection, gsection; 9170 PetscSF sf; 9171 PetscBool hasConstraints, ghasConstraints; 9172 9173 PetscFunctionBegin; 9174 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9175 PetscValidPointer(odm,2); 9176 PetscCall(DMGetLocalSection(dm, §ion)); 9177 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9178 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9179 if (!ghasConstraints) { 9180 PetscCall(PetscObjectReference((PetscObject)dm)); 9181 *odm = dm; 9182 PetscFunctionReturn(0); 9183 } 9184 PetscCall(DMClone(dm, odm)); 9185 PetscCall(DMCopyFields(dm, *odm)); 9186 PetscCall(DMGetLocalSection(*odm, &newSection)); 9187 PetscCall(DMGetPointSF(*odm, &sf)); 9188 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9189 PetscCall(DMSetGlobalSection(*odm, gsection)); 9190 PetscCall(PetscSectionDestroy(&gsection)); 9191 PetscFunctionReturn(0); 9192 } 9193 9194 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9195 { 9196 DM dmco, dmfo; 9197 Mat interpo; 9198 Vec rscale; 9199 Vec cglobalo, clocal; 9200 Vec fglobal, fglobalo, flocal; 9201 PetscBool regular; 9202 9203 PetscFunctionBegin; 9204 PetscCall(DMGetFullDM(dmc, &dmco)); 9205 PetscCall(DMGetFullDM(dmf, &dmfo)); 9206 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9207 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9208 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9209 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9210 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9211 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9212 PetscCall(VecSet(cglobalo, 0.)); 9213 PetscCall(VecSet(clocal, 0.)); 9214 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9215 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9216 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9217 PetscCall(VecSet(fglobal, 0.)); 9218 PetscCall(VecSet(fglobalo, 0.)); 9219 PetscCall(VecSet(flocal, 0.)); 9220 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9221 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9222 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9223 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9224 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9225 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9226 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9227 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9228 *shift = fglobal; 9229 PetscCall(VecDestroy(&flocal)); 9230 PetscCall(VecDestroy(&fglobalo)); 9231 PetscCall(VecDestroy(&clocal)); 9232 PetscCall(VecDestroy(&cglobalo)); 9233 PetscCall(VecDestroy(&rscale)); 9234 PetscCall(MatDestroy(&interpo)); 9235 PetscCall(DMDestroy(&dmfo)); 9236 PetscCall(DMDestroy(&dmco)); 9237 PetscFunctionReturn(0); 9238 } 9239 9240 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9241 { 9242 PetscObject shifto; 9243 Vec shift; 9244 9245 PetscFunctionBegin; 9246 if (!interp) { 9247 Vec rscale; 9248 9249 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9250 PetscCall(VecDestroy(&rscale)); 9251 } else { 9252 PetscCall(PetscObjectReference((PetscObject)interp)); 9253 } 9254 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9255 if (!shifto) { 9256 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9257 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9258 shifto = (PetscObject) shift; 9259 PetscCall(VecDestroy(&shift)); 9260 } 9261 shift = (Vec) shifto; 9262 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9263 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9264 PetscCall(MatDestroy(&interp)); 9265 PetscFunctionReturn(0); 9266 } 9267 9268 /* Pointwise interpolation 9269 Just code FEM for now 9270 u^f = I u^c 9271 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9272 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9273 I_{ij} = psi^f_i phi^c_j 9274 */ 9275 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9276 { 9277 PetscSection gsc, gsf; 9278 PetscInt m, n; 9279 void *ctx; 9280 DM cdm; 9281 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9282 9283 PetscFunctionBegin; 9284 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9285 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9286 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9287 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9288 9289 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9290 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9291 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9292 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9293 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9294 9295 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9296 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9297 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9298 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9299 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9300 if (scaling) { 9301 /* Use naive scaling */ 9302 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9303 } 9304 PetscFunctionReturn(0); 9305 } 9306 9307 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9308 { 9309 VecScatter ctx; 9310 9311 PetscFunctionBegin; 9312 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9313 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9314 PetscCall(VecScatterDestroy(&ctx)); 9315 PetscFunctionReturn(0); 9316 } 9317 9318 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9319 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9320 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9321 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9322 { 9323 const PetscInt Nc = uOff[1] - uOff[0]; 9324 PetscInt c; 9325 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9326 } 9327 9328 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9329 { 9330 DM dmc; 9331 PetscDS ds; 9332 Vec ones, locmass; 9333 IS cellIS; 9334 PetscFormKey key; 9335 PetscInt depth; 9336 9337 PetscFunctionBegin; 9338 PetscCall(DMClone(dm, &dmc)); 9339 PetscCall(DMCopyDisc(dm, dmc)); 9340 PetscCall(DMGetDS(dmc, &ds)); 9341 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9342 PetscCall(DMCreateGlobalVector(dmc, mass)); 9343 PetscCall(DMGetLocalVector(dmc, &ones)); 9344 PetscCall(DMGetLocalVector(dmc, &locmass)); 9345 PetscCall(DMPlexGetDepth(dmc, &depth)); 9346 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9347 PetscCall(VecSet(locmass, 0.0)); 9348 PetscCall(VecSet(ones, 1.0)); 9349 key.label = NULL; 9350 key.value = 0; 9351 key.field = 0; 9352 key.part = 0; 9353 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9354 PetscCall(ISDestroy(&cellIS)); 9355 PetscCall(VecSet(*mass, 0.0)); 9356 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9357 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9358 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9359 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9360 PetscCall(DMDestroy(&dmc)); 9361 PetscFunctionReturn(0); 9362 } 9363 9364 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9365 { 9366 PetscSection gsc, gsf; 9367 PetscInt m, n; 9368 void *ctx; 9369 DM cdm; 9370 PetscBool regular; 9371 9372 PetscFunctionBegin; 9373 if (dmFine == dmCoarse) { 9374 DM dmc; 9375 PetscDS ds; 9376 PetscWeakForm wf; 9377 Vec u; 9378 IS cellIS; 9379 PetscFormKey key; 9380 PetscInt depth; 9381 9382 PetscCall(DMClone(dmFine, &dmc)); 9383 PetscCall(DMCopyDisc(dmFine, dmc)); 9384 PetscCall(DMGetDS(dmc, &ds)); 9385 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9386 PetscCall(PetscWeakFormClear(wf)); 9387 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9388 PetscCall(DMCreateMatrix(dmc, mass)); 9389 PetscCall(DMGetLocalVector(dmc, &u)); 9390 PetscCall(DMPlexGetDepth(dmc, &depth)); 9391 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9392 PetscCall(MatZeroEntries(*mass)); 9393 key.label = NULL; 9394 key.value = 0; 9395 key.field = 0; 9396 key.part = 0; 9397 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9398 PetscCall(ISDestroy(&cellIS)); 9399 PetscCall(DMRestoreLocalVector(dmc, &u)); 9400 PetscCall(DMDestroy(&dmc)); 9401 } else { 9402 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9403 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9404 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9405 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9406 9407 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9408 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9409 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9410 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9411 9412 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9413 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9414 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9415 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9416 } 9417 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9418 PetscFunctionReturn(0); 9419 } 9420 9421 /*@ 9422 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9423 9424 Input Parameter: 9425 . dm - The DMPlex object 9426 9427 Output Parameter: 9428 . regular - The flag 9429 9430 Level: intermediate 9431 9432 .seealso: `DMPlexSetRegularRefinement()` 9433 @*/ 9434 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9435 { 9436 PetscFunctionBegin; 9437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9438 PetscValidBoolPointer(regular, 2); 9439 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9440 PetscFunctionReturn(0); 9441 } 9442 9443 /*@ 9444 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9445 9446 Input Parameters: 9447 + dm - The DMPlex object 9448 - regular - The flag 9449 9450 Level: intermediate 9451 9452 .seealso: `DMPlexGetRegularRefinement()` 9453 @*/ 9454 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9455 { 9456 PetscFunctionBegin; 9457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9458 ((DM_Plex *) dm->data)->regularRefinement = regular; 9459 PetscFunctionReturn(0); 9460 } 9461 9462 /* anchors */ 9463 /*@ 9464 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9465 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9466 9467 not collective 9468 9469 Input Parameter: 9470 . dm - The DMPlex object 9471 9472 Output Parameters: 9473 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9474 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9475 9476 Level: intermediate 9477 9478 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9479 @*/ 9480 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9481 { 9482 DM_Plex *plex = (DM_Plex *)dm->data; 9483 9484 PetscFunctionBegin; 9485 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9486 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9487 if (anchorSection) *anchorSection = plex->anchorSection; 9488 if (anchorIS) *anchorIS = plex->anchorIS; 9489 PetscFunctionReturn(0); 9490 } 9491 9492 /*@ 9493 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9494 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9495 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9496 9497 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9498 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9499 9500 collective on dm 9501 9502 Input Parameters: 9503 + dm - The DMPlex object 9504 . 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). 9505 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9506 9507 The reference counts of anchorSection and anchorIS are incremented. 9508 9509 Level: intermediate 9510 9511 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9512 @*/ 9513 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9514 { 9515 DM_Plex *plex = (DM_Plex *)dm->data; 9516 PetscMPIInt result; 9517 9518 PetscFunctionBegin; 9519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9520 if (anchorSection) { 9521 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9522 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9523 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9524 } 9525 if (anchorIS) { 9526 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9527 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9528 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9529 } 9530 9531 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9532 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9533 plex->anchorSection = anchorSection; 9534 9535 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9536 PetscCall(ISDestroy(&plex->anchorIS)); 9537 plex->anchorIS = anchorIS; 9538 9539 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9540 PetscInt size, a, pStart, pEnd; 9541 const PetscInt *anchors; 9542 9543 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9544 PetscCall(ISGetLocalSize(anchorIS,&size)); 9545 PetscCall(ISGetIndices(anchorIS,&anchors)); 9546 for (a = 0; a < size; a++) { 9547 PetscInt p; 9548 9549 p = anchors[a]; 9550 if (p >= pStart && p < pEnd) { 9551 PetscInt dof; 9552 9553 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9554 if (dof) { 9555 9556 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9557 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9558 } 9559 } 9560 } 9561 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9562 } 9563 /* reset the generic constraints */ 9564 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9565 PetscFunctionReturn(0); 9566 } 9567 9568 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9569 { 9570 PetscSection anchorSection; 9571 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9572 9573 PetscFunctionBegin; 9574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9575 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9576 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9577 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9578 if (numFields) { 9579 PetscInt f; 9580 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9581 9582 for (f = 0; f < numFields; f++) { 9583 PetscInt numComp; 9584 9585 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9586 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9587 } 9588 } 9589 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9590 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9591 pStart = PetscMax(pStart,sStart); 9592 pEnd = PetscMin(pEnd,sEnd); 9593 pEnd = PetscMax(pStart,pEnd); 9594 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9595 for (p = pStart; p < pEnd; p++) { 9596 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9597 if (dof) { 9598 PetscCall(PetscSectionGetDof(section,p,&dof)); 9599 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9600 for (f = 0; f < numFields; f++) { 9601 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9602 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9603 } 9604 } 9605 } 9606 PetscCall(PetscSectionSetUp(*cSec)); 9607 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9608 PetscFunctionReturn(0); 9609 } 9610 9611 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9612 { 9613 PetscSection aSec; 9614 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9615 const PetscInt *anchors; 9616 PetscInt numFields, f; 9617 IS aIS; 9618 MatType mtype; 9619 PetscBool iscuda,iskokkos; 9620 9621 PetscFunctionBegin; 9622 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9623 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9624 PetscCall(PetscSectionGetStorageSize(section, &n)); 9625 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9626 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9627 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9628 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9629 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9630 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9631 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9632 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9633 else mtype = MATSEQAIJ; 9634 PetscCall(MatSetType(*cMat,mtype)); 9635 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9636 PetscCall(ISGetIndices(aIS,&anchors)); 9637 /* cSec will be a subset of aSec and section */ 9638 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9639 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9640 PetscCall(PetscMalloc1(m+1,&i)); 9641 i[0] = 0; 9642 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9643 for (p = pStart; p < pEnd; p++) { 9644 PetscInt rDof, rOff, r; 9645 9646 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9647 if (!rDof) continue; 9648 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9649 if (numFields) { 9650 for (f = 0; f < numFields; f++) { 9651 annz = 0; 9652 for (r = 0; r < rDof; r++) { 9653 a = anchors[rOff + r]; 9654 if (a < sStart || a >= sEnd) continue; 9655 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9656 annz += aDof; 9657 } 9658 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9659 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9660 for (q = 0; q < dof; q++) { 9661 i[off + q + 1] = i[off + q] + annz; 9662 } 9663 } 9664 } else { 9665 annz = 0; 9666 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9667 for (q = 0; q < dof; q++) { 9668 a = anchors[rOff + q]; 9669 if (a < sStart || a >= sEnd) continue; 9670 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9671 annz += aDof; 9672 } 9673 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9674 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9675 for (q = 0; q < dof; q++) { 9676 i[off + q + 1] = i[off + q] + annz; 9677 } 9678 } 9679 } 9680 nnz = i[m]; 9681 PetscCall(PetscMalloc1(nnz,&j)); 9682 offset = 0; 9683 for (p = pStart; p < pEnd; p++) { 9684 if (numFields) { 9685 for (f = 0; f < numFields; f++) { 9686 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9687 for (q = 0; q < dof; q++) { 9688 PetscInt rDof, rOff, r; 9689 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9690 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9691 for (r = 0; r < rDof; r++) { 9692 PetscInt s; 9693 9694 a = anchors[rOff + r]; 9695 if (a < sStart || a >= sEnd) continue; 9696 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9697 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9698 for (s = 0; s < aDof; s++) { 9699 j[offset++] = aOff + s; 9700 } 9701 } 9702 } 9703 } 9704 } else { 9705 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9706 for (q = 0; q < dof; q++) { 9707 PetscInt rDof, rOff, r; 9708 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9709 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9710 for (r = 0; r < rDof; r++) { 9711 PetscInt s; 9712 9713 a = anchors[rOff + r]; 9714 if (a < sStart || a >= sEnd) continue; 9715 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9716 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9717 for (s = 0; s < aDof; s++) { 9718 j[offset++] = aOff + s; 9719 } 9720 } 9721 } 9722 } 9723 } 9724 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9725 PetscCall(PetscFree(i)); 9726 PetscCall(PetscFree(j)); 9727 PetscCall(ISRestoreIndices(aIS,&anchors)); 9728 PetscFunctionReturn(0); 9729 } 9730 9731 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9732 { 9733 DM_Plex *plex = (DM_Plex *)dm->data; 9734 PetscSection anchorSection, section, cSec; 9735 Mat cMat; 9736 9737 PetscFunctionBegin; 9738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9739 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9740 if (anchorSection) { 9741 PetscInt Nf; 9742 9743 PetscCall(DMGetLocalSection(dm,§ion)); 9744 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9745 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9746 PetscCall(DMGetNumFields(dm,&Nf)); 9747 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9748 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9749 PetscCall(PetscSectionDestroy(&cSec)); 9750 PetscCall(MatDestroy(&cMat)); 9751 } 9752 PetscFunctionReturn(0); 9753 } 9754 9755 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9756 { 9757 IS subis; 9758 PetscSection section, subsection; 9759 9760 PetscFunctionBegin; 9761 PetscCall(DMGetLocalSection(dm, §ion)); 9762 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9763 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9764 /* Create subdomain */ 9765 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9766 /* Create submodel */ 9767 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9768 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9769 PetscCall(DMSetLocalSection(*subdm, subsection)); 9770 PetscCall(PetscSectionDestroy(&subsection)); 9771 PetscCall(DMCopyDisc(dm, *subdm)); 9772 /* Create map from submodel to global model */ 9773 if (is) { 9774 PetscSection sectionGlobal, subsectionGlobal; 9775 IS spIS; 9776 const PetscInt *spmap; 9777 PetscInt *subIndices; 9778 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9779 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9780 9781 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9782 PetscCall(ISGetIndices(spIS, &spmap)); 9783 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9784 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9785 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9786 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9787 for (p = pStart; p < pEnd; ++p) { 9788 PetscInt gdof, pSubSize = 0; 9789 9790 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9791 if (gdof > 0) { 9792 for (f = 0; f < Nf; ++f) { 9793 PetscInt fdof, fcdof; 9794 9795 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9796 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9797 pSubSize += fdof-fcdof; 9798 } 9799 subSize += pSubSize; 9800 if (pSubSize) { 9801 if (bs < 0) { 9802 bs = pSubSize; 9803 } else if (bs != pSubSize) { 9804 /* Layout does not admit a pointwise block size */ 9805 bs = 1; 9806 } 9807 } 9808 } 9809 } 9810 /* Must have same blocksize on all procs (some might have no points) */ 9811 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9812 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9813 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9814 else {bs = bsMinMax[0];} 9815 PetscCall(PetscMalloc1(subSize, &subIndices)); 9816 for (p = pStart; p < pEnd; ++p) { 9817 PetscInt gdof, goff; 9818 9819 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9820 if (gdof > 0) { 9821 const PetscInt point = spmap[p]; 9822 9823 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9824 for (f = 0; f < Nf; ++f) { 9825 PetscInt fdof, fcdof, fc, f2, poff = 0; 9826 9827 /* Can get rid of this loop by storing field information in the global section */ 9828 for (f2 = 0; f2 < f; ++f2) { 9829 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9830 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9831 poff += fdof-fcdof; 9832 } 9833 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9834 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9835 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9836 subIndices[subOff] = goff+poff+fc; 9837 } 9838 } 9839 } 9840 } 9841 PetscCall(ISRestoreIndices(spIS, &spmap)); 9842 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9843 if (bs > 1) { 9844 /* We need to check that the block size does not come from non-contiguous fields */ 9845 PetscInt i, j, set = 1; 9846 for (i = 0; i < subSize; i += bs) { 9847 for (j = 0; j < bs; ++j) { 9848 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9849 } 9850 } 9851 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9852 } 9853 /* Attach nullspace */ 9854 for (f = 0; f < Nf; ++f) { 9855 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9856 if ((*subdm)->nullspaceConstructors[f]) break; 9857 } 9858 if (f < Nf) { 9859 MatNullSpace nullSpace; 9860 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9861 9862 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9863 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9864 } 9865 } 9866 PetscFunctionReturn(0); 9867 } 9868 9869 /*@ 9870 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9871 9872 Input Parameter: 9873 - dm - The DM 9874 9875 Level: developer 9876 9877 Options Database Keys: 9878 . -dm_plex_monitor_throughput - Activate the monitor 9879 9880 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9881 @*/ 9882 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9883 { 9884 #if defined(PETSC_USE_LOG) 9885 PetscStageLog stageLog; 9886 PetscLogEvent event; 9887 PetscLogStage stage; 9888 PetscEventPerfInfo eventInfo; 9889 PetscReal cellRate, flopRate; 9890 PetscInt cStart, cEnd, Nf, N; 9891 const char *name; 9892 #endif 9893 9894 PetscFunctionBegin; 9895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9896 #if defined(PETSC_USE_LOG) 9897 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9898 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9899 PetscCall(DMGetNumFields(dm, &Nf)); 9900 PetscCall(PetscLogGetStageLog(&stageLog)); 9901 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9902 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9903 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9904 N = (cEnd - cStart)*Nf*eventInfo.count; 9905 flopRate = eventInfo.flops/eventInfo.time; 9906 cellRate = N/eventInfo.time; 9907 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))); 9908 #else 9909 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9910 #endif 9911 PetscFunctionReturn(0); 9912 } 9913