Designers and Builders
Designers and Builders are the main structure in bluemira for creating a Component.
The two main classes are:
bluemira.base.designer.Designer: the Designer base classbluemira.base.builder.Builder: the Builder base class
A Designer carries out component design activities,
for example evaluating a geometry parameterisation,
or performing an optimisation.
It outputs a minimal representation of a component that can be used to generate geometry
(note that this minimal representation may itself be some, simple, geometry).
A Builder is responsible for generating and manipulating bluemira
geometry objects (CAD), to create a Component.
It will typically perform geometry operations like offsets or sweeps,
and is not intended to perform any complex calculations.
Designers
Designers solve the minimal design problem of a
Component or any other object that requires calculation or optimisation.
The minimal design problem could result in, for instance, a geometric wire
or some relevant values that allow the Builder to build
the Component CAD.
A Designer is optional as some components can be completely built with
user input and calculations from previous component design stages.
Optimisation problems should be run within a Designer.
A basic Designer only requires a run() method and a
param_cls attribute to store the ParameterFrame class reference.
Once initialised the Designer is run with its execute() method.
The below is for illustrative purposes and is overkill,
in this instance you would just have a Builder.
from dataclasses import dataclass
from bluemira.base.designer import Designer
from bluemira.base.parameter_frame import Parameter, ParameterFrame
@dataclass
class DesignerPF(ParameterFrame):
A: Parameter[float]
class MyDesigner(Designer[float]):
param_cls = DesignerPF
def run(self) -> float:
return self.params.A.value
To initialise a Designer you need any ParameterFrame instance that is a
superset of Designer.param_cls and optionally a build_config dictionary which
contains configuration options for the Designer.
It is possible to execute a Designer in different ways depending on requirements or
software availability. If another method such as mock() or read() is defined
and run_mode is specified in the build_config the execute() method will call the specified method.
class MyOtherDesigner(Designer[float]):
param_cls = DesignerPF
def run(self) -> float:
return self.params.A.value
def mock(self) -> float:
return self.params.A.value ** 2
params = {"A": {"value": 2, "unit": "dimensionless"}}
build_config = {"run_mode": "mock"}
designer = MyOtherDesigner(params, build_config)
print(designer.execute()) # == 4
Builders
The minimal design problem output if required along with user input to the Builder is all
the information needed to build the CAD for the Component.
The build() method of the Builder usually builds
the xz, xy and xyz views of a Component, and combines them into a component tree.
Although what the build method does is up to the Reactor Designer.
It is recommended to build only one xyz sector for a given component.
The resulting reactor build will be much faster and the
show_cad() and save_cad() methods
provide a n_sector argument which will copy and rotate each sector as needed for a given usecase.
Like a Designer a Builder requires a param_cls attribute
and is initialised with a ParameterFrame instance that is a superset of param_cls
and optionally the Designer.execute() output and a build_config dictionary.
The below is an example of a standard Builder structure and once initialised
the build() method is called to create the Component.
from dataclasses import dataclass
from bluemira.base.builder import Builder
from bluemira.base.components import Component
from bluemira.base.parameter_frame import Parameter, ParameterFrame
@dataclass
class BuilderPF(ParameterFrame):
R_0: Parameter[float]
class MyBuilder(Builder):
param_cls = BuilderPF
def build(self) -> Component:
return self.component_tree(
xz=[self.build_xz()],
xy=[self.build_xy()],
xyz=[self.build_xyz()],
)
def build_xz(self):
"""Build a 2D geometry PhysicalComponent"""
def build_xy(self):
"""Build a 2D geometry PhysicalComponent"""
def build_xyz(self):
"""Build a 3D geometry PhysicalComponent"""