Skip to content

Commit 2f162ea

Browse files
committed
Update changelog, readme, examples and bump version
1 parent 8b6b2b3 commit 2f162ea

File tree

6 files changed

+100
-62
lines changed

6 files changed

+100
-62
lines changed

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.10.0]
9+
10+
### Added
11+
12+
- Edge grading:
13+
- Added `Operation.chop_edge(corner_1, corner_2, ...)` that offers
14+
fine-control of grading of each edge; see `examples/advanced/edge_grading.py`
15+
for more info
16+
- Automatic grading:
17+
- A complete rewrite of automatic graders (`FixedCountGrader`, `SimpleGrader`)
18+
- Resurrected `InflationGrader` and this time it works (proved on the cyclone case)
19+
- Example for spline sketches/shapes
20+
21+
- Optimization:
22+
- Added manual clipping to bounds
23+
(scipy's methods often ignore them)
24+
25+
### Changed
26+
27+
- Optimization
28+
- Bugfix: optimization with links now takes more distant neighbours into account
29+
(a problem with certain cases)
30+
31+
### Removed
32+
33+
- Automatic grading: removed `SmoothGrader`
34+
(proves to be useless in real world and difficult to control);
35+
better to use edge grading (see `.chop_edge()`)
36+
837
## [1.9.6]
938

1039
### Added

README.md

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ Python classes for easier creation of OpenFOAM's blockMesh dictionaries.
44

55
# About
66

7-
_blockMesh_ is 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 `#calc` or even the dreadful `m4` quickly become unmanageable and cryptic.
7+
`blockMesh` is a very powerful mesher but creating even simple meshes requires a lot of manual work. Attempts to simplify or parametrize blockMeshDicts with `#calc` or `m4` often become cryptic and hard to maintain.
88

9-
classy_blocks' aim is to minimize the amount of meticulous work by providing a
10-
more intuitive workflow, off-the-shelf parts and some automatic helpers for building and optimization of block-structured hexahedral meshes.
11-
Still it is not an automatic mesher and therefore some kinds of geometry are more suited than others.
9+
`classy_blocks` aims to reduce this overhead by providing a more intuitive workflow, reusable building blocks and automatic helpers for constructing and optimizing block-structured hexahedral meshes. Nonetheless, it is not an automatic mesher, so some geometries are better suited than others.
1210

1311
## Tutorial
1412

@@ -54,7 +52,7 @@ Check out the [classy_blocks tutorial on damogranlabs.com](https://damogranlabs.
5452

5553
## Workflow
5654

57-
As 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.
55+
As 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.
5856

5957
## Building Elements
6058

@@ -67,7 +65,7 @@ _Unchecked items are not implemented yet but are on a TODO list_
6765
- [x] Revolve
6866
- [x] Wedge (a shortcut to Revolve for 2D axisymmetric cases)
6967
- [x] Connector (A Loft between two existing Operations)
70-
- [x] Sketches of common cross-sections
68+
- [x] Sketches (collections of 2D faces) of common cross-sections
7169
- [x] Quarter and Semi circle
7270
- [x] Circle
7371
- [x] Boxed circle
@@ -102,19 +100,19 @@ After blocks have been placed, it is possible to create new geometry based on pl
102100
- [x] Move Vertex/Edge/Face
103101
- [x] Delete a Block created by a Shape or Object
104102
- [x] Project Vertex/Edge/Face
105-
- [x] Optimize point position of a Sketch or mesh vertices
103+
- [x] Optimize point position of a sketch/shape (with arbitrarily constrained movement)
106104

107105
## Meshing Specification
108106

109107
- [x] Simple definition of all supported kinds of edges with a dedicated class (Arc/Origin/Angle/Spline/PolyLine/Project)
110108
- [x] Automatic sorting/reorienting of block vertices based on specified _front_ and _top_ points
111109
- [x] Automatic 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)
112-
- [ ] [Edge grading](https://www.openfoam.com/documentation/user-guide/4-mesh-generation-and-conversion/4.3-mesh-generation-with-the-blockmesh-utility#x13-450004.3.1.3) (separate specification for each edge)
110+
- [x] [Edge grading](https://www.openfoam.com/documentation/user-guide/4-mesh-generation-and-conversion/4.3-mesh-generation-with-the-blockmesh-utility#x13-450004.3.1.3) (separate specification for each edge)
113111
- [x] Automatic propagation of grading and cell count from a single block to all connected blocks as required by blockMesh
114112
- [x] Projections of vertices, edges and block faces to geometry (triangulated and [searchable surfaces](https://www.openfoam.com/documentation/guides/latest/doc/guide-meshing-snappyhexmesh-geometry.html#meshing-snappyhexmesh-searchable-objects))
115113
- [x] Face merging as described by [blockMesh user guide](https://www.openfoam.com/documentation/user-guide/4-mesh-generation-and-conversion/4.3-mesh-generation-with-the-blockmesh-utility#x13-470004.3.2). Breaks the pure-hexahedral-mesh rule but can often save the day for trickier geometries. Automatic duplication of points on merged block faces
116114
- [x] Auto grading for high-Re meshes
117-
- [ ] Auto grading for Low-Re meshes: boundary layer with specified cell-to-cell expansion, transition with 2:1 expansion, and specified 'bulk' cell size
115+
- [x] Auto grading for Low-Re meshes: boundary layer with specified cell-to-cell expansion, transition with 2:1 (or user-defined) expansion, and specified 'bulk' cell size
118116

119117
# Examples
120118

@@ -266,17 +264,6 @@ A collection of pre-assembled parametric Shapes, ready to be used for further co
266264
Three pipes, joined in a single point.
267265
![N-Joint](showcase/n_joint.png)
268266

269-
## Automatic Grading
270-
271-
After blocks have been positioned their cell count must be defined. This can be done manually with something like `operation.chop(axis, start_size=..., c2c_expansion=...)` or anything that `.chop()` method supports. Not all blocks need to be chopped as cell counts will be propagated throughout the mesh so it is advisable to only _chop_ the minimum required.
272-
273-
All that can also be avoided by using automatic graders, for instance, `SmoothGrader` will set counts so that desired cell size will be obtained but will also use multigrading to keep cell sizes between neighbouring blocks as uniform as possible.
274-
275-
![SmoothGrader, automatic grading of blocks](showcase/smooth_grader.png)
276-
277-
Also other, quicker and simpler graders are available.
278-
The ultimate grader that will also create inflation layers on walls for resolved boundary layer is in development.
279-
280267
## Projection To Geometry
281268

282269
[Any geometry that snappyHexMesh understands](https://www.openfoam.com/documentation/guides/latest/doc/guide-meshing-snappyhexmesh-geometry.html)
@@ -389,15 +376,36 @@ Airfoil core with blunt trailing edge (imported points from NACA generator) and
389376
(see `examples/complex/airfoil.py`). A simulation-ready mesh needs additional blocks to expand domain further away from the airfoil.
390377
![Airfoil](showcase/airfoil.png "Airfoil core mesh")
391378

392-
## Automatic Edge Grading
379+
## Chopping
380+
381+
In classy_blocks lingo, _chopping_ means setting block's cell count and optionally grading. For best control it can be specified manually with something like `operation.chop(axis, start_size=..., c2c_expansion=...)` (or any other supported combination of parameters) but it only needs to be done on a single block in a _row_ of connected blocks. All touching blocks will inherit user-specified chops automatically.
382+
383+
## Edge Grading
393384

394-
When setting cell counts and expansion ratios, it is possible to specify which value to keep constant. Mostly this will be used for keeping thickness of the first cell at the wall consistent to maintain desired `y+` throughout the mesh. This is done by simple specifying a `preserve="..."` keyword.
385+
When setting cell counts and expansion ratios, it is possible to specify which value to keep constant. When propagating chops through the mesh this will keep the required value constant. For instance, thickness of the first cell at the wall can be maintained to keep desired `y+` throughout the mesh. This is done by simply specifying a `preserve="..."` keyword.
395386

396387
Example: a block chopped in a classic way where cell sizes will increase when block size increases:
397388
![Classic block grading](showcase/classy_classic_grading.png "Classic block grading")
398389
The same case but with a specified `preserve="start_size"` keyword for the bottom and `preserve="end_size"` for the top edge:
399390
![Grading for consistent cell size](showcase/classy_edges_grading.png "Classy block grading")
400391

392+
It is also possible to locate a specific edge and modify its grading by using `operation.chop_edge(corner_1, corner_2, ...)`. For example, this cylinder with wall boundary layers has some edges manually redefined:
393+
394+
![Manual edge grading](showcase/edges_grading.png "Manual edge grading")
395+
396+
## Automatic Grading
397+
398+
classy_blocks offers automatic graders that will set cell counts and gradings throughout the whole mesh with no user intervention:
399+
400+
- `FixedCountGrader` will simply set the same cell count on all blocks.
401+
- `SimpleGrader` will try to maintain user-specified cell size.
402+
- `InflationGrader` will require the user to set wall patches first, then it will set cell sizes on the wall to maintain required first cell thickness,
403+
make a boundary (inflation) layer that will maintain specified cell-to-cell expansion. Between the last boundary-layer cell and the bulk, a _buffer_ layer will be created with a larger (user-specified) cell-to-cell expansion to save on cell count.
404+
405+
All automatic graders will only grade what the user has not chopped yet - so it's easy to override grader's doings by manually chopping shapes first.
406+
407+
> Check out `examples/complex/cyclone` to see that almost no manual chopping is required to grade the whole mesh!
408+
401409
## Debugging
402410

403411
By default, a `debug.vtk` file is created where each block represents a hexahedral cell.

examples/advanced/edge_grading.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,48 @@
1-
# NOT FINISHED!
2-
# TODO: add operation.grade_edge() and show its usage in this example
1+
"""A simple cylinder but with custom grading of selected edges"""
2+
33
import os
44

55
import classy_blocks as cb
66

77
mesh = cb.Mesh()
88

9-
start = cb.Box([0, 0, 0], [1, 1, 0.1])
9+
axis_point_1 = [0, 0, 0]
10+
axis_point_2 = [1, 0, 0]
11+
radius_point_1 = [0, 1, 0]
12+
13+
cylinder = cb.Cylinder(axis_point_1, axis_point_2, radius_point_1)
14+
15+
cylinder.set_start_patch("inlet")
16+
cylinder.set_end_patch("outlet")
17+
cylinder.set_outer_patch("walls")
18+
19+
# Chop and grade
20+
bl_thickness = 1e-3
21+
core_size = 0.1
1022

11-
start.chop(0, start_size=0.1)
12-
start.chop(1, length_ratio=0.5, start_size=0.01, c2c_expansion=1.2, preserve="start_size")
13-
start.chop(1, length_ratio=0.5, end_size=0.01, c2c_expansion=1 / 1.2, preserve="end_size")
14-
start.chop(2, count=1)
15-
mesh.add(start)
23+
# Edge chopping can only be done on a completely specified mesh;
24+
cylinder.chop_axial(count=30)
25+
cylinder.chop_radial(start_size=core_size, end_size=bl_thickness)
26+
cylinder.chop_tangential(start_size=core_size)
1627

17-
expand_start = start.get_face("right")
18-
expand = cb.Loft(expand_start, expand_start.copy().translate([1, 0, 0]).scale(2))
19-
expand.chop(2, start_size=0.1)
20-
mesh.add(expand)
28+
# After all edges have been specified (chopped),
29+
# specific ones can be changed manually.
30+
# Keep in mind that count is already fixed and cannot be changed.
2131

22-
contract_start = expand.get_face("top")
23-
contract = cb.Loft(contract_start, contract_start.copy().translate([1, 0, 0]).scale(0.25))
24-
contract.chop(2, start_size=0.1)
25-
mesh.add(contract)
32+
# Case 1: remove grading
33+
cylinder.shell[0].chop_edge(0, 1, c2c_expansion=1)
34+
# Case 2: make a thicker first cell
35+
cylinder.shell[1].chop_edge(0, 1, end_size=5 * bl_thickness)
36+
# Case 3: weird random multigrading
37+
cylinder.shell[2].chop_edge(0, 1, length_ratio=0.5, count=2)
38+
cylinder.shell[2].chop_edge(0, 1, c2c_expansion=1 / 1.5)
39+
# Case 4: chop one block differently so that neighbour block will be edge-graded
40+
cylinder.shell[1].chop(2, count=30, start_size=0.01)
2641

27-
end = cb.Extrude(contract.get_face("top"), 1)
28-
end.chop(2, start_size=0.1)
29-
mesh.add(end)
3042

31-
mesh.set_default_patch("walls", "wall")
43+
mesh.add(cylinder)
44+
cylinder.set_start_patch("walls")
45+
cylinder.set_end_patch("walls")
46+
mesh.modify_patch("walls", "wall")
3247

3348
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

examples/shape/cylinder.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,14 @@
2222
bl_thickness = 1e-3
2323
core_size = 0.1
2424

25-
# cylinder.chop_axial(count=30)
26-
# cylinder.chop_radial(start_size=core_size, end_size=bl_thickness)
27-
# cylinder.chop_tangential(start_size=core_size)
28-
29-
# chop a single edge of a single operation
30-
# case 1: remove grading
31-
# cylinder.shell[0].chop_edge(0, 1, c2c_expansion=1)
32-
# case 2: make a thicker first cell
33-
# cylinder.shell[1].chop_edge(0, 1, end_size=5 * bl_thickness)
34-
# case 3: weird random multigrading
35-
# cylinder.shell[2].chop_edge(0, 1, length_ratio=0.5, count=2)
36-
# cylinder.shell[2].chop_edge(0, 1, c2c_expansion=1 / 1.5)
37-
# case 4: chop one block differently so that neighbour block will be edge-graded
38-
# cylinder.shell[1].chop(2, count=30, start_size=0.01)
25+
cylinder.chop_axial(count=30)
26+
cylinder.chop_radial(start_size=core_size, end_size=bl_thickness)
27+
cylinder.chop_tangential(start_size=core_size)
3928

40-
41-
mesh.add(cylinder)
4229
cylinder.set_start_patch("walls")
4330
cylinder.set_end_patch("walls")
44-
mesh.modify_patch("walls", "wall")
4531

46-
grader = cb.InflationGrader(mesh, bl_thickness, core_size)
47-
grader.grade()
32+
mesh.add(cylinder)
33+
mesh.modify_patch("walls", "wall")
4834

4935
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "classy_blocks"
3-
version = "1.9.6"
3+
version = "1.10.0"
44
description = "Python classes for easier creation of openFoam's blockMesh dictionaries."
55
readme = "README.md"
66
license = "MIT"

showcase/smooth_grader.png

-243 KB
Binary file not shown.

0 commit comments

Comments
 (0)