Skip to content

Commit 2c0edc1

Browse files
committed
Do much polishing on HighReGrader. Also, bugfixes
1 parent 5c21dbb commit 2c0edc1

File tree

12 files changed

+268
-129
lines changed

12 files changed

+268
-129
lines changed

.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.ruff": "explicit"
7+
"source.organizeImports.isort": "explicit"
88
},
99
},
1010
"python.analysis.typeCheckingMode": "basic",

examples/advanced/autograding_highre.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import os
22

33
import classy_blocks as cb
4-
from classy_blocks.grading.autograding.grader import HighReGrader, SimpleGrader
5-
from classy_blocks.grading.autograding.params import HighReChopParams, SimpleChopParams
4+
from classy_blocks.grading.autograding.grader import HighReGrader
5+
from classy_blocks.grading.autograding.params import HighReChopParams
66

77
mesh = cb.Mesh()
88

@@ -25,12 +25,12 @@
2525
mesh.set_default_patch("walls", "wall")
2626

2727

28-
params = HighReChopParams(0.075)
28+
params = HighReChopParams(0.05)
2929
grader = HighReGrader(mesh, params)
30-
grader.grade(take="max")
30+
grader.grade()
3131

32-
params = SimpleChopParams(0.075)
33-
grader = SimpleGrader(mesh, params)
32+
# params = SimpleChopParams(0.05)
33+
# grader = SimpleGrader(mesh, params)
3434
# grader.grade(take="max")
3535

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

examples/shape/cylinder.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import classy_blocks as cb
44
from classy_blocks.construct.flat.sketches.disk import DiskBase
5+
from classy_blocks.grading.autograding.grader import HighReGrader
6+
from classy_blocks.grading.autograding.params import HighReChopParams
57

6-
DiskBase.core_ratio = 0.7 # Default is 0.8
8+
DiskBase.core_ratio = 0.4 # Default is 0.8
79

810
mesh = cb.Mesh()
911

@@ -24,10 +26,18 @@
2426
bl_thickness = 0.05
2527
core_size = 0.2
2628

27-
cylinder.chop_axial(count=30)
28-
cylinder.chop_radial(start_size=core_size, end_size=bl_thickness)
29-
cylinder.chop_tangential(start_size=core_size)
29+
# cylinder.chop_axial(count=30)
30+
# cylinder.chop_radial(start_size=core_size, end_size=bl_thickness)
31+
# cylinder.chop_tangential(start_size=core_size)
3032

3133
mesh.add(cylinder)
3234

35+
mesh.assemble()
36+
mesh.block_list.update()
37+
38+
params = HighReChopParams(0.1)
39+
grader = HighReGrader(mesh, params)
40+
grader.grade()
41+
42+
3343
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

examples/shape/quarter_cylinder.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import os
2+
3+
import classy_blocks as cb
4+
from classy_blocks.construct.flat.sketches.disk import QuarterDisk
5+
from classy_blocks.grading.autograding.grader import HighReGrader
6+
from classy_blocks.grading.autograding.params import HighReChopParams
7+
from classy_blocks.util import functions as f
8+
9+
mesh = cb.Mesh()
10+
11+
axis_point_1 = f.vector(0.0, 0.0, 0.0)
12+
axis_point_2 = f.vector(5.0, 5.0, 0.0)
13+
radius_point_1 = f.vector(0.0, 0.0, 2.0)
14+
15+
# make a disk with small core block - yields particularly bad cell sizes with normal chops
16+
QuarterDisk.core_ratio = 0.4
17+
18+
quarter_disk = QuarterDisk(axis_point_1, radius_point_1, axis_point_1 - axis_point_2)
19+
quarter_cylinder = cb.ExtrudedShape(quarter_disk, f.norm(axis_point_2 - axis_point_1))
20+
21+
mesh.add(quarter_cylinder)
22+
23+
mesh.assemble()
24+
# TODO: automate or something
25+
mesh.block_list.update()
26+
27+
params = HighReChopParams(0.05)
28+
grader = HighReGrader(mesh, params)
29+
grader.grade()
30+
31+
32+
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")
Lines changed: 37 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,75 @@
1-
from typing import Optional, Set, get_args
1+
import abc
2+
from typing import get_args
23

34
from classy_blocks.grading.autograding.params import ChopParams, FixedCountParams, HighReChopParams, SimpleChopParams
4-
from classy_blocks.grading.autograding.probe import Probe
5-
from classy_blocks.grading.chop import Chop
6-
from classy_blocks.items.wires.wire import Wire
5+
from classy_blocks.grading.autograding.probe import Probe, Row
76
from classy_blocks.mesh import Mesh
87
from classy_blocks.types import ChopTakeType, DirectionType
98

109

11-
class GraderBase:
10+
class GraderBase(abc.ABC):
11+
stages: int
12+
1213
def __init__(self, mesh: Mesh, params: ChopParams):
1314
self.mesh = mesh
1415
self.params = params
1516

