Python 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 lof of bugs. However, you're welcome to suggest features, improvements, and point out bugs. Until it becomes a_pip package_ you can use it as a submodule or just download the code and import stuff to your project.
tl;dr: clone the classy_examples repository, install
jinja2
and runrun.py
.
This is a collection of Python classes for creation of blockMeshDict files for OpenFOAM's blockMesh tool. Its purpose is to avoid manual entering of numbers into blockMeshDict and also avoid the dreadful m4
or #calc
.
Since it is easier to crunch numbers and vectors and everything else with numpy
it is a better idea to do that there and then just throw everything into blockMeshDicts. This tool is a link between these two steps.
- If your brain hurts during meticulous tasks such as manual copying of numbers from excel or even paper
- If you don't want to waste energy on low-level stuff such as numbering vertices
- If you have a rather simplish parametric model and would like to make a bunch of simulations with changing geometry (optimizations etc.)
- Write your parametric model's geometry with a short Python script and translate it directly to
blockMeshDict
- Predefined shapes like
Cylinder
or operations likeExtrude
andRevolve
* - Simple specification of edges: a single point for circular or a list of points for a spline edge
- Automatic calculation of number of cells with
block.count_to_size(cell_size)
- Automatic cell grading calculation by setting required cell size
block.grade_to_size(cell_size)
- Automatic propagation of grading and cell count from block to block as required by blockMesh
*There are 3 different abstraction levels:
- Shapes take points and vectors as parameters (depending on that shape) and returns an object that is passed to Mesh. Everything (including blocks) is created implicitly and you don't have to deal with any of the low-level stuff.
- An Operation combines a
Face
(4 points, 4 edges) and transforms it into a block using a rule based on the operation itself.Revolve
, for instance, rotates the face around a specified axis and also creates circular edges between the two faces. - The lowest-level approach is to calculate vertex and edge points manually and create blocks from those.
- Cone Frustum (truncated cone)
- Cylinder
- Ring (annulus)
- Elbow (bent pipe)
See examples/shape for example use of each 'shape'. See examples/complex for a more real-life example usage of shapes.
A Face
is a collection of 4 vertices and 4 edges. It is a 2D object analogous to a sketch in most CAD modelers - once defined, it can be used to create 3D shapes with various operations.
A single block is created from a Face
translated by an extrude vector.
A single face is revolved around a given axis so that a circular object with a constant cross-section is created.
A special case of revolve for 2D axisymmetric meshes. A list of (x,y)
points is revolved symetrically around x-axis as required by a wedge
boundary condition in OpenFOAM.
A single block, created between two Face
s. Edges between the same vertices on the two faces can also be specified.
See examples/operations for an example of each operation.
Basically any kind of block can be created with Loft so this is usually as low-level as you'll need to go.
Manual block creation using vertices, edges, etc.
Workflow is similar to bare-bones blockMeshDict but you don't have to track vertex/edge/block indexes. You do:
- Calculate block vertices
- Calculate edge points, if any
- Create a Mesh object
- Create a Block object with vertices and edges for each block
- Add blocks to mesh
- Set block cell count and sizes
- Assign patches
- Pray you did everything right
- Cry because you didn't
See examples/primitive for a demonstration.
- numpy
- scipy
- jinja2
A single channel of an impeller, without volute and with infinitely thin blades:
A full volute and inlet (impeller mesh is created separately):
A real-life square volute with a blunt cutwater:
These contain data to be written to blockMeshDict and also methods for point manipulation and output formatting.
Vertex
: an object containing (x, y, z) point and its index in blockMesh. Also formats output so OpenFOAM can read it.Edge
: a collection of twoVertex
indexes and a number ofPoint
s in betweenFace
: a collection of exactly 4Vertex
es and optionally 4Edge
s. If only some of the 4 edges are curved aNone
can be passed instead of a list of edge points.Block
: containsVertex
andEdge
objects and other block data: patches, number of cells, grading, cell zone, description.Mesh
: holds lists of all blockMeshDict data:Vertex
,Edge
,Block
.
A blockMesh is created from a number of blocks, therefore a Block
object is in the center of attention. A Block
can be created in different ways:
- Directly from 8 vertices. The order of vertices follows the sketch on openfoam.com user manual. Edges are added to block by specifying vertex indexes and a list of points in between.
- From 2
Face
objects. Edges between the same vertex on both faces can be provided as well. - From any of the Operations. Creation of a Block with an Operation depends on type of specific operation.
- By using a predefined Shape. Creation procedure again differs from shape to shape. Usually multiple blocks are returned.
Once blocks are created, additional data may be added (number of cells, grading, patches). Finally, all blocks must be added to Mesh. That will prepare data for blockMesh and create a blockMeshDict from a template.
Mesh
only contains a list of blocks. Each block self-contains its data. Since blocks share vertices and edges and blockMesh needs separate lists of the latter, Mesh.prepare_data()
will traverse its list of blocks and store vertices and edges to separate lists. During that it will check for duplicates and drop them. It will also collect patches from all blocks and store them into a template-readable list.
Check out util/geometry.py
for bonus functions. More about that is written in my blog post, [https://damogranlabs.com/2019/11/points-and-vectors/].
There are also a couple of functions used in the example.
Of course you are free to use your own :)
- More examples from real life
- More Shapes
- ElbowWall
- Predefined ready-to-use parametric objects
- T-joint
- X-joint
- Elbow from segments
- Elbow wall from segments
- Optional face merging
- Tools
- refineWallLayer script
- Technicalities:
- More Tests, including examples
- logging for info/debug
- output geometry to .obj for debugging
- shorter imports (something to do with
__init__.py
files)
- A proper documentation