Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def main():

component = paramak.PortCutterRectangular(
distance=3,
z_pos=0,
center_point=(0, 0),
height=0.2,
width=0.4,
fillet_radius=0.02,
Expand All @@ -344,7 +344,7 @@ def main():

component = paramak.PortCutterCircular(
distance=3,
z_pos=0.25,
center_point=(0.25, 0),
radius=0.1,
# azimuth_placement_angle=[0, 45, 90, 180], # TODO: fix issue #548
azimuth_placement_angle=[0, 45, 90],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ def main():
# makes the middle row of ports
circular_ports = paramak.PortCutterCircular(
distance=5,
z_pos=0,
center_point=(0, 0),
radius=0.2,
azimuth_placement_angle=angles_for_ports
)

# makes the lower row of ports
rectangular_ports = paramak.PortCutterRectangular(
distance=5,
z_pos=-1,
center_point=(-1, 0),
height=0.3,
width=0.4,
fillet_radius=0.08,
Expand Down
1 change: 1 addition & 0 deletions paramak/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
from .parametric_components.shell_fs import ShellFS

from .parametric_reactors.ball_reactor import BallReactor
from .parametric_reactors.ball_reactor_with_ports import BallReactorWithPorts
from .parametric_reactors.submersion_reactor import SubmersionTokamak
from .parametric_reactors.single_null_submersion_reactor import SingleNullSubmersionTokamak
from .parametric_reactors.single_null_ball_reactor import SingleNullBallReactor
Expand Down
43 changes: 22 additions & 21 deletions paramak/parametric_components/port_cutters_circular.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@

from paramak import ExtrudeCircleShape

from typing import Optional


class PortCutterCircular(ExtrudeCircleShape):
"""Creates an extruded shape with a circular section that is used to cut
other components (eg. blanket, vessel,..) in order to create ports.

Args:
z_pos (float): Z position (cm) of the port
height (float): height (cm) of the port
width (float): width (cm) of the port
distance (float): extruded distance (cm) of the cutter
stp_filename (str, optional): defaults to "PortCutterCircular.stp".
stl_filename (str, optional): defaults to "PortCutterCircular.stl".
name (str, optional): defaults to "circular_port_cutter".
material_tag (str, optional): defaults to "circular_port_cutter_mat".
extrusion_start_offset (float, optional): the distance between 0 and
center_point: center point of the port cutter. Defaults to (0, 0).
radius: radius (cm) of port cutter.
distance: extruded distance (cm) of the port cutter.
stp_filename: defaults to "PortCutterCircular.stp".
stl_filename: defaults to "PortCutterCircular.stl".
name: defaults to "circular_port_cutter".
material_tag: defaults to "circular_port_cutter_mat".
extrusion_start_offset: the distance between 0 and
the start of the extrusion. Defaults to 1..
"""

def __init__(
self,
z_pos,
radius,
distance,
workplane="ZY",
rotation_axis="Z",
extrusion_start_offset=1.,
stp_filename="PortCutterCircular.stp",
stl_filename="PortCutterCircular.stl",
name="circular_port_cutter",
material_tag="circular_port_cutter_mat",
radius: float,
distance: float,
center_point: Optional[tuple] = (0, 0),
workplane: Optional[str] = "ZY",
rotation_axis: Optional[str] = "Z",
extrusion_start_offset: Optional[float] = 1.,
stp_filename: Optional[str] = "PortCutterCircular.stp",
stl_filename: Optional[str] = "PortCutterCircular.stl",
name: Optional[str] = "circular_port_cutter",
material_tag: Optional[str] = "circular_port_cutter_mat",
**kwargs
):
super().__init__(
Expand All @@ -47,8 +48,8 @@ def __init__(
**kwargs
)

self.z_pos = z_pos
self.center_point = center_point
self.radius = radius

def find_points(self):
self.points = [(0, self.z_pos)]
self.points = [self.center_point]
54 changes: 33 additions & 21 deletions paramak/parametric_components/port_cutters_rectangular.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@

from paramak import ExtrudeStraightShape

from typing import Optional


class PortCutterRectangular(ExtrudeStraightShape):
"""Creates an extruded shape with a rectangular section that is used to cut
other components (eg. blanket, vessel,..) in order to create ports.

Args:
z_pos (float): Z position (cm) of the port
height (float): height (cm) of the port
width (float): width (cm) of the port
distance (float): extruded distance (cm) of the cutter
center_point: Center point of the port cutter. Defaults to (0, 0).
height: height (cm) of the port cutter.
width: width (cm) of the port cutter.
distance: extruded distance (cm) of the port cutter.
fillet_radius (float, optional): If not None, radius (cm) of fillets
added to edges orthogonal to the Z direction. Defaults to None.
stp_filename (str, optional): defaults to "PortCutterRectangular.stp".
Expand All @@ -24,18 +26,18 @@ class PortCutterRectangular(ExtrudeStraightShape):

def __init__(
self,
z_pos,
height,
width,
distance,
workplane="ZY",
rotation_axis="Z",
extrusion_start_offset=1.,
fillet_radius=None,
stp_filename="PortCutterRectangular.stp",
stl_filename="PortCutterRectangular.stl",
name="rectangular_port_cutter",
material_tag="rectangular_port_cutter_mat",
height: float,
width: float,
distance: float,
center_point: Optional[tuple] = (0, 0),
workplane: Optional[str] = "ZY",
rotation_axis: Optional[str] = "Z",
extrusion_start_offset: Optional[float] = 1.,
fillet_radius: Optional[float] = None,
stp_filename: Optional[str] = "PortCutterRectangular.stp",
stl_filename: Optional[str] = "PortCutterRectangular.stl",
name: Optional[str] = "rectangular_port_cutter",
material_tag: Optional[str] = "rectangular_port_cutter_mat",
**kwargs
):

Expand All @@ -52,11 +54,11 @@ def __init__(
**kwargs
)

self.z_pos = z_pos
self.center_point = center_point
self.height = height
self.width = width
self.fillet_radius = fillet_radius
self.add_fillet()
# self.add_fillet()

def find_points(self):
points = [
Expand All @@ -65,9 +67,19 @@ def find_points(self):
(self.width / 2, self.height / 2),
(-self.width / 2, self.height / 2),
]
points = [(e[0], e[1] + self.z_pos) for e in points]
points = [(e[0] + self.center_point[0], e[1] +
self.center_point[1]) for e in points]
self.points = points

def add_fillet(self):
def add_fillet(self, solid):
if "X" not in self.workplane:
filleting_edge = "|X"
if "Y" not in self.workplane:
filleting_edge = "|Y"
if "Z" not in self.workplane:
filleting_edge = "|Z"

if self.fillet_radius is not None and self.fillet_radius != 0:
self.solid = self.solid.edges('#Z').fillet(self.fillet_radius)
solid = solid.edges(filleting_edge).fillet(self.fillet_radius)

return solid
4 changes: 4 additions & 0 deletions paramak/parametric_reactors/ball_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import warnings

import paramak
from paramak.utils import perform_port_cutting


class BallReactor(paramak.Reactor):
Expand Down Expand Up @@ -423,6 +424,9 @@ def _make_blankets_layers(self):
cut=[self._center_column_cutter],
)

self._firstwall, self._blanket, self._blanket_rear_wall = perform_port_cutting(
self, self._firstwall, self._blanket, self._blanket_rear_wall)

return [self._firstwall, self._blanket, self._blanket_rear_wall]

def _make_divertor(self):
Expand Down
69 changes: 69 additions & 0 deletions paramak/parametric_reactors/ball_reactor_with_ports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

import warnings
from typing import Optional

import numpy as np
import paramak
from paramak.utils import perform_port_cutting


class BallReactorWithPorts(paramak.BallReactor):
"""Creates geometry for a simple ball reactor including a plasma,
cylindrical center column shielding, square toroidal field coils
and ports. There is no inboard breeder blanket on this ball reactor
like most spherical reactors.

Arguments:
port_type: type of port to be cut. Defaults to None.
port_center_point: position of port center point in the workplane
given. Defaults to (0, 0).
port_radius: radius of circular ports. Defaults to None.
port_height: height of rectangular ports. Defaults to None.
port_width: width of rectangular ports. Defaults to None.
port_distance: extrusion distance of port cutter. Defaults to None.
port_azimuth_placement_angle: azimuthal placement angle of each port.
Defaults to None if no ports are created. Defaults to list of
equally spaced floats between 0 and 360 of length equal to
number_of_ports if number_of_ports is provided but
port_azimuth_placement_angle is not.
port_start_radius: extrusion start point of port cutter. Defaults
to major_radius.
port_fillet_radius: fillet radius of rectangular ports. Defaults to 0.
"""

def __init__(
self,
port_type: Optional[str] = None,
port_center_point: Optional[tuple] = (0, 0),
port_radius: Optional[float] = None,
port_height: Optional[float] = None,
port_width: Optional[float] = None,
port_distance: Optional[float] = None,
port_azimuth_placement_angle: Optional[list] = None,
port_start_radius: Optional[float] = None,
port_fillet_radius: Optional[float] = 0,
**kwargs
):

super().__init__(**kwargs)

self.port_type = port_type
self.port_center_point = port_center_point
self.port_radius = port_radius
self.port_height = port_height
self.port_width = port_width
self.port_distance = port_distance
self.port_azimuth_placement_angle = port_azimuth_placement_angle
self.port_start_radius = port_start_radius
self.port_fillet_radius = port_fillet_radius

@property
def port_start_radius(self):
return self._port_start_radius

@port_start_radius.setter
def port_start_radius(self, value):
if value is None:
self._port_start_radius = self.major_radius
else:
self._port_start_radius = value
5 changes: 5 additions & 0 deletions paramak/parametric_shapes/extruded_mixed_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ def create_solid(self):
distance=extrusion_distance,
both=self.extrude_both)

# filleting rectangular port cutter edges
# must be done before azimuthal placement
if hasattr(self, "add_fillet"):
solid = self.add_fillet(solid)

solid = self.rotate_solid(solid)
cutting_wedge = calculate_wedge_cut(self)
solid = self.perform_boolean_operations(solid, wedge_cut=cutting_wedge)
Expand Down
58 changes: 58 additions & 0 deletions paramak/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,64 @@ def export_wire_to_html(
return fig


def perform_port_cutting(self, *args):

components = []

if self.port_type is None:
for component in args:
components.append(component)
if len(args) == 1:
return component
return components

else:
if self.port_type == "circular":
if self.port_height is not None or self.port_width is not None:
raise ValueError('only port_radius should be specified')
if self.port_radius is None:
raise ValueError('port_radius must be specified')

port_cutter = paramak.PortCutterCircular(
center_point=self.port_center_point,
radius=self.port_radius,
distance=self.port_distance,
extrusion_start_offset=self.port_start_radius,
azimuth_placement_angle=self.port_azimuth_placement_angle
)

elif self.port_type == "rectangular":
if self.port_radius is not None:
raise ValueError(
'only port_height and port_width should be specified')
if self.port_height is None or self.port_width is None:
raise ValueError(
'port_height and port_width must be specified')

port_cutter = paramak.PortCutterRectangular(
center_point=self.port_center_point,
height=self.port_height,
width=self.port_width,
distance=self.port_distance,
extrusion_start_offset=self.port_start_radius,
fillet_radius=self.port_fillet_radius,
azimuth_placement_angle=self.port_azimuth_placement_angle
)

else:
raise ValueError('invalid port type')

for component in args:
if component.cut is None:
component.cut = [port_cutter]
else:
component.cut.insert(0, port_cutter)
components.append(component)
if len(args) == 1:
return component
return components


class FaceAreaSelector(cq.Selector):
"""A custom CadQuery selector the selects faces based on their area with a
tolerance. The following useage example will fillet the faces of an extrude
Expand Down
Loading