1617
self.mesh.assemble()
1718
self.probe = Probe(self.mesh)
1819

19-
def _get_end_size(self, wires: Set[Wire]) -> Optional[float]:
20-
"""Returns average size of wires' last cell"""
21-
if len(wires) == 0:
22-
return None
20+
def get_count(self, row: Row, take: ChopTakeType) -> int:
21+
count = row.get_count()
2322

24-
return sum(wire.grading.end_size for wire in wires) / len(wires)
23+
if count is None:
24+
# take length from a row, as requested by 'take'
25+
length = row.get_length(take)
26+
# and set count from it
27+
count = self.params.get_count(length)
2528

26-
def _get_start_size(self, wires: Set[Wire]) -> Optional[float]:
27-
"""Returns average size of wires' first cell"""
28-
if len(wires) == 0:
29-
return None
29+
return count
3030

31-
return sum(wire.grading.start_size for wire in wires) / len(wires)
31+
def grade_axis(self, axis: DirectionType, take: ChopTakeType, stage: int) -> None:
32+
handled_wires = set()
3233

33-
def grade_axis(self, axis: DirectionType, take: ChopTakeType) -> None:
3434
for row in self.probe.get_rows(axis):
35-
# determine count
36-
wires = row.get_wires()
37-
38-
for wire in wires:
39-
if wire.is_defined:
40-
# there's a wire with a defined count already, use that
41-
count = wire.grading.count
42-
break
43-
else:
44-
# take length from a row, as requested
45-
length = row.get_length(take)
46-
# and set count from it
47-
count = self.params.get_count(length)
35+
count = self.get_count(row, take)
4836

4937
for wire in row.get_wires():
38+
if wire in handled_wires:
39+
continue
40+
5041
# don't touch defined wires
5142
# TODO! don't touch wires, defined by USER
5243
# if wire.is_defined:
5344
# # TODO: test
5445
# continue
5546

56-
size_before = self._get_end_size(wire.before)
57-
size_after = self._get_start_size(wire.after)
58-
chops = self.params.get_chops(count, wire.length, size_before, size_after)
47+
size_before = wire.size_before
48+
size_after = wire.size_after
49+
50+
chops = self.params.get_chops(stage, count, wire.length, size_before, size_after)
5951

6052
wire.grading.clear()
6153
for chop in chops:
6254
wire.grading.add_chop(chop)
6355

56+
wire.copy_to_coincidents()
57+
58+
handled_wires.add(wire)
59+
handled_wires.update(wire.coincidents)
60+
6461
def grade(self, take: ChopTakeType = "avg") -> None:
6562
for axis in get_args(DirectionType):
66-
self.grade_axis(axis, take)
63+
for stage in range(self.stages):
64+
self.grade_axis(axis, take, stage)
6765

6866

6967
class FixedCountGrader(GraderBase):
7068
"""The simplest possible mesh grading: use a constant cell count for all axes on all blocks;
7169
useful during mesh building and some tutorial cases"""
7270

71+
stages = 1
72+
7373
def __init__(self, mesh: Mesh, params: FixedCountParams):
7474
super().__init__(mesh, params)
7575

@@ -79,6 +79,8 @@ class SimpleGrader(GraderBase):
7979
A single chop is used that sets cell count based on size.
8080
Cell sizes between blocks differ as blocks' sizes change."""
8181

82+
stages = 1
83+
8284
def __init__(self, mesh: Mesh, params: SimpleChopParams):
8385
super().__init__(mesh, params)
8486

@@ -89,38 +91,7 @@ class HighReGrader(GraderBase):
8991
are utilized to keep cell sizes between blocks consistent
9092
(as much as possible)"""
9193

94+
stages = 3
95+
9296
def __init__(self, mesh: Mesh, params: HighReChopParams):
9397
super().__init__(mesh, params)
94-
95-
def grade_axis(self, axis, take) -> None:
96-
for row in self.probe.get_rows(axis):
97-
# determine count
98-
wires = row.get_wires()
99-
100-
for wire in reversed(wires):
101-
if wire.is_defined:
102-
# there's a wire with a defined count already, use that
103-
count = wire.grading.count
104-
break
105-
else:
106-
# take length from a row, as requested
107-
length = row.get_length(take)
108-
# and set count from it
109-
count = self.params.get_count(length)
110-
111-
for wire in row.get_wires():
112-
# don't touch defined wires
113-
# TODO! don't touch wires, defined by USER
114-
# if wire.is_defined:
115-
# # TODO: test
116-
# continue
117-
118-
# make a rudimentary chop first, then adjust
119-
# in subsequent passes
120-
chops = [Chop(length_ratio=0.5, count=count // 2), Chop(length_ratio=0.5, count=count // 2)]
121-
122-
for chop in chops:
123-
wire.grading.add_chop(chop)
124-
125-
super().grade_axis(axis, take)
126-
super().grade_axis(axis, take)

src/classy_blocks/grading/autograding/params.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ def get_count(self, length: float) -> int:
3030
"""Calculates count based on given length - used once only"""
3131

3232
@abc.abstractmethod
33-
def get_chops(self, count: int, length: float, size_before: CellSizeType, size_after: CellSizeType) -> List[Chop]:
33+
def get_chops(
34+
self, stage: int, count: int, length: float, size_before: CellSizeType, size_after: CellSizeType
35+
) -> List[Chop]:
3436
"""Fixes cell count but modifies chops so that proper cell sizing will be obeyed"""
3537
# That depends on inherited classes' philosophy
3638

@@ -42,7 +44,7 @@ class FixedCountParams(ChopParams):
4244
def get_count(self, _length):
4345
return self.count
4446

45-
def get_chops(self, count, _length, _size_before=0, _size_after=0) -> List[Chop]:
47+
def get_chops(self, _stage, count, _length, _size_before=0, _size_after=0) -> List[Chop]:
4648
return [Chop(count=count)]
4749

4850

@@ -53,7 +55,7 @@ class SimpleChopParams(ChopParams):
5355
def get_count(self, length: float):
5456
return int(length / self.cell_size)
5557

56-
def get_chops(self, count, _length, _size_before=0, _size_after=0):
58+
def get_chops(self, _stage, count, _length, _size_before=0, _size_after=0):
5759
return [Chop(count=count)]
5860

5961

@@ -73,7 +75,9 @@ def get_count(self, length: float):
7375
def define_sizes(
7476
self, count: int, length: float, size_before: CellSizeType, size_after: CellSizeType
7577
) -> Tuple[float, float]:
76-
"""Defines start and end cell size with respect to given circumstances"""
78+
"""Defines start and end cell size.
79+
size_before and size_after are taken from preceding/following wires;
80+
when a size is None, this is the last/first wire."""
7781
if size_before == 0 or size_after == 0:
7882
# until all counts/sizes are defined
7983
# (the first pass with uniform grading),
@@ -82,28 +86,36 @@ def define_sizes(
8286

8387
# not enough room for all cells?
8488
cramped = self.cell_size * count > length
89+
base_size = length / count
90+
91+
if cramped:
92+
return base_size, base_size
8593

8694
if size_before is None:
87-
if cramped:
88-
size_before = length / count
89-
else:
90-
size_before = self.cell_size
95+
size_before = self.cell_size
9196

9297
if size_after is None:
93-
if cramped:
94-
size_after = length / count
95-
else:
96-
size_after = self.cell_size
98+
size_after = self.cell_size
9799

98100
return size_before, size_after
99101

100-
def get_chops(self, count, length, size_before=CellSizeType, size_after=CellSizeType):
102+
def get_chops(self, stage, count, length, size_before, size_after):
103+
halfcount = count // 2
104+
105+
uniform_chops = [
106+
Chop(length_ratio=0.5, count=halfcount),
107+
Chop(length_ratio=0.5, count=halfcount),
108+
]
109+
110+
if stage == 0:
111+
# start with simple uniformly graded chops first
112+
return uniform_chops
113+
101114
size_before, size_after = self.define_sizes(count, length, size_before, size_after)
102115

103116
# choose length ratio so that cells at the middle of blocks
104117
# (between the two chops) have the same size
105118
def fobj(lratio):
106-
halfcount = count // 2
107119
chop_1 = Chop(length_ratio=lratio, count=halfcount, start_size=size_before)
108120
data_1 = chop_1.calculate(length)
109121

@@ -228,5 +240,5 @@ def get_count(self, length: float):
228240
# return chops
229241
return 1
230242

231-
def get_chops(self, count, length, size_before=0, size_after=0) -> List[Chop]:
243+
def get_chops(self, stage, count, length, size_before=0, size_after=0) -> List[Chop]:
232244
raise NotImplementedError("TODO!")

src/classy_blocks/grading/autograding/probe.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import functools
2-
from typing import Dict, List, get_args
2+
from typing import Dict, List, Optional, get_args
33

44
from classy_blocks.items.block import Block
55
from classy_blocks.items.wires.axis import Axis
@@ -43,7 +43,7 @@ class Row:
4343
def __init__(self, direction: DirectionType):
4444
self.direction = direction
4545

46-
# block of different orientations can belong to the same row;
46+
# blocks of different orientations can belong to the same row;
4747
# remember how they are oriented
4848
self.blocks: List[Block] = []
4949
self.headings: List[DirectionType] = []
@@ -80,6 +80,13 @@ def get_wires(self) -> List[Wire]:
8080

8181
return wires
8282

83+
def get_count(self) -> Optional[int]:
84+
for wire in self.get_wires():
85+
if wire.is_defined:
86+
return wire.grading.count
87+
88+
return None
89+
8390

8491
class Catalogue:
8592
"""A collection of rows on a specified axis"""

0 commit comments

Comments
 (0)