Skip to content

Commit ea9a01f

Browse files
committed
Add an autochop object for low-re cases
1 parent 8bd0746 commit ea9a01f

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed

src/classy_blocks/grading/autochop/__init__.py

Whitespace-only changes.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import dataclasses
2+
import warnings
3+
from typing import List, Tuple
4+
5+
from classy_blocks.grading import relations as gr
6+
from classy_blocks.grading.chop import Chop
7+
from classy_blocks.types import ChopTakeType
8+
9+
10+
class AutoChopError(Exception):
11+
"""Raised when there's not enough space to finish a part of autochop"""
12+
13+
14+
def sum_length(start_size: float, count: int, c2c_expansion: float) -> float:
15+
"""Returns absolute length of the chop"""
16+
length = 0.0
17+
size = start_size
18+
19+
for _ in range(count):
20+
length += size
21+
size *= c2c_expansion
22+
23+
return length
24+
25+
26+
@dataclasses.dataclass
27+
class LowReChopParams:
28+
"""Parameters for mesh grading for Low-Re cases.
29+
To save on cell count, only a required thickness (boundary layer)
30+
will be covered with thin cells (c2c_expansion in size ratio between them).
31+
Then a bigger expansion ratio will be applied between the last cell of boundary layer
32+
and the first cell of the bulk flow.
33+
34+
Example:
35+
________________
36+
|
37+
| > bulk size (cell_size=bulk, no expansion)
38+
|________________
39+
|
40+
|________________ > buffer layer (c2c = 2)
41+
|________________
42+
|================ > boundary layer (cell_size=y+, c2c=1.2)
43+
/ / / / / / / / / wall
44+
45+
Args:
46+
first_cell_size (float): thickness of the first cell near the wall
47+
c2c_expansion (float): expansion ratio between cells in boundary layer
48+
bl_thickness_factor (int): thickness of the boundary layer in y+ units (relative to first_cell_size)
49+
buffer_expansion (float): expansion between cells in buffer layer
50+
bulk_cell_size (float): size of cells inside the domain
51+
52+
Autochop will take all relevant blocks and choose one to start with - set cell counts
53+
and other parameters that must stay fixed for all further blocks.
54+
It will choose the longest/shortest ('max/min') block edge or something in between ('avg').
55+
The finest grid will be obtained with 'max', the coarsest with 'min'.
56+
"""
57+
58+
first_cell_size: float
59+
bulk_cell_size: float
60+
61+
c2c_expansion: float = 1.2
62+
bl_thickness_factor: int = 30
63+
buffer_expansion: float = 2
64+
65+
take: ChopTakeType = "avg"
66+
67+
@property
68+
def boundary_layer_thickness(self) -> float:
69+
return self.first_cell_size * self.bl_thickness_factor
70+
71+
def _get_boundary_chop(self, length: float) -> Tuple[Chop, float]:
72+
"""Creates a Chop for the boundary layer; returns size of the last cell"""
73+
near_wall = Chop(
74+
length_ratio=length / self.boundary_layer_thickness,
75+
start_size=self.first_cell_size,
76+
c2c_expansion=self.c2c_expansion,
77+
)
78+
data = near_wall.calculate(self.first_cell_size * self.boundary_layer_thickness)
79+
return (near_wall, data.end_size)
80+
81+
def _get_buffer_chop(self, start_size: float) -> Tuple[Chop, float]:
82+
"""Creates a chop between the last cell of boundary layer
83+
and the first cell of bulk flow; returns length of the chop"""
84+
buffer_count = gr.get_count__total_expansion__c2c_expansion(
85+
1, self.bulk_cell_size / start_size, self.buffer_expansion
86+
)
87+
buffer_size = sum_length(start_size, buffer_count, self.buffer_expansion)
88+
buffer = Chop(start_size=start_size, c2c_expansion=self.buffer_expansion, count=buffer_count)
89+
90+
return buffer, buffer_size
91+
92+
def _get_bulk_chop(self, remaining_size: float) -> Chop:
93+
count = max(1, int(remaining_size / self.bulk_cell_size))
94+
return Chop(count=count)
95+
96+
def get_chops_from_length(self, length: float) -> List[Chop]:
97+
chops: List[Chop] = []
98+
99+
if length < self.boundary_layer_thickness:
100+
warnings.warn("Boundary layer is thicker than block size!", stacklevel=1)
101+
102+
# near-wall sizes:
103+
near_wall, last_bl_size = self._get_boundary_chop(length)
104+
remaining_length = length - self.boundary_layer_thickness
105+
chops.append(near_wall)
106+
107+
if remaining_length <= 0:
108+
warnings.warn("Stopping chops at boundary layer (not enough space)!", stacklevel=1)
109+
return chops
110+
111+
# buffer
112+
buffer, buffer_size = self._get_buffer_chop(last_bl_size)
113+
chops.append(buffer)
114+
if buffer_size >= remaining_length:
115+
warnings.warn("Stopping chops at buffer layer (not enough space)!", stacklevel=1)
116+
return chops
117+
118+
# bulk
119+
remaining_length = remaining_length - buffer_size
120+
bulk = self._get_bulk_chop(remaining_length)
121+
chops.append(bulk)
122+
123+
return chops

tests/test_grading/__init__.py

Whitespace-only changes.

tests/test_grading/test_auto.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import unittest
2+
3+
from parameterized import parameterized
4+
5+
from classy_blocks.grading.autochop.low_re import LowReChopParams
6+
7+
8+
class LowReChopTests(unittest.TestCase):
9+
def setUp(self):
10+
self.params = LowReChopParams(1e-3, 0.01, 1.2, 30, 2, "avg")
11+
12+
@parameterized.expand(
13+
(
14+
(2, 3),
15+
(1, 3),
16+
(0.04, 2),
17+
(0.01, 1),
18+
(1e-3, 1),
19+
(1e-4, 1),
20+
)
21+
)
22+
def test_get_from_length(self, length, chop_count):
23+
chops = self.params.get_chops_from_length(length)
24+
25+
self.assertEqual(len(chops), chop_count)
File renamed without changes.

0 commit comments

Comments
 (0)