from dataclasses import dataclass
from bluemira.display import plot_2d
from bluemira.display.plotter import PlotOptions
from bluemira.geometry.optimisation import optimise_geometry
from bluemira.geometry.parameterisations import GeometryParameterisation
from bluemira.geometry.tools import make_circle, make_polygon
from bluemira.geometry.wire import BluemiraWire
from bluemira.utilities.opt_variables import OptVariable, OptVariablesFrame, VarDictT, ov
@dataclass
class CircleOptVariables(OptVariablesFrame):
"""Optimisation variables for a circle in the xz-plane."""
radius: OptVariable = ov("radius", 10, 1e-5, 15)
centre_x: OptVariable = ov("centre_x", 0, -10, 10)
centre_z: OptVariable = ov("centre_z", 0, 0, 10)
class Circle(GeometryParameterisation):
"""Geometry parameterisation for a circle in the xz-plane."""
def __init__(self, var_dict: VarDictT | None = None):
opt_variables = CircleOptVariables()
opt_variables.adjust_variables(var_dict, strict_bounds=False)
super().__init__(opt_variables)
def create_shape(self, label: str = "") -> BluemiraWire:
"""Create the circle."""
return make_circle(
self.variables["radius"].value,
center=(
self.variables["centre_x"].value,
0,
self.variables["centre_z"].value,
),
axis=(0, 1, 0),
label=label,
)
zone = make_polygon({"x": [-2, -2, 3, 3], "z": [0, 1, 1, 0]}, closed=True)
# Now lets create our circle within the shape
circle = Circle({
"radius": {"value": 10},
"centre_x": {"value": -2},
"centre_z": {"value": 1.5},
})
plot_2d([circle.create_shape(), zone])
def objective(geom: GeometryParameterisation) -> float:
"""Objective function to minimise the perimeter of a circle."""
return geom.create_shape().length
result = optimise_geometry(
geom=circle,
f_objective=objective,
keep_out_zones=[{"wire": zone, "n_discr": 300, "tol": 1e-12}],
algorithm="SLSQP",
opt_conditions={"ftol_rel": 1e-8, "max_eval": 200},
)
print(result)
print(result.geom.variables)
plot_2d([result.geom.create_shape(), zone], PlotOptions(ndiscr=500))