Skip to content

Commit 7a4b1bd

Browse files
committed
Merge branch 'release'
2 parents c38c817 + 918fe8c commit 7a4b1bd

File tree

153 files changed

+4234
-1588
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

153 files changed

+4234
-1588
lines changed

.github/workflows/build_ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ jobs:
66
pytests:
77
strategy:
88
matrix:
9-
python-version: ["3.8", "3.9", "3.10", "3.11"]
9+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
1010
fail-fast: false
1111
runs-on: ubuntu-latest
1212
steps:

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"editor.defaultFormatter": "ms-python.black-formatter",
55
"editor.wordBasedSuggestions": "off",
66
"editor.codeActionsOnSave": {
7-
"source.organizeImports": "explicit"
7+
"source.organizeImports.isort": "explicit"
88
},
99
},
1010
"python.analysis.typeCheckingMode": "basic",

CHANGELOG.md

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

7-
# [1.6.4]
7+
# [1.7.0]
8+
### Added
9+
- Automatic grading:
10+
- `FixedCountGrader`: simple and quick, grades all blocks in all directions with the same number. Useful while developing meshes - settings blocking etc.
11+
- `SimpleGrader`: quick and good for cases where blocks do not differ much in size. Sets simple-graded counts on blocks based on wanted cell size.
12+
- `SmoothGrader`: Tries to stretch and squeeze cells within blocks by using two graded chops in each direction. The idea is to try to keep difference in cell size between neighbouring blocks as little as possible. Blocks that cannot maintain required cell size are simply/uniformly chopped.
13+
- Possibility to define rings by their inner radius
14+
- Spline round shapes
15+
- Cylinders:
16+
- Add symmetry patch to SemiCylinder
17+
- New examples:
18+
- Quarter cylinder
19+
- One core cylinder
20+
- `ShapeOptimizer` can optimize shapes _before_ they are added to mesh
21+
22+
### Changed
23+
- Renamed `classy_blocks.typing` module to `classy_blocks.cbtyping` due to name clash
24+
- Bugfixes
25+
26+
## [1.6.4]
827
### Added
928
- MappedSketch.merge() method
1029

1130
### Changed
1231
- Improved blocking in cyclone example
1332

14-
# [1.6.3]
33+
## [1.6.3]
1534
### Changed
1635
- Bugfix: sorting of cells by sensitivity
1736
- Bugfix: sensitivity calculation moved clamps around
@@ -21,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2140
### Removed
2241
- Quality caching (produced invalid results and did not speed up optimization)
2342

24-
# [1.6.2]
43+
## [1.6.2]
2544
### Added
2645
- QuarterSplineRound and QuarterSplineRoundRing; cylinders and rings with an arbitrary, parametrized spline cross-section
2746
- Lofts and Shapes, created with spline side-edges (when multiple sketches for mid-sections are provided)
@@ -30,15 +49,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3049
### Changed
3150
- Bugfixes
3251

33-
# [1.6.1]
52+
## [1.6.1]
3453
### Added
3554
- Assemblies and *Joints
3655
- Examples thereof
3756

3857
### Changed
3958
- Some bugfixes
4059

41-
# [1.6.0]
60+
## [1.6.0]
4261
### Added
4362
- Array element; handling multiple points at once (makes transforms faster)
4463
- Complete overhaul of Optimization:
@@ -55,14 +74,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5574
### Removed
5675
- QuadMap is no longer needed (handled by Grid classes)
5776

58-
# [1.5.3]
77+
## [1.5.3]
5978
### Added
6079
- RoundSolidShape.remove_inner_edges() can now remove edges from a specific face (start, end or both)
6180

6281
### Changed
6382
- Bugfix: invalid cells in round shapes (due to wrong spline point calculation)
6483

65-
# [1.5.2]
84+
## [1.5.2]
6685
### Added
6786
- Spline edges on QuarterDisk, HalfDisk and Disk (FourCoreDisk) to improve mesh quality
6887
- Face.remove_edges() to reset all edges to simple lines
@@ -71,7 +90,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7190
### Changed
7291
- Updated affected tutorials (diffusers, cyclone)
7392

74-
# [1.5.1]
93+
## [1.5.1]
7594
### Added
7695
- Optimization:
7796
- Choice of solver (different problems require - work best - with different solvers)
@@ -86,7 +105,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
86105
### Changed
87106
- Improved optimization speed
88107

89-
# [1.5.0]
108+
## [1.5.0]
90109
### Added
91110
- Curves:
92111
- get_tangent()
@@ -114,15 +133,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
114133
- Calling .transform() with a Mirror transformation will warn about creating an inverted block
115134

116135

117-
# [1.4.1]
136+
## [1.4.1]
118137
### Changed
119138
- Improved optimization output
120139

121140
### Removed
122141
- Relaxation within optimization
123142
- Numerical integration of analytic curve lengths; use discretization instead
124143

