Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added .bounding_box and refactored .largest_dimension #228

Merged
merged 8 commits into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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
40 changes: 11 additions & 29 deletions paramak/reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from cadquery import exporters

import paramak
from paramak.utils import _replace, get_hash
from paramak.utils import _replace, get_hash, get_bounding_box, get_largest_dimension


class Reactor:
Expand All @@ -25,32 +25,23 @@ class Reactor:
graveyard_offset.
graveyard_offset: The distance between the graveyard and the largest
shape. If graveyard_size is set the this is ignored.
largest_shapes: Identifying the shape(s) with the largest size in each
dimension (x,y,z) can speed up the production of the graveyard.
Defaults to None which finds the largest shapes by looping through
all the shapes and creating bounding boxes. This can be slow and
that is why the user is able to provide a subsection of shapes to
use when calculating the graveyard dimensions.
"""

def __init__(
self,
shapes_and_components: List[paramak.Shape] = [],
graveyard_size: float = 20_000.0,
graveyard_offset: Optional[float] = None,
largest_shapes: Optional[List[paramak.Shape]] = None,
):

self.shapes_and_components = shapes_and_components
self.graveyard_offset = graveyard_offset
self.graveyard_size = graveyard_size
self.largest_shapes = largest_shapes

self.input_variable_names: List[str] = [
# 'shapes_and_components', commented out to avoid calculating solids
"graveyard_size",
"graveyard_offset",
"largest_shapes",
]

self.stp_filenames: List[str] = []
Expand Down Expand Up @@ -99,31 +90,22 @@ def graveyard_offset(self, value):
def largest_dimension(self):
"""Calculates a bounding box for the Reactor and returns the largest
absolute value of the largest dimension of the bounding box"""
largest_dimension = 0

if self.largest_shapes is None:
shapes_to_bound = self.shapes_and_components
else:
shapes_to_bound = self.largest_shapes

for component in shapes_to_bound:
largest_dimension = max(largest_dimension, component.largest_dimension)
# self._largest_dimension = largest_dimension
return largest_dimension
return get_largest_dimension(self.solid)

@largest_dimension.setter
def largest_dimension(self, value):
self._largest_dimension = value

@property
def largest_shapes(self):
return self._largest_shapes

@largest_shapes.setter
def largest_shapes(self, value):
if not isinstance(value, (list, tuple, type(None))):
raise ValueError("paramak.Reactor.largest_shapes should be a " "list of paramak.Shapes")
self._largest_shapes = value
def bounding_box(self):
"""Calculates returns the largest distance from the origin (0,0,0)
coordinate as an absolute value"""

return get_bounding_box(self.solid)

@bounding_box.setter
def bounding_box(self, value):
self._bounding_box = value

@property
def shapes_and_components(self):
Expand Down
41 changes: 15 additions & 26 deletions paramak/shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
facet_wire,
get_hash,
intersect_solid,
plotly_trace,
union_solid,
get_largest_dimension,
get_bounding_box,
)


Expand Down Expand Up @@ -217,36 +218,24 @@ def union(self, value):
def largest_dimension(self):
"""Calculates a bounding box for the Shape and returns the largest
absolute value of the largest dimension of the bounding box"""
largest_dimension = 0
if isinstance(self.solid, (Compound, shapes.Solid)):
for solid in self.solid.Solids():
bound_box = solid.BoundingBox()
largest_dimension = max(
abs(bound_box.xmax),
abs(bound_box.xmin),
abs(bound_box.ymax),
abs(bound_box.ymin),
abs(bound_box.zmax),
abs(bound_box.zmin),
largest_dimension,
)
else:
bound_box = self.solid.val().BoundingBox()
largest_dimension = max(
abs(bound_box.xmax),
abs(bound_box.xmin),
abs(bound_box.ymax),
abs(bound_box.ymin),
abs(bound_box.zmax),
abs(bound_box.zmin),
)
self.largest_dimension = largest_dimension
return largest_dimension

return get_largest_dimension(self.solid)

@largest_dimension.setter
def largest_dimension(self, value):
self._largest_dimension = value

@property
def bounding_box(self):
"""Calculates returns the largest distance from the origin (0,0,0)
coordinate as an absolute value"""

return get_bounding_box(self.solid)

@bounding_box.setter
def bounding_box(self, value):
self._bounding_box = value

@property
def workplane(self):
return self._workplane
Expand Down
55 changes: 49 additions & 6 deletions paramak/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,49 @@
import plotly.graph_objects as go
from cadquery import importers
from OCP.GCPnts import GCPnts_QuasiUniformDeflection
from cadquery.occ_impl import shapes

import paramak

def get_bounding_box(solid) -> Tuple[Tuple[float, float, float], Tuple[float, float, float]]:
"""Calculates a bounding box for the Shape and returns the coordinates of
the corners lower-left and upper-right. This function is useful when
creating OpenMC mesh tallies as the bounding box is required in this form"""

if isinstance(solid, (cq.Compound, shapes.Solid)):

bound_box = solid.BoundingBox()
# previous method lopped though solids but this is not needed
# for single_solid in solid.Solids():
# bound_box = single_solid.BoundingBox()

else:
bound_box = solid.val().BoundingBox()

lower_left = (bound_box.xmin, bound_box.ymin, bound_box.zmin)

upper_right = (bound_box.xmax, bound_box.ymax, bound_box.zmax)

return (lower_left, upper_right)


def get_largest_dimension(solid):
"""Calculates returns the largest distance from the origin (0,0,0)
coordinate as an absolute value"""

bounding_box = get_bounding_box(solid)

largest_dimension = max(
(
abs(bounding_box[0][0]),
abs(bounding_box[0][1]),
abs(bounding_box[0][2]),
abs(bounding_box[1][0]),
abs(bounding_box[1][1]),
abs(bounding_box[1][2]),
)
)

return largest_dimension


def transform_curve(edge, tolerance: Optional[float] = 1e-3):
Expand Down Expand Up @@ -314,7 +355,9 @@ def calculate_wedge_cut(self):
if self.rotation_angle == 360:
return None

cutting_wedge = paramak.CuttingWedgeFS(self)
from paramak import CuttingWedgeFS

cutting_wedge = CuttingWedgeFS(self)
return cutting_wedge


Expand Down Expand Up @@ -632,7 +675,7 @@ def export_wire_to_html(
tolerance=tolerance,
)

points = paramak.utils.extract_points_from_edges(edges=edges, view_plane=view_plane)
points = extract_points_from_edges(edges=edges, view_plane=view_plane)

fig.add_trace(plotly_trace(points=points, mode=mode, name="edge " + str(counter)))

Expand All @@ -648,7 +691,7 @@ def export_wire_to_html(
# this is for cadquery generated solids
edges = wire.val().Edges()

points = paramak.utils.extract_points_from_edges(edges=edges, view_plane=view_plane)
points = extract_points_from_edges(edges=edges, view_plane=view_plane)

fig.add_trace(plotly_trace(points=points, mode="markers", name="points on wire " + str(counter)))

Expand Down Expand Up @@ -694,9 +737,9 @@ def convert_circle_to_spline(
solid = solid.moveTo(p_0[0], p_0[1]).threePointArc(p_1, p_2)
edge = solid.vals()[0]

new_edge = paramak.utils.transform_curve(edge, tolerance=tolerance)
new_edge = transform_curve(edge, tolerance=tolerance)

points = paramak.utils.extract_points_from_edges(edges=new_edge, view_plane="XZ")
points = extract_points_from_edges(edges=new_edge, view_plane="XZ")

return points

Expand Down
4 changes: 2 additions & 2 deletions tests/test_parametric_reactors/test_ball_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def setUp(self):
def test_input_variable_names(self):
"""tests that the number of inputs variables is correct"""

assert len(self.test_reactor.input_variables.keys()) == 28
assert len(self.test_reactor.input_variable_names) == 28
assert len(self.test_reactor.input_variables.keys()) == 27
assert len(self.test_reactor.input_variable_names) == 27

def test_creation_with_narrow_divertor(self):
"""Creates a BallReactor with a narrow divertor and checks that the correct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def setUp(self):
def test_input_variable_names(self):
"""tests that the number of inputs variables is correct"""

