Package: classy-blocks
classy_blocksPython classes for easier creation of OpenFOAM's blockMesh dictionaries.Warning! This project is currently under development and is not yet very user-friendly. It still lacks some important features and probably features a lot of bugs. However, you're welcome to suggest features, improvements, and point out bugs.Note: version 1.0.0 introduced backwards-incompatible changes in API. Uselatest 0.0.1 commitfor your old scripts. However, you might want to give the new version a try...AboutblockMeshis a very powerful mesher but the amount of manual labour it requires to make even the simplest
meshes makes it mostly useless. Even attempts to simplify or parametrize blockMeshDicts with#calcor even
the dreadfulm4quickly become unmanageable and cryptic.classy_blocks' aim is to minimize the amount of meticulous work by providing a
more intuitive workflow, off-the-shelf parts and some automatic helpers for building and optimization of block-structured hexahedral meshes.
Still it is not an automatic mesher and therefore some kinds of geometry are more suited than others.TutorialCheck out theclassy_blocks tutorial on damogranlabs.com!Useful ForFieldsTurbomachinery (impellers, propellers)MicrofluidicsFlow around buildingsHeat transfer (PCB models, heatsinks)Airfoils (2D)Solids (heat transfer, mechanical stresses)CasesSimpler rotational geometry (immersed rotors, mixers, cyclones)Pipes/channelsTanks/plenums/containersExternal aerodynamics of blunt bodiesModeling thin geometry (seals, labyrinths)Parametric studiesBackground meshes for snappy (cylindrical, custom)2D and axisymmetric casesOverset meshesNot Good ForExternal aerodynamics of vehicles (too complex to mesh manually, without refinement generates too many cells)Complex geometry in generalOne-off simulations (use automatic meshers)How To Use ItTo install the currentstableversion from pypi, usepip install classy_blocksTo download the cutting-edge development version, unstall the development branch from github:pip install git+https://github.com/damogranlabs/classy_blocks.git@developmentIf you want to run examples, follow instructions inExamplesIf you want to contribute, follow instructions inCONTRIBUTING.rstFeaturesWorkflowAs opposed to blockMesh, where the user is expected to manually enter pre-calculated vertices, edges, blocks and whatnot, classy_blocks tries to mimic procedural modeling of modern 3D CAD programs. Here, a Python script contains steps that describe geometry of blocks, their cell count, grading, patches and so on. At the end, the procedure is translated directly to blockMeshDict and no manual editing of the latter should be required.Building ElementsUnchecked items are not implemented yet but are on a TODO listManual definition of a Block with Vertices, Edges and FacesOperations (Loft, Extrude, Revolve)LoftExtrudeRevolveWedge (a shortcut to Revolve for 2D axisymmetric cases)Predefined ShapesBox (shortcut to Block aligned with coordinate system)Elbow (bent pipe of various diameters/cross-sections)Cone Frustum (truncated cone)CylinderRing (annulus)HemispherePredefined parametric ObjectsT-joint (round pipes)X-jointN-joint (multiple pipes)Box with hole (radial)Box with hole (cartesian)Other building toolsUse existing Operation's Face to generate a new OperationChain Shape's start/end surface to generate a new ShapeExpand Shape's outer surface to generate a new Shape (Cylinder/Annulus > Annulus)Contract Shape's inner surface into a new Shape (Annulus > Cylinder/Annulus)Join two Operations by extending their EdgesOffset Operation's faces to form new operationsModifiersAfter blocks have been placed, it is possible to create new geometry based on placed blocks or to modify them.Move Vertex/Edge/FaceDelete a Block created by a Shape or ObjectProject Vertex/Edge/FaceOptimize Vertex positionsMeshing SpecificationSimple definition of all supported kinds of edges with a dedicated class (Arc/Origin/Angle/Spline/PolyLine/Project)Automatic sorting/reorienting of block vertices based on specifiedfrontandtoppointsAutomatic calculation of cell count and grading by specifying any of a number of parameters (cell-to-cell expansion ratio, start cell width, end cell width, total expansion ratio)Edge grading(separate specification for each edge)Automatic propagation of grading and cell count from a single block to all connected blocks as required by blockMeshProjections of vertices, edges and block faces to geometry (triangulated andsearchable surfaces)Face merging as described byblockMesh user guide. Breaks the pure-hexahedral-mesh rule but can often save the day for trickier geometries. Automatic duplication of points on merged block facesAuto grading for Low-Re meshes: boundary layer with specified cell-to-cell expansion, transition with 2:1 expansion, and specified 'bulk' cell sizeExamplesHow to run:Installclassy_blocksas described abovecdto directory of the chosen exampleRunpython <example.py>; that will write blockMeshDict to examples/caseRunblockMeshon the caseOpenexamples/case/case.foamin ParaView to view the resultFor instance:cdexamples/chaining
pythontank.py
blockMesh-case../caseShapesA simple Cylinder:inlet=cb.Cylinder([x_start,0,0],[x_end,0,0],[0,0,radius])inlet.chop_radial(count=n_cells_radial,end_size=boundary_layer_thickness)inlet.chop_axial(start_size=axial_cell_size,end_size=2*axial_cell_size)inlet.chop_tangential(count=n_cells_tangential)inlet.set_start_patch('inlet')inlet.set_outer_patch('wall')inlet.set_end_patch('outlet')mesh.add(inlet)Seeexamples/shapefor use of eachshapeandexamples/complexfor a more real-life example usage of shapes.OperationsAnalogous to a sketch in 3D CAD software, a Face is a set of 4 vertices and 4 edges.
AnOperationis a 3D shape obtained by swiping a Face into 3rd dimension by a specified rule; an example of Revolve:# a quadrangle with one curved sidebase=cb.Face([# quad vertices[0,0,0],[1,0,0],[1,1,0],[0,1,0]],[# edges: None specifies straight edgecb.Arc([0.5,-0.2,0]),None,None,None])revolve=cb.Revolve(base,# face to revolvef.deg2rad(45),# revolve angle[0,-1,0],# axis[-2,0,0]# origin)revolve.chop(0,count=15)# first edgerevolve.chop(1,count=15)# second edgerevolve.chop(2,start_size=0.05)# revolve directionmesh.add(revolve)Seeexamples/operationsfor an example of each operation.Projection To GeometryAny geometry that snappyHexMesh understandsis also supported by blockMesh.
That includes searchable surfaces such as spheres and cylinders and triangulated surfaces.Projecting a block side to a geometry is straightforward; edges, however, can be projected to a single geometry (will 'snap' to the closest point) or to an intersection of two surfaces, which will define it exactly.Geometry is specified as a simple dictionary of strings and is thrown in blockMeshDict exactly as provided by the user.geometry={'terrain':['type triSurfaceMesh','name terrain','file "terrain.stl"',],'left_wall':['type       searchablePlane','planeType  pointAndNormal','point      (-1 0 0)','normal     (1  0  0)',]}box=cb.Box([-1.,-1.,-1.],[1.,1.,1.])box.project_side('bottom','terrain')box.project_edge(0,1,'terrain')box.project_edge(3,0,['terrain','left_wall'])Face MergingSimply provide names of patches to be merged and callmesh.merge_patches(<master>, <slave>).
classy_blocks will take care of point duplication and whatnot.box=cb.Box([-0.5,-0.5,0],[0.5,0.5,1])foriinrange(3):box.chop(i,count=25)box.set_patch('top','box_top')mesh.add(box)cylinder=cb.Cylinder([0,0,1],[0,0,2],[0.25,0,1])cylinder.chop_axial(count=10)cylinder.chop_radial(count=10)cylinder.chop_tangential(count=20)cylinder.set_bottom_patch('cylinder_bottom')mesh.add(cylinder)mesh.merge_patches('box_top','cylinder_bottom')Chaining and Expanding/ContractingUseful for Shapes, mostly for piping and rotational geometry; An existing Shape's start or end sketch can be reused as a
starting sketch for a new Shape, as long as they are compatible.
For instance, anElbowcan bechainedto aCylinderjust like joining pipes in plumbing.Moreover, most shapes* can be expanded to form awallversion of the same shape. For instance, expanding aCylindercreates anExtrudedRing.Seeexamples/chainingfor an example of each operation.Offsetting FacesIt is possible to create new blocks by offsetting existing blocks' faces.
As an example, a sphere can be created by offsetting all six faces of a simple box,
then projected to asearchableSphere.Seeexamples/shapes/shell.pyfor the sphere tutorial.Automatic Blocking OptimizationOnce an approximate blocking is established, one can fetch specific vertices and specifies certain degrees of freedom along which those vertices will be moved to get blocks of better quality.Block is treated as a single cell for which OpenFOAM's cell quality criteria are calculated and optimized per user's instructions.Vertices can move freely (3 degrees of freedom), along a specified line/curve (1 DoF) or surface (2 DoF).# [...] A simple setup with two cylinders of different radii,# connected by a short conical frustum that has bad cells# [...]mesh.assemble()# Find inside vertices at connecting frustumfinder=cb.RoundSolidFinder(mesh,frustum)inner_vertices=finder.find_core(True).union(finder.find_core(False))optimizer=cb.Optimizer(mesh)# Move chosen vertices along a line, parallel to x-axisforvertexininner_vertices:clamp=cb.LineClamp(vertex,vertex.position,vertex.position+f.vector(1,0,0))optimizer.release_vertex(clamp)optimizer.optimize()mesh.write(os.path.join("..","case","system","blockMeshDict"),debug_path="debug.vtk")The result (basic blocking > optimized):Seeexamples/optimizationfor the diffuser example.DebuggingBy default, adebug.vtkfile is created where each block represents a hexahedral cell.
By showingblock_idswith a proper color scale the blocking can be visualized.
This is useful when blockMesh fails with errors reporting invalid/inside-out blocks but VTK will
happily show anything.ShowcaseThese are some screenshots of parametric models, built with classy_blocks.Rectangular ducts (Extrude and Revolve Operations)3D pipes with twists and turns (chained Elbow and Cylinder Shapes)A simple tank with rounded edgesA flywheel in a case. VTK Blocking output for debug is shown in the middleVenturi tube2D mesh for studying Karman Vortex StreetHelmholtz nozzle, a resonator with sharp edges. Seethis sketch.Edges and faces, projected to an STL surfaceMesh for studying flow around a sphere, with projected edges and facesAirfoil core with blunt trailing edge (imported points from NACA generator) and adjustable angle of attack. Exact blocking is determined by in-situ optimization
(seeexamples/complex/airfoil.py). A simulation-ready mesh needs additional blocks to expand domain further away from the airfoil.A parametric, Low-Re mesh of a real-life impeller(not included in examples)A complex example: parametric, Low-Re mesh of a cyclonePrerequisitesPackage (python) dependencies can be found inpyproject.tomlfile.
Other dependencies that must be installed:python3.8 and higherOpenFoam: .org or .com version is supported, foam-extend's blockMesh doesn't support multigrading but is otherwise also compatible.Technical InformationThere's no official documentation yet so here are some tips for easier navigation through source.The Process, RoughlyUser writes a script that defines operations/shapes/objects, their edges, projections, cell counts, whatever is needed.All the stuff is added to mesh.Mesh converts user entered data into vertices, blocks, edges and whatnot.The mesh can be written at that point; or,Modification of placed geometry, either by manually moving vertices or by utilizing some sort of optimization algorithm.Output of optimized/modified mesh.TODOUnchecked list items fromFeaturesUsabilityFrustum with any profile, not just arcJoining two blocks by moving vertices/creating new blocksTechnical stuff:Skew transformDebugging: connection between block and Shapes, naming101% test coverageDocumentation