125-
# [1.4.0]
144+
## [1.4.0]
126145
### Added
127146
- Channel example
128147
- Cyclone example
@@ -157,7 +176,7 @@ that parameter is of a similar magnitudes than points' coordinates.
157176
### Removed
158177
- Junction.delta() is now handled by optimization automatically
159178

160-
# [1.3.3]
179+
## [1.3.3]
161180
### Added
162181
- Airfoil example
163182
- Translation and Rotational Link: move together with vertices being optimized (see the airfoil example)
@@ -172,19 +191,19 @@ that parameter is of a similar magnitudes than points' coordinates.
172191
### Removed
173192
- Curve.get_closest_param() now finds initial_param automatically
174193

175-
# [1.3.2] Curves
194+
## [1.3.2] Curves
176195
### Added
177196
- *Curve objects for dealing with edge specification and optimization
178197

179-
# [1.3.1] Optimization/Backport
198+
## [1.3.1] Optimization/Backport
180199
### Added
181200
- mesh.clear() removes lists of all items that were populated during mesh.assemble()
182201
- mesh.backport() updates user supplied operations' points with results of optimization/modification
183202

184203
### Changed
185204
- Optimizer: under-relaxation for the first optimization iterations
186205

187-
# [1.3.0] Blocking Optimization
206+
## [1.3.0] Blocking Optimization
188207
### Added
189208
- **Blocking Optimization**
190209
- Finders for easier fetching vertices, generated by mesh.assemble()
@@ -208,7 +227,7 @@ that parameter is of a similar magnitudes than points' coordinates.
208227
- Calling .project_side() on an Operation will add the new geometry to edges instead of replacing them (but will replace existing label for the side)
209228

210229

211-
# [1.2.0] Shell Shape
230+
## [1.2.0] Shell Shape
212231
### Added
213232
- A Shell Shape, created from arbitrary set of faces
214233
### Changed

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,15 @@ _Unchecked items are not implemented yet but are on a TODO list_
7777
- [x] Ring (annulus)
7878
- [x] Hemisphere
7979
- [x] Stacks (collections of similar Shapes stacked on top of each other)
80-
- [ ] Predefined parametric Objects
80+
- [x] Predefined parametric Objects
8181
- [x] T-joint (round pipes)
8282
- [x] X-joint
8383
- [x] N-joint (multiple pipes)
84-
- [ ] Collector (a barrel with multiple radial outlets)
8584
- [ ] Other building tools
8685
- [x] Use existing Operation's Face to generate a new Operation
8786
- [x] Chain Shape's start/end surface to generate a new Shape
8887
- [x] Expand Shape's outer surface to generate a new Shape (Cylinder/Annulus > Annulus)
8988
- [x] Contract Shape's inner surface into a new Shape (Annulus > Cylinder/Annulus)
90-
- [ ] Join two Operations by extending their Edges
9189
- [x] Offset Operation's faces to form new operations
9290

9391
## Modifiers
@@ -106,6 +104,7 @@ After blocks have been placed, it is possible to create new geometry based on pl
106104
- [x] Automatic propagation of grading and cell count from a single block to all connected blocks as required by blockMesh
107105
- [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))
108106
- [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
107+
- [x] Auto grading for high-Re meshes
109108
- [ ] Auto grading for Low-Re meshes: boundary layer with specified cell-to-cell expansion, transition with 2:1 expansion, and specified 'bulk' cell size
110109

111110
# Examples
@@ -254,6 +253,16 @@ A collection of pre-assembled parametric Shapes, ready to be used for further co
254253
Three pipes, joined in a single point.
255254
![N-Joint](showcase/n_joint.png)
256255

256+
## Automatic Grading
257+
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.
258+
259+
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.
260+
261+
![SmoothGrader, automatic grading of blocks](showcase/smooth_grader.png)
262+
263+
Also other, quicker and simpler graders are available.
264+
The ultimate grader that will also create inflation layers on walls for resolved boundary layer is in development.
265+
257266
## Projection To Geometry
258267

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

379+
## Automatic Edge Grading
380+
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.
381+
382+
Example: a block chopped in a classic way where cell sizes will increase when block size increases:
383+
![Classic block grading](showcase/classy_classic_grading.png "Classic block grading")
384+
The same case but with a specified `preserve="start_size"` keyword for the bottom and `preserve="end_size"` for the top edge:
385+
![Grading for consistent cell size](showcase/classy_edges_grading.png "Classy block grading")
370386

371387
## Debugging
372388

classy_blocks.code-workspace

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
"Pylance",
1313
"scipy"
1414
],
15-
"editor.autoClosingBrackets": "never"
15+
"editor.autoClosingBrackets": "never",
16+
"isort.importStrategy": "fromEnvironment",
17+
"editor.defaultFormatter": null,
18+
"ruff.organizeImports": false
1619
},
1720
"extensions": {
1821
"recommendations": [

examples/advanced/edge_grading.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# NOT FINISHED!
2+
# TODO: add operation.grade_edge() and show its usage in this example
3+
import os
4+
5+
import classy_blocks as cb
6+
7+
mesh = cb.Mesh()
8+
9+
start = cb.Box([0, 0, 0], [1, 1, 0.1])
10+
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)
16+
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)
21+
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)
26+
27+
end = cb.Extrude(contract.get_face("top"), 1)
28+
end.chop(2, start_size=0.1)
29+
mesh.add(end)
30+
31+
mesh.set_default_patch("walls", "wall")
32+
33+
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