assert len(self.test_reactor.input_variables.keys()) == 17
assert len(self.test_reactor.input_variable_names) == 17
assert len(self.test_reactor.input_variables.keys()) == 16
assert len(self.test_reactor.input_variable_names) == 16

def test_creation(self):
"""Creates a ball reactor using the CenterColumnStudyReactor parametric_reactor and checks
Expand Down
4 changes: 2 additions & 2 deletions tests/test_parametric_reactors/test_eu_demo_2015_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ def test_input_variable_names(self):
"""tests that the number of inputs variables is correct"""

my_reactor = paramak.EuDemoFrom2015PaperDiagram(number_of_tf_coils=1)
assert len(my_reactor.input_variables.keys()) == 5
assert len(my_reactor.input_variable_names) == 5
assert len(my_reactor.input_variables.keys()) == 4
assert len(my_reactor.input_variable_names) == 4

def test_plasma_construction(self):
"""Creates the plasma part of the EuDemoFrom2015PaperDiagram and checks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def setUp(self):
def test_input_variable_names(self):
"""tests that the number of inputs variables is correct"""

assert len(self.test_reactor.input_variables.keys()) == 13
assert len(self.test_reactor.input_variable_names) == 13
assert len(self.test_reactor.input_variables.keys()) == 12
assert len(self.test_reactor.input_variable_names) == 12

