Skip to content

Commit 22d5ae0

Browse files
committed
Add a ShapeOptimizer and an example usage
1 parent db90e0c commit 22d5ae0

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

examples/optimization/duct.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# An example where a Shape is optimized *before* it is added to mesh, using ShapeOptimizer
2+
import os
3+
4+
import classy_blocks as cb
5+
from classy_blocks.optimize.junction import ClampExistsError
6+
from classy_blocks.optimize.optimizer import ShapeOptimizer
7+
8+
mesh = cb.Mesh()
9+
10+
start_sketch = cb.SplineDisk([0, 0, 0], [2.5, 0, 0], [0, 1, 0], 0, 0)
11+
end_sketch = cb.SplineDisk([0, 0, 0], [1, 0, 0], [0, 2.5, 0], 0, 0).translate([0, 0, 1])
12+
13+
shape = cb.LoftedShape(start_sketch, end_sketch)
14+
15+
optimizer = ShapeOptimizer(shape.operations)
16+
17+
for operation in shape.operations[:4]:
18+
# remove edges because inner splines will ruin the day
19+
# TODO: make edges move with points too
20+
operation.top_face.remove_edges()
21+
operation.bottom_face.remove_edges()
22+
23+
for point in operation.point_array:
24+
try:
25+
optimizer.add_clamp(cb.FreeClamp(point))
26+
except ClampExistsError:
27+
pass
28+
29+
optimizer.optimize(tolerance=0.01)
30+
31+
# Quick'n'dirty chopping, don't do this at home
32+
for operation in shape.operations:
33+
for axis in range(3):
34+
operation.chop(axis, count=10)
35+
36+
mesh.add(shape)
37+
38+
mesh.set_default_patch("walls", "wall")
39+
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")

src/classy_blocks/optimize/mapper.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from classy_blocks.util import functions as f
77
from classy_blocks.util.constants import TOL
88

9+
ElementType = Union[Face, Operation]
10+
911

1012
class Mapper:
1113
"""A helper that constructs mapped sketches/shapes
@@ -32,8 +34,21 @@ def _add_point(self, point: NPPointType) -> int:
3234

3335
return index
3436

35-
def add(self, element: Union[Face, Operation]):
37+
def add(self, element: ElementType) -> None:
3638
"""Add Face's or Operation's points to the map"""
3739
indexes = [self._add_point(point) for point in element.point_array]
3840
self.indexes.append(indexes)
3941
self.elements.append(element)
42+
43+
@classmethod
44+
def from_map(cls, points: List[NPPointType], indexes: List[IndexType], elements: List[ElementType]) -> "Mapper":
45+
"""Creates a ready-made mapper from a sketch/shape that already has points/indexes defined"""
46+
if len(indexes) != len(elements):
47+
raise ValueError("Number of indexes and elements don't match!")
48+
49+
mapper = cls()
50+
mapper.points = points
51+
mapper.indexes = indexes
52+
mapper.elements = elements
53+
54+
return mapper

src/classy_blocks/optimize/optimizer.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import abc
22
import copy
33
import time
4-
from typing import Literal
4+
from typing import List, Literal
55

66
import numpy as np
77
import scipy.optimize
88

99
from classy_blocks.construct.flat.sketches.mapped import MappedSketch
10+
from classy_blocks.construct.operations.operation import Operation
1011
from classy_blocks.mesh import Mesh
1112
from classy_blocks.optimize.clamps.clamp import ClampBase
1213
from classy_blocks.optimize.clamps.surface import PlaneClamp
1314
from classy_blocks.optimize.grid import GridBase, HexGrid, QuadGrid
1415
from classy_blocks.optimize.iteration import ClampOptimizationData, IterationDriver
1516
from classy_blocks.optimize.links import LinkBase
17+
from classy_blocks.optimize.mapper import Mapper
1618
from classy_blocks.util.constants import TOL
1719

1820
MinimizationMethodType = Literal["SLSQP", "L-BFGS-B", "Nelder-Mead", "Powell"]
@@ -148,6 +150,26 @@ def backport(self):
148150
self.mesh.vertices[i].move_to(point)
149151

150152

153+
class ShapeOptimizer(OptimizerBase):
154+
def __init__(self, operations: List[Operation], report: bool = True):
155+
self.mapper = Mapper()
156+
157+
for operation in operations:
158+
self.mapper.add(operation)
159+
160+
grid = HexGrid(np.array(self.mapper.points), self.mapper.indexes)
161+
162+
super().__init__(grid, report)
163+
164+
def backport(self) -> None:
165+
# Move every point of every operation to wherever it is now
166+
for iop, indexes in enumerate(self.mapper.indexes):
167+
operation = self.mapper.elements[iop]
168+
169+
for ipnt, i in enumerate(indexes):
170+
operation.points[ipnt].move_to(self.grid.points[i])
171+
172+
151173
class SketchOptimizer(OptimizerBase):
152174
def __init__(self, sketch: MappedSketch, report: bool = True):
153175
self.sketch = sketch

0 commit comments

Comments
 (0)