examples/advanced/smooth_grader.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# A terrible blocking of a rectangle for displaying SmoothGrader capabilities
2+
3+
import os
4+
5+
import numpy as np
6+
7+
import classy_blocks as cb
8+
9+
mesh = cb.Mesh()
10+
11+
base = cb.Grid([0, 0, 0], [3, 2, 0], 3, 2)
12+
13+
shape = cb.ExtrudedShape(base, 1)
14+
15+
# turn one block around to test grader's skillz
16+
shape.grid[1][0].rotate(np.pi, [0, 0, 1])
17+
18+
mesh.add(shape)
19+
20+
# move some points to get a mesh with uneven blocks
21+
mesh.assemble()
22+
finder = cb.GeometricFinder(mesh)
23+
24+
move_points = [[0, 1, 1], [2, 1, 1], [3, 1, 1]]
25+
26+
for point in move_points:
27+
vertex = list(finder.find_in_sphere(point))[0]
28+
vertex.translate([0, 0.8, 0])
29+
30+
mesh.set_default_patch("walls", "wall")
31+
mesh.block_list.update()
32+
grader = cb.SmoothGrader(mesh, 0.05)
33+
grader.grade()
34+
35+
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

examples/chaining/labyrinth.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
face = cb.Face([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]])
1616
extrude = cb.Extrude(face, 1)
17-
extrudes.append(extrude)
17+
mesh.add(extrude)
1818

1919
for side in ("top", "right", "top", "top", "left", "top"):
2020
face = extrude.get_face(side)
@@ -29,14 +29,11 @@
2929
# the operations to keep them consistent - 'top' faces
3030
# facing upwards.
3131
orienter.reorient(extrude)
32-
33-
extrudes.append(extrude)
34-
35-
for extrude in extrudes:
36-
for i in range(3):
37-
extrude.chop(i, count=10)
38-
3932
mesh.add(extrude)
4033

4134
mesh.set_default_patch("walls", "wall")
35+
36+
grader = cb.FixedCountGrader(mesh, 5)
37+
grader.grade()
38+
4239
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

examples/chaining/tank.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,25 @@
66
diameter = 0.5
77
length = 0.5 # including end caps
88

9-
# refer to other examples for a proper-ish grading setup
10-
h = 0.05
11-
129
mesh = cb.Mesh()
1310

1411
cylinder = cb.Cylinder([0, 0, 0], [length, 0, 0], [0, diameter / 2, 0])
1512

1613
wall_name = "tank_wall"
1714

18-
cylinder.chop_axial(start_size=h)
19-
cylinder.chop_radial(start_size=h)
20-
cylinder.chop_tangential(start_size=h)
2115
cylinder.set_outer_patch(wall_name)
2216

2317
start_cap = cb.Hemisphere.chain(cylinder, start_face=True)
24-
start_cap.chop_axial(start_size=h)
2518
start_cap.set_outer_patch(wall_name)
2619

2720
end_cap = cb.Hemisphere.chain(cylinder, start_face=False)
28-
end_cap.chop_axial(start_size=h)
2921
end_cap.set_outer_patch(wall_name)
3022

3123
mesh.add(cylinder)
3224
mesh.add(start_cap)
3325
mesh.add(end_cap)
3426

27+
grader = cb.SimpleGrader(mesh, 0.05)
28+
grader.grade()
29+
3530
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

examples/complex/airfoil/airfoil.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ def get_loft(indexes):
135135
# Keep in mind that not all blocks need exact specification as
136136
# chopping will propagate automatically through blocking
137137
lofts[0].chop(2, count=1) # 1 cell in the 3rd dimension
138-
lofts[1].chop(1, start_size=BL_THICKNESS, c2c_expansion=C2C_EXPANSION, take="max")
138+
# keep consistent first cell thickness by using edge grading
139+
lofts[1].chop(1, start_size=BL_THICKNESS, c2c_expansion=C2C_EXPANSION, take="max", preserve="start_size")
139140
lofts[8].chop(1, start_size=CELL_SIZE, take="max")
140141

141142
for i in (0, 1, 2, 3, 4, 5, 6):
@@ -195,7 +196,9 @@ def optimize_along_line(point_index, line_index_1, line_index_2):
195196
optimize_along_line(5, 3, 6)
196197

197198
if OPTIMIZE:
198-
optimizer.optimize(tolerance=1e-7, method="SLSQP")
199+
optimizer.optimize(tolerance=1e-3, method="SLSQP")
200+
mesh.backport()
201+
mesh.clear()
199202

200203
### Write the mesh
201204
mesh.modify_patch("topAndBottom", "empty")

0 commit comments

Comments
 (0)