def test_stp_file_creation(self):
"""Exports a step file and checks that it was saved successfully"""
Expand Down
4 changes: 2 additions & 2 deletions tests/test_parametric_reactors/test_iter_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ def test_input_variable_names(self):
"""tests that the number of inputs variables is correct"""

my_reactor = paramak.IterFrom2020PaperDiagram(number_of_tf_coils=1)
assert len(my_reactor.input_variables.keys()) == 5
assert len(my_reactor.input_variable_names) == 5
assert len(my_reactor.input_variables.keys()) == 4
assert len(my_reactor.input_variable_names) == 4

def test_plasma_construction(self):
"""Creates the plasma part of the ITERTokamak and checks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ def setUp(self):
def test_input_variable_names(self):
"""tests that the number of inputs variable is correct"""

assert len(self.test_reactor.input_variables.keys()) == 31
assert len(self.test_reactor.input_variable_names) == 31
assert len(self.test_reactor.input_variables.keys()) == 30
assert len(self.test_reactor.input_variable_names) == 30

def test_gap_between_blankets_impacts_volume(self):
"""Creates a SegmentedBlanketBallReactor with different
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def setUp(self):
def test_input_variable_names(self):
"""tests that the number of inputs variables is correct"""

assert len(self.test_reactor.input_variables.keys()) == 28
assert len(self.test_reactor.input_variable_names) == 28
assert len(self.test_reactor.input_variables.keys()) == 27
assert len(self.test_reactor.input_variable_names) == 27

def test_single_null_ball_reactor_with_pf_and_tf_coils(self):
"""Checks that a SingleNullBallReactor with optional pf and tf coils can
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ def setUp(self):
def test_input_variable_names(self):
"""tests that the number of inputs variables is correct"""

assert len(self.test_reactor.input_variables.keys()) == 29
assert len(self.test_reactor.input_variable_names) == 29
assert len(self.test_reactor.input_variables.keys()) == 27
assert len(self.test_reactor.input_variable_names) == 27

def test_single_null_submersion_tokamak_with_pf_and_tf_coils(self):
"""Creates a SingleNullSubmersionTokamak with pf and tf coils and checks
Expand Down
4 changes: 2 additions & 2 deletions tests/test_parametric_reactors/test_sparc_2020_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ def setUp(self):
def test_input_variables_names(self):
"""tests that the number of inputs variables is correct"""

assert len(self.test_reactor.input_variables.keys()) == 28
assert len(self.test_reactor.input_variable_names) == 28
assert len(self.test_reactor.input_variables.keys()) == 27
assert len(self.test_reactor.input_variable_names) == 27

def test_make_sparc_2020_reactor(self):
"""Runs the example to check the output files are produced"""
Expand Down
17 changes: 15 additions & 2 deletions tests/test_parametric_shapes/test_extrude_straight_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,28 @@ class TestExtrudeStraightShape(unittest.TestCase):
def setUp(self):
self.test_shape = ExtrudeStraightShape(points=[(10, 10), (10, 30), (30, 30), (30, 10)], distance=30)

def test_bounding_box(self):
"""checks the bounding box value"""

assert self.test_shape.bounding_box == (
(10.0, -15.0, 10.0),
(30.0, 15.0, 30.0),
)

def test_largest_dimension(self):
"""checks the largest dimension value"""

assert self.test_shape.largest_dimension == 30.0

def test_translate(self):
"""Checks the shape extends to the bounding box and then translates
the shape and checks it is extended to the new bounding box"""

assert self.test_shape.solid.val().BoundingBox().xmax == 30
assert self.test_shape.solid.val().BoundingBox().xmin == 10
assert self.test_shape.solid.val().BoundingBox().ymax == 15
assert self.test_shape.solid.val().BoundingBox().ymin == -15
assert self.test_shape.solid.val().BoundingBox().zmax == 30
assert self.test_shape.solid.val().BoundingBox().xmin == 10
assert self.test_shape.solid.val().BoundingBox().ymin == -15
assert self.test_shape.solid.val().BoundingBox().zmin == 10

self.test_shape.translate = (1, 2, 3)
Expand Down
Loading