From ed314ae27a7367660a32d12936d9b7c6f42b1ba7 Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 9 Aug 2024 15:42:48 +0200 Subject: [PATCH 01/52] Add test for microtile classes --- splinepy/microstructure/microstructure.py | 4 +- splinepy/microstructure/tiles/__init__.py | 2 + splinepy/microstructure/tiles/armadillo.py | 9 + splinepy/microstructure/tiles/chi.py | 14 +- splinepy/microstructure/tiles/cross_2d.py | 15 +- splinepy/microstructure/tiles/cross_3d.py | 6 + .../microstructure/tiles/cross_3d_linear.py | 2 + splinepy/microstructure/tiles/cube_void.py | 1 + .../microstructure/tiles/double_lattice.py | 3 +- splinepy/microstructure/tiles/ellips_v_oid.py | 1 + splinepy/microstructure/tiles/hollow_cube.py | 1 + .../microstructure/tiles/hollow_octagon.py | 2 + .../tiles/hollow_octagon_extrude.py | 4 +- .../microstructure/tiles/inverse_cross_3d.py | 556 +++++++++--------- splinepy/microstructure/tiles/snappy.py | 4 +- tests/test_microstructure.py | 75 +++ 16 files changed, 412 insertions(+), 287 deletions(-) create mode 100644 tests/test_microstructure.py diff --git a/splinepy/microstructure/microstructure.py b/splinepy/microstructure/microstructure.py index 366935651..bb34246c6 100644 --- a/splinepy/microstructure/microstructure.py +++ b/splinepy/microstructure/microstructure.py @@ -9,7 +9,7 @@ class Microstructure(_SplinepyBase): - """Helper class to facilitatae the construction of microstructures.""" + """Helper class to facilitate the construction of microstructures.""" def __init__( self, @@ -18,7 +18,7 @@ def __init__( microtile=None, parametrization_function=None, ): - """Helper class to facilitatae the construction of microstructures. + """Helper class to facilitate the construction of microstructures. Parameters ---------- diff --git a/splinepy/microstructure/tiles/__init__.py b/splinepy/microstructure/tiles/__init__.py index 3b35a1f5c..f1b703a04 100644 --- a/splinepy/microstructure/tiles/__init__.py +++ b/splinepy/microstructure/tiles/__init__.py @@ -8,6 +8,7 @@ armadillo, chi, cross_2d, + cross_3d, cross_3d_linear, cube_void, double_lattice, @@ -42,6 +43,7 @@ "chi", "cross_2d", "cube_void", + "cross_3d", "cross_3d_linear", "double_lattice", "ellips_v_oid", diff --git a/splinepy/microstructure/tiles/armadillo.py b/splinepy/microstructure/tiles/armadillo.py index e7f39aa66..9bbf602da 100644 --- a/splinepy/microstructure/tiles/armadillo.py +++ b/splinepy/microstructure/tiles/armadillo.py @@ -20,6 +20,15 @@ class Armadillo(_TileBase): _dim = 3 _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 1 + _sensitivities_implemented = False + _closure_directions = [ + "x_min", + "x_max", + "y_min", + "y_max", + "z_min", + "z_max", + ] def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/chi.py b/splinepy/microstructure/tiles/chi.py index b8430d0dc..e3cbf708b 100644 --- a/splinepy/microstructure/tiles/chi.py +++ b/splinepy/microstructure/tiles/chi.py @@ -18,6 +18,9 @@ class Chi(_TileBase): _para_dim = 1 _evaluation_points = _np.array([[0.5, 0.5]]) _n_info_per_eval_point = 1 + _sensitivities_implemented = True + + _parameter_bounds = {"parameters": [-_np.pi / 2, _np.pi / 2]} def create_tile( self, @@ -48,11 +51,16 @@ def create_tile( ) parameters = _np.array([[_np.pi / 8]]) else: + angle_bounds = self._parameter_bounds["parameters"] if not ( - _np.all(parameters >= -_np.pi * 0.5) - and _np.all(parameters < _np.pi * 0.5) + _np.all(parameters >= angle_bounds[0]) + and _np.all(parameters < angle_bounds[1]) ): - raise ValueError("The parameter must be in -Pi/2 and Pi/2") + error_message = ( + f"The parameter must be in {angle_bounds[0]}" + + f"and {angle_bounds[1]}" + ) + raise ValueError(error_message) pass self.check_params(parameters) diff --git a/splinepy/microstructure/tiles/cross_2d.py b/splinepy/microstructure/tiles/cross_2d.py index 083d0c65a..cf4a988d2 100644 --- a/splinepy/microstructure/tiles/cross_2d.py +++ b/splinepy/microstructure/tiles/cross_2d.py @@ -26,6 +26,9 @@ class Cross2D(_TileBase): ] ) _n_info_per_eval_point = 1 + _parameter_bounds = {"center_expansion": [0.5, 1.5]} + _sensitivities_implemented = True + _closure_directions = ["x_min", "x_max", "y_min", "y_max"] def _closing_tile( self, @@ -417,8 +420,16 @@ def create_tile( if not isinstance(center_expansion, float): raise ValueError("Invalid Type") - if not ((center_expansion > 0.5) and (center_expansion < 1.5)): - raise ValueError("Center Expansion must be in (.5,1.5)") + center_expansion_bounds = self._parameter_bounds["center_expansion"] + if not ( + (center_expansion > center_expansion_bounds[0]) + and (center_expansion < center_expansion_bounds[1]) + ): + error_message = ( + "Center Expansion must be in (" + + f"{center_expansion_bounds[0]}, {center_expansion_bounds[1]})" + ) + raise ValueError(error_message) max_radius = min(0.5, (0.5 / center_expansion)) diff --git a/splinepy/microstructure/tiles/cross_3d.py b/splinepy/microstructure/tiles/cross_3d.py index 8752c9881..01282c6f3 100644 --- a/splinepy/microstructure/tiles/cross_3d.py +++ b/splinepy/microstructure/tiles/cross_3d.py @@ -28,6 +28,8 @@ class Cross3D(_TileBase): ] ) _n_info_per_eval_point = 1 + _sensitivities_implemented = True + _closure_directions = ["z_min", "z_max"] def _closing_tile( self, @@ -557,6 +559,10 @@ def create_tile( derivatives = None if closure is not None: + if closure not in self._closure_directions: + raise NotImplementedError( + f"Closure '{closure}' not implemented" + ) return self._closing_tile( parameters=parameters, parameter_sensitivities=parameter_sensitivities, diff --git a/splinepy/microstructure/tiles/cross_3d_linear.py b/splinepy/microstructure/tiles/cross_3d_linear.py index 3e5901371..952738afe 100644 --- a/splinepy/microstructure/tiles/cross_3d_linear.py +++ b/splinepy/microstructure/tiles/cross_3d_linear.py @@ -28,6 +28,8 @@ class Cross3DLinear(_TileBase): ] ) _n_info_per_eval_point = 1 + _sensitivities_implemented = True + _closure_directions = ["z_min", "z_max"] def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/cube_void.py b/splinepy/microstructure/tiles/cube_void.py index be4f1ab3a..a8da85df6 100644 --- a/splinepy/microstructure/tiles/cube_void.py +++ b/splinepy/microstructure/tiles/cube_void.py @@ -25,6 +25,7 @@ class CubeVoid(_TileBase): _para_dim = 3 _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 4 + _sensitivities_implemented = True # Aux values _sphere_ctps = _np.array( diff --git a/splinepy/microstructure/tiles/double_lattice.py b/splinepy/microstructure/tiles/double_lattice.py index ad8f6e803..ffb2166b2 100644 --- a/splinepy/microstructure/tiles/double_lattice.py +++ b/splinepy/microstructure/tiles/double_lattice.py @@ -20,6 +20,7 @@ class DoubleLattice(_TileBase): _para_dim = 2 _evaluation_points = _np.array([[0.5, 0.5]]) _n_info_per_eval_point = 2 + _sensitivities_implemented = True def create_tile( self, @@ -44,7 +45,7 @@ def create_tile( correlates with thickness of branches and entouring wall contact_length : double required for conformity between tiles, sets the length of the center - block on the tiles boundary + block on the tile's boundary Returns ------- diff --git a/splinepy/microstructure/tiles/ellips_v_oid.py b/splinepy/microstructure/tiles/ellips_v_oid.py index 4b6e7bf23..ec7a5cfe9 100644 --- a/splinepy/microstructure/tiles/ellips_v_oid.py +++ b/splinepy/microstructure/tiles/ellips_v_oid.py @@ -27,6 +27,7 @@ class EllipsVoid(_TileBase): _para_dim = 3 _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 4 + _sensitivities_implemented = True # Aux values _c0 = 0.5 / 3**0.5 diff --git a/splinepy/microstructure/tiles/hollow_cube.py b/splinepy/microstructure/tiles/hollow_cube.py index cd8cc300a..028ca0ed4 100644 --- a/splinepy/microstructure/tiles/hollow_cube.py +++ b/splinepy/microstructure/tiles/hollow_cube.py @@ -28,6 +28,7 @@ class HollowCube(_TileBase): ] ) _n_info_per_eval_point = 1 + _sensitivities_implemented = True def create_tile( self, diff --git a/splinepy/microstructure/tiles/hollow_octagon.py b/splinepy/microstructure/tiles/hollow_octagon.py index 20a628e17..44b31a65a 100644 --- a/splinepy/microstructure/tiles/hollow_octagon.py +++ b/splinepy/microstructure/tiles/hollow_octagon.py @@ -18,6 +18,8 @@ class HollowOctagon(_TileBase): _para_dim = 2 _evaluation_points = _np.array([[0.5, 0.5]]) _n_info_per_eval_point = 1 + _sensitivities_implemented = False + _closure_directions = ["x_min", "x_max", "y_min", "y_max"] def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/hollow_octagon_extrude.py b/splinepy/microstructure/tiles/hollow_octagon_extrude.py index 82e738d23..dbf5f1901 100644 --- a/splinepy/microstructure/tiles/hollow_octagon_extrude.py +++ b/splinepy/microstructure/tiles/hollow_octagon_extrude.py @@ -18,6 +18,8 @@ class HollowOctagonExtrude(_TileBase): _para_dim = 3 _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 1 + _sensitivities_implemented = False + _closure_directions = ["x_min", "x_max", "y_min", "y_max"] def create_tile( self, @@ -215,7 +217,7 @@ def create_tile( return (spline_list, None) - def closing_tile( + def _closing_tile( self, parameters=None, parameter_sensitivities=None, # TODO diff --git a/splinepy/microstructure/tiles/inverse_cross_3d.py b/splinepy/microstructure/tiles/inverse_cross_3d.py index c24954702..a633632fc 100644 --- a/splinepy/microstructure/tiles/inverse_cross_3d.py +++ b/splinepy/microstructure/tiles/inverse_cross_3d.py @@ -32,6 +32,8 @@ class InverseCross3D(_TileBase): ] ) _n_info_per_eval_point = 1 + _sensitivities_implemented = False + _closure_directions = ["z_min", "z_max"] def _closing_tile( self, @@ -40,7 +42,7 @@ def _closing_tile( closure=None, boundary_width=0.1, filling_height=0.5, - seperator_distance=None, + separator_distance=None, **kwargs, # noqa ARG002 ): """Create a closing tile to match with closed surface. @@ -53,7 +55,7 @@ def _closing_tile( with of the boundary surrounding branch filling_height : float portion of the height that is filled in parametric domain - seperator_distance : float + separator_distance : float Describes the position of the separator layer in the control point domain closure : str @@ -70,8 +72,8 @@ def _closing_tile( raise ValueError("No closing direction given") # Set default values - if seperator_distance is None: - seperator_distance = 0.3 + if separator_distance is None: + separator_distance = 0.3 if parameters is None: self._logd("Tile request is not parametrized, setting default 0.2") @@ -108,7 +110,7 @@ def _closing_tile( center_width = 1.0 - 2 * boundary_width r_center = center_width * 0.5 half_r_center = (r_center + 0.5) * 0.5 - aux_column_width = 0.5 - 2 * (0.5 - seperator_distance) + aux_column_width = 0.5 - 2 * (0.5 - separator_distance) spline_list = [] if closure == "z_min": @@ -123,7 +125,7 @@ def _closing_tile( [-r_center, r_center, filling_height], [-0.5, -aux_column_width, ctps_mid_height_top], [ - -seperator_distance, + -separator_distance, -aux_column_width, ctps_mid_height_top, ], @@ -134,16 +136,16 @@ def _closing_tile( ], [-0.5, aux_column_width, ctps_mid_height_top], [ - -seperator_distance, + -separator_distance, aux_column_width, ctps_mid_height_top, ], [-branch_thickness, branch_thickness, ctps_mid_height_top], [-0.5, -aux_column_width, 1.0], - [-seperator_distance, -aux_column_width, 1.0], + [-separator_distance, -aux_column_width, 1.0], [-branch_thickness, -branch_thickness, 1.0], [-0.5, aux_column_width, 1.0], - [-seperator_distance, aux_column_width, 1.0], + [-separator_distance, aux_column_width, 1.0], [-branch_thickness, branch_thickness, 1.0], ] ) + _np.array([0.5, 0.5, 0.0]) @@ -165,23 +167,23 @@ def _closing_tile( [0.5, r_center, filling_height], [branch_thickness, -branch_thickness, ctps_mid_height_top], [ - seperator_distance, + separator_distance, -aux_column_width, ctps_mid_height_top, ], [0.5, -aux_column_width, ctps_mid_height_top], [branch_thickness, branch_thickness, ctps_mid_height_top], [ - seperator_distance, + separator_distance, aux_column_width, ctps_mid_height_top, ], [0.5, aux_column_width, ctps_mid_height_top], [branch_thickness, -branch_thickness, 1.0], - [seperator_distance, -aux_column_width, 1.0], + [separator_distance, -aux_column_width, 1.0], [0.5, -aux_column_width, 1.0], [branch_thickness, branch_thickness, 1.0], - [seperator_distance, aux_column_width, 1.0], + [separator_distance, aux_column_width, 1.0], [0.5, aux_column_width, 1.0], ] ) + _np.array([0.5, 0.5, 0.0]) @@ -205,12 +207,12 @@ def _closing_tile( [aux_column_width, -0.5, ctps_mid_height_top], [ -aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_top, ], [ aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_top, ], [ @@ -221,8 +223,8 @@ def _closing_tile( [branch_thickness, -branch_thickness, ctps_mid_height_top], [-aux_column_width, -0.5, 1.0], [aux_column_width, -0.5, 1.0], - [-aux_column_width, -seperator_distance, 1.0], - [aux_column_width, -seperator_distance, 1.0], + [-aux_column_width, -separator_distance, 1.0], + [aux_column_width, -separator_distance, 1.0], [-branch_thickness, -branch_thickness, 1.0], [branch_thickness, -branch_thickness, 1.0], ] @@ -247,20 +249,20 @@ def _closing_tile( [branch_thickness, branch_thickness, ctps_mid_height_top], [ -aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_top, ], [ aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_top, ], [-aux_column_width, 0.5, ctps_mid_height_top], [aux_column_width, 0.5, ctps_mid_height_top], [-branch_thickness, branch_thickness, 1.0], [branch_thickness, branch_thickness, 1.0], - [-aux_column_width, seperator_distance, 1.0], - [aux_column_width, seperator_distance, 1.0], + [-aux_column_width, separator_distance, 1.0], + [aux_column_width, separator_distance, 1.0], [-aux_column_width, 0.5, 1.0], [aux_column_width, 0.5, 1.0], ] @@ -285,22 +287,22 @@ def _closing_tile( [-half_r_center, -r_center, filling_height], [-r_center, -r_center, filling_height], [-0.5, -0.5, ctps_mid_height_top], - [-seperator_distance, -0.5, ctps_mid_height_top], + [-separator_distance, -0.5, ctps_mid_height_top], [-aux_column_width, -0.5, ctps_mid_height_top], - [-0.5, -seperator_distance, ctps_mid_height_top], + [-0.5, -separator_distance, ctps_mid_height_top], [ - -seperator_distance, - -seperator_distance, + -separator_distance, + -separator_distance, ctps_mid_height_top, ], [ -aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_top, ], [-0.5, -aux_column_width, ctps_mid_height_top], [ - -seperator_distance, + -separator_distance, -aux_column_width, ctps_mid_height_top, ], @@ -310,13 +312,13 @@ def _closing_tile( ctps_mid_height_top, ], [-0.5, -0.5, 1.0], - [-seperator_distance, -0.5, 1.0], + [-separator_distance, -0.5, 1.0], [-aux_column_width, -0.5, 1.0], - [-0.5, -seperator_distance, 1.0], - [-seperator_distance, -seperator_distance, 1.0], - [-aux_column_width, -seperator_distance, 1.0], + [-0.5, -separator_distance, 1.0], + [-separator_distance, -separator_distance, 1.0], + [-aux_column_width, -separator_distance, 1.0], [-0.5, -aux_column_width, 1.0], - [-seperator_distance, -aux_column_width, 1.0], + [-separator_distance, -aux_column_width, 1.0], [-branch_thickness, -branch_thickness, 1.0], ] ) + _np.array([0.5, 0.5, 0.0]) @@ -340,33 +342,33 @@ def _closing_tile( [-r_center, 0.5, filling_height], [-0.5, aux_column_width, ctps_mid_height_top], [ - -seperator_distance, + -separator_distance, aux_column_width, ctps_mid_height_top, ], [-branch_thickness, branch_thickness, ctps_mid_height_top], - [-0.5, seperator_distance, ctps_mid_height_top], + [-0.5, separator_distance, ctps_mid_height_top], [ - -seperator_distance, - seperator_distance, + -separator_distance, + separator_distance, ctps_mid_height_top, ], [ -aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_top, ], [-0.5, 0.5, ctps_mid_height_top], - [-seperator_distance, 0.5, ctps_mid_height_top], + [-separator_distance, 0.5, ctps_mid_height_top], [-aux_column_width, 0.5, ctps_mid_height_top], [-0.5, aux_column_width, 1.0], - [-seperator_distance, aux_column_width, 1.0], + [-separator_distance, aux_column_width, 1.0], [-branch_thickness, branch_thickness, 1.0], - [-0.5, seperator_distance, 1.0], - [-seperator_distance, seperator_distance, 1.0], - [-aux_column_width, seperator_distance, 1.0], + [-0.5, separator_distance, 1.0], + [-separator_distance, separator_distance, 1.0], + [-aux_column_width, separator_distance, 1.0], [-0.5, 0.5, 1.0], - [-seperator_distance, 0.5, 1.0], + [-separator_distance, 0.5, 1.0], [-aux_column_width, 0.5, 1.0], ] ) + _np.array([0.5, 0.5, 0.0]) @@ -389,34 +391,34 @@ def _closing_tile( [half_r_center, -r_center, filling_height], [0.5, -r_center, filling_height], [aux_column_width, -0.5, ctps_mid_height_top], - [seperator_distance, -0.5, ctps_mid_height_top], + [separator_distance, -0.5, ctps_mid_height_top], [0.5, -0.5, ctps_mid_height_top], [ aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_top, ], [ - seperator_distance, - -seperator_distance, + separator_distance, + -separator_distance, ctps_mid_height_top, ], - [0.5, -seperator_distance, ctps_mid_height_top], + [0.5, -separator_distance, ctps_mid_height_top], [branch_thickness, -branch_thickness, ctps_mid_height_top], [ - seperator_distance, + separator_distance, -aux_column_width, ctps_mid_height_top, ], [0.5, -aux_column_width, ctps_mid_height_top], [aux_column_width, -0.5, 1.0], - [seperator_distance, -0.5, 1.0], + [separator_distance, -0.5, 1.0], [0.5, -0.5, 1.0], - [aux_column_width, -seperator_distance, 1.0], - [seperator_distance, -seperator_distance, 1.0], - [0.5, -seperator_distance, 1.0], + [aux_column_width, -separator_distance, 1.0], + [separator_distance, -separator_distance, 1.0], + [0.5, -separator_distance, 1.0], [branch_thickness, -branch_thickness, 1.0], - [seperator_distance, -aux_column_width, 1.0], + [separator_distance, -aux_column_width, 1.0], [0.5, -aux_column_width, 1.0], ] ) + _np.array([0.5, 0.5, 0.0]) @@ -440,33 +442,33 @@ def _closing_tile( [0.5, 0.5, filling_height], [branch_thickness, branch_thickness, ctps_mid_height_top], [ - seperator_distance, + separator_distance, aux_column_width, ctps_mid_height_top, ], [0.5, aux_column_width, ctps_mid_height_top], [ aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_top, ], [ - seperator_distance, - seperator_distance, + separator_distance, + separator_distance, ctps_mid_height_top, ], - [0.5, seperator_distance, ctps_mid_height_top], + [0.5, separator_distance, ctps_mid_height_top], [aux_column_width, 0.5, ctps_mid_height_top], - [seperator_distance, 0.5, ctps_mid_height_top], + [separator_distance, 0.5, ctps_mid_height_top], [0.5, 0.5, ctps_mid_height_top], [branch_thickness, branch_thickness, 1.0], - [seperator_distance, aux_column_width, 1.0], + [separator_distance, aux_column_width, 1.0], [0.5, aux_column_width, 1.0], - [aux_column_width, seperator_distance, 1.0], - [seperator_distance, seperator_distance, 1.0], - [0.5, seperator_distance, 1.0], + [aux_column_width, separator_distance, 1.0], + [separator_distance, separator_distance, 1.0], + [0.5, separator_distance, 1.0], [aux_column_width, 0.5, 1.0], - [seperator_distance, 0.5, 1.0], + [separator_distance, 0.5, 1.0], [0.5, 0.5, 1.0], ] ) + _np.array([0.5, 0.5, 0.0]) @@ -484,14 +486,14 @@ def _closing_tile( branch_neighbor_x_min_ctps = _np.array( [ [-0.5, -aux_column_width, 0.0], - [-seperator_distance, -aux_column_width, 0.0], + [-separator_distance, -aux_column_width, 0.0], [-branch_thickness, -branch_thickness, 0.0], [-0.5, aux_column_width, 0.0], - [-seperator_distance, aux_column_width, 0.0], + [-separator_distance, aux_column_width, 0.0], [-branch_thickness, branch_thickness, 0.0], [-0.5, -aux_column_width, ctps_mid_height_bottom], [ - -seperator_distance, + -separator_distance, -aux_column_width, ctps_mid_height_bottom, ], @@ -502,7 +504,7 @@ def _closing_tile( ], [-0.5, aux_column_width, ctps_mid_height_bottom], [ - -seperator_distance, + -separator_distance, aux_column_width, ctps_mid_height_bottom, ], @@ -530,10 +532,10 @@ def _closing_tile( branch_neighbor_x_max_ctps = _np.array( [ [branch_thickness, -branch_thickness, 0.0], - [seperator_distance, -aux_column_width, 0.0], + [separator_distance, -aux_column_width, 0.0], [0.5, -aux_column_width, 0.0], [branch_thickness, branch_thickness, 0.0], - [seperator_distance, aux_column_width, 0.0], + [separator_distance, aux_column_width, 0.0], [0.5, aux_column_width, 0.0], [ branch_thickness, @@ -541,7 +543,7 @@ def _closing_tile( ctps_mid_height_bottom, ], [ - seperator_distance, + separator_distance, -aux_column_width, ctps_mid_height_bottom, ], @@ -552,7 +554,7 @@ def _closing_tile( ctps_mid_height_bottom, ], [ - seperator_distance, + separator_distance, aux_column_width, ctps_mid_height_bottom, ], @@ -577,20 +579,20 @@ def _closing_tile( [ [-aux_column_width, -0.5, 0.0], [aux_column_width, -0.5, 0.0], - [-aux_column_width, -seperator_distance, 0.0], - [aux_column_width, -seperator_distance, 0.0], + [-aux_column_width, -separator_distance, 0.0], + [aux_column_width, -separator_distance, 0.0], [-branch_thickness, -branch_thickness, 0.0], [branch_thickness, -branch_thickness, 0.0], [-aux_column_width, -0.5, ctps_mid_height_bottom], [aux_column_width, -0.5, ctps_mid_height_bottom], [ -aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_bottom, ], [ aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_bottom, ], [ @@ -623,8 +625,8 @@ def _closing_tile( [ [-branch_thickness, branch_thickness, 0.0], [branch_thickness, branch_thickness, 0.0], - [-aux_column_width, seperator_distance, 0.0], - [aux_column_width, seperator_distance, 0.0], + [-aux_column_width, separator_distance, 0.0], + [aux_column_width, separator_distance, 0.0], [-aux_column_width, 0.5, 0.0], [aux_column_width, 0.5, 0.0], [ @@ -639,12 +641,12 @@ def _closing_tile( ], [ -aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_bottom, ], [ aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_bottom, ], [-aux_column_width, 0.5, ctps_mid_height_bottom], @@ -668,31 +670,31 @@ def _closing_tile( branch_x_min_y_min_ctps = _np.array( [ [-0.5, -0.5, 0.0], - [-seperator_distance, -0.5, 0.0], + [-separator_distance, -0.5, 0.0], [-aux_column_width, -0.5, 0.0], - [-0.5, -seperator_distance, 0.0], - [-seperator_distance, -seperator_distance, 0.0], - [-aux_column_width, -seperator_distance, 0.0], + [-0.5, -separator_distance, 0.0], + [-separator_distance, -separator_distance, 0.0], + [-aux_column_width, -separator_distance, 0.0], [-0.5, -aux_column_width, 0.0], - [-seperator_distance, -aux_column_width, 0.0], + [-separator_distance, -aux_column_width, 0.0], [-branch_thickness, -branch_thickness, 0.0], [-0.5, -0.5, ctps_mid_height_bottom], - [-seperator_distance, -0.5, ctps_mid_height_bottom], + [-separator_distance, -0.5, ctps_mid_height_bottom], [-aux_column_width, -0.5, ctps_mid_height_bottom], - [-0.5, -seperator_distance, ctps_mid_height_bottom], + [-0.5, -separator_distance, ctps_mid_height_bottom], [ - -seperator_distance, - -seperator_distance, + -separator_distance, + -separator_distance, ctps_mid_height_bottom, ], [ -aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_bottom, ], [-0.5, -aux_column_width, ctps_mid_height_bottom], [ - -seperator_distance, + -separator_distance, -aux_column_width, ctps_mid_height_bottom, ], @@ -722,13 +724,13 @@ def _closing_tile( branch_x_max_y_max_ctps = _np.array( [ [branch_thickness, branch_thickness, 0.0], - [seperator_distance, aux_column_width, 0.0], + [separator_distance, aux_column_width, 0.0], [0.5, aux_column_width, 0.0], - [aux_column_width, seperator_distance, 0.0], - [seperator_distance, seperator_distance, 0.0], - [0.5, seperator_distance, 0.0], + [aux_column_width, separator_distance, 0.0], + [separator_distance, separator_distance, 0.0], + [0.5, separator_distance, 0.0], [aux_column_width, 0.5, 0.0], - [seperator_distance, 0.5, 0.0], + [separator_distance, 0.5, 0.0], [0.5, 0.5, 0.0], [ branch_thickness, @@ -736,24 +738,24 @@ def _closing_tile( ctps_mid_height_bottom, ], [ - seperator_distance, + separator_distance, aux_column_width, ctps_mid_height_bottom, ], [0.5, aux_column_width, ctps_mid_height_bottom], [ aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_bottom, ], [ - seperator_distance, - seperator_distance, + separator_distance, + separator_distance, ctps_mid_height_bottom, ], - [0.5, seperator_distance, ctps_mid_height_bottom], + [0.5, separator_distance, ctps_mid_height_bottom], [aux_column_width, 0.5, ctps_mid_height_bottom], - [seperator_distance, 0.5, ctps_mid_height_bottom], + [separator_distance, 0.5, ctps_mid_height_bottom], [0.5, 0.5, ctps_mid_height_bottom], [r_center, r_center, inv_filling_height], [half_r_center, r_center, inv_filling_height], @@ -776,35 +778,35 @@ def _closing_tile( branch_x_max_y_min_ctps = _np.array( [ [aux_column_width, -0.5, 0.0], - [seperator_distance, -0.5, 0.0], + [separator_distance, -0.5, 0.0], [0.5, -0.5, 0.0], - [aux_column_width, -seperator_distance, 0.0], - [seperator_distance, -seperator_distance, 0.0], - [0.5, -seperator_distance, 0.0], + [aux_column_width, -separator_distance, 0.0], + [separator_distance, -separator_distance, 0.0], + [0.5, -separator_distance, 0.0], [branch_thickness, -branch_thickness, 0.0], - [seperator_distance, -aux_column_width, 0.0], + [separator_distance, -aux_column_width, 0.0], [0.5, -aux_column_width, 0.0], [aux_column_width, -0.5, ctps_mid_height_bottom], - [seperator_distance, -0.5, ctps_mid_height_bottom], + [separator_distance, -0.5, ctps_mid_height_bottom], [0.5, -0.5, ctps_mid_height_bottom], [ aux_column_width, - -seperator_distance, + -separator_distance, ctps_mid_height_bottom, ], [ - seperator_distance, - -seperator_distance, + separator_distance, + -separator_distance, ctps_mid_height_bottom, ], - [0.5, -seperator_distance, ctps_mid_height_bottom], + [0.5, -separator_distance, ctps_mid_height_bottom], [ branch_thickness, -branch_thickness, ctps_mid_height_bottom, ], [ - seperator_distance, + separator_distance, -aux_column_width, ctps_mid_height_bottom, ], @@ -830,17 +832,17 @@ def _closing_tile( branch_x_min_y_max_ctps = _np.array( [ [-0.5, aux_column_width, 0.0], - [-seperator_distance, aux_column_width, 0.0], + [-separator_distance, aux_column_width, 0.0], [-branch_thickness, branch_thickness, 0.0], - [-0.5, seperator_distance, 0.0], - [-seperator_distance, seperator_distance, 0.0], - [-aux_column_width, seperator_distance, 0.0], + [-0.5, separator_distance, 0.0], + [-separator_distance, separator_distance, 0.0], + [-aux_column_width, separator_distance, 0.0], [-0.5, 0.5, 0.0], - [-seperator_distance, 0.5, 0.0], + [-separator_distance, 0.5, 0.0], [-aux_column_width, 0.5, 0.0], [-0.5, aux_column_width, ctps_mid_height_bottom], [ - -seperator_distance, + -separator_distance, aux_column_width, ctps_mid_height_bottom, ], @@ -849,19 +851,19 @@ def _closing_tile( branch_thickness, ctps_mid_height_bottom, ], - [-0.5, seperator_distance, ctps_mid_height_bottom], + [-0.5, separator_distance, ctps_mid_height_bottom], [ - -seperator_distance, - seperator_distance, + -separator_distance, + separator_distance, ctps_mid_height_bottom, ], [ -aux_column_width, - seperator_distance, + separator_distance, ctps_mid_height_bottom, ], [-0.5, 0.5, ctps_mid_height_bottom], - [-seperator_distance, 0.5, ctps_mid_height_bottom], + [-separator_distance, 0.5, ctps_mid_height_bottom], [-aux_column_width, 0.5, ctps_mid_height_bottom], [-0.5, r_center, inv_filling_height], [-half_r_center, r_center, inv_filling_height], @@ -889,7 +891,7 @@ def create_tile( self, parameters=None, parameter_sensitivities=None, - seperator_distance=None, + separator_distance=None, center_expansion=1.0, closure=None, **kwargs, # noqa ARG002 @@ -905,7 +907,7 @@ def create_tile( parameters : np.array only first entry is used, defines the internal radii of the branches - seperator_distance : float + separator_distance : float Control point distance to separation layer of biquadratic degrees, determines the minimum branch thickness (defaults to 0.4) center_expansion : float @@ -927,16 +929,16 @@ def create_tile( raise ValueError("Center Expansion must be in (.5, 1.5)") # Set default values - if seperator_distance is None: - seperator_distance = 0.3 + if separator_distance is None: + separator_distance = 0.3 if center_expansion is None: center_expansion = 1.0 # Check if all radii are in allowed range max_radius = min(0.5, (0.5 / center_expansion)) - max_radius = min(max_radius, seperator_distance) - min_radius = max(0.5 - seperator_distance, 0) + max_radius = min(max_radius, separator_distance) + min_radius = max(0.5 - separator_distance, 0) # set to default if nothing is given if parameters is None: @@ -967,7 +969,7 @@ def create_tile( return self._closing_tile( parameters=parameters, parameter_sensitivities=parameter_sensitivities, - seperator_distance=seperator_distance, + separator_distance=separator_distance, closure=closure, **kwargs, ) @@ -995,7 +997,7 @@ def create_tile( ] = _np.minimum(parameters.ravel(), center_r) # Branch midlength hd_center = 0.5 * (0.5 + center_r) - aux_column_width = 0.5 - 2 * (0.5 - seperator_distance) + aux_column_width = 0.5 - 2 * (0.5 - separator_distance) # Init return type spline_list = [] @@ -1004,18 +1006,18 @@ def create_tile( x_min_y_min = _np.array( [ [-0.5, -0.5, -aux_column_width], - [-seperator_distance, -0.5, -aux_column_width], + [-separator_distance, -0.5, -aux_column_width], [-y_min_r, -0.5, -y_min_r], - [-0.5, -seperator_distance, -aux_column_width], + [-0.5, -separator_distance, -aux_column_width], [-hd_center, -hd_center, -aux_column_width], [-aux_y_min, -hd_center, -aux_y_min], [-0.5, -x_min_r, -x_min_r], [-hd_center, -aux_x_min, -aux_x_min], [-center_r, -center_r, -center_r], [-0.5, -0.5, aux_column_width], - [-seperator_distance, -0.5, aux_column_width], + [-separator_distance, -0.5, aux_column_width], [-y_min_r, -0.5, y_min_r], - [-0.5, -seperator_distance, aux_column_width], + [-0.5, -separator_distance, aux_column_width], [-hd_center, -hd_center, aux_column_width], [-aux_y_min, -hd_center, aux_y_min], [-0.5, -x_min_r, x_min_r], @@ -1031,20 +1033,20 @@ def create_tile( x_max_y_min = _np.array( [ [y_min_r, -0.5, -y_min_r], - [seperator_distance, -0.5, -aux_column_width], + [separator_distance, -0.5, -aux_column_width], [0.5, -0.5, -aux_column_width], [aux_y_min, -hd_center, -aux_y_min], [hd_center, -hd_center, -aux_column_width], - [0.5, -seperator_distance, -aux_column_width], + [0.5, -separator_distance, -aux_column_width], [center_r, -center_r, -center_r], [hd_center, -aux_x_max, -aux_x_max], [0.5, -x_max_r, -x_max_r], [y_min_r, -0.5, y_min_r], - [seperator_distance, -0.5, aux_column_width], + [separator_distance, -0.5, aux_column_width], [0.5, -0.5, aux_column_width], [aux_y_min, -hd_center, aux_y_min], [hd_center, -hd_center, aux_column_width], - [0.5, -seperator_distance, aux_column_width], + [0.5, -separator_distance, aux_column_width], [center_r, -center_r, center_r], [hd_center, -aux_x_max, aux_x_max], [0.5, -x_max_r, x_max_r], @@ -1060,20 +1062,20 @@ def create_tile( [-0.5, x_min_r, -x_min_r], [-hd_center, aux_x_min, -aux_x_min], [-center_r, center_r, -center_r], - [-0.5, seperator_distance, -aux_column_width], + [-0.5, separator_distance, -aux_column_width], [-hd_center, hd_center, -aux_column_width], [-aux_y_max, hd_center, -aux_y_max], [-0.5, 0.5, -aux_column_width], - [-seperator_distance, 0.5, -aux_column_width], + [-separator_distance, 0.5, -aux_column_width], [-y_max_r, 0.5, -y_max_r], [-0.5, x_min_r, x_min_r], [-hd_center, aux_x_min, aux_x_min], [-center_r, center_r, center_r], - [-0.5, seperator_distance, aux_column_width], + [-0.5, separator_distance, aux_column_width], [-hd_center, hd_center, aux_column_width], [-aux_y_max, hd_center, aux_y_max], [-0.5, 0.5, aux_column_width], - [-seperator_distance, 0.5, aux_column_width], + [-separator_distance, 0.5, aux_column_width], [-y_max_r, 0.5, y_max_r], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1089,18 +1091,18 @@ def create_tile( [0.5, x_max_r, -x_max_r], [aux_y_max, hd_center, -aux_y_max], [hd_center, hd_center, -aux_column_width], - [0.5, seperator_distance, -aux_column_width], + [0.5, separator_distance, -aux_column_width], [y_max_r, 0.5, -y_max_r], - [seperator_distance, 0.5, -aux_column_width], + [separator_distance, 0.5, -aux_column_width], [0.5, 0.5, -aux_column_width], [center_r, center_r, center_r], [hd_center, aux_x_max, aux_x_max], [0.5, x_max_r, x_max_r], [aux_y_max, hd_center, aux_y_max], [hd_center, hd_center, aux_column_width], - [0.5, seperator_distance, aux_column_width], + [0.5, separator_distance, aux_column_width], [y_max_r, 0.5, y_max_r], - [seperator_distance, 0.5, aux_column_width], + [separator_distance, 0.5, aux_column_width], [0.5, 0.5, aux_column_width], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1112,15 +1114,15 @@ def create_tile( x_min_z_min = _np.array( [ [-0.5, -aux_column_width, -0.5], - [-seperator_distance, -aux_column_width, -0.5], + [-separator_distance, -aux_column_width, -0.5], [-z_min_r, -z_min_r, -0.5], [-0.5, aux_column_width, -0.5], - [-seperator_distance, aux_column_width, -0.5], + [-separator_distance, aux_column_width, -0.5], [-z_min_r, z_min_r, -0.5], - [-0.5, -aux_column_width, -seperator_distance], + [-0.5, -aux_column_width, -separator_distance], [-hd_center, -aux_column_width, -hd_center], [-aux_z_min, -aux_z_min, -hd_center], - [-0.5, aux_column_width, -seperator_distance], + [-0.5, aux_column_width, -separator_distance], [-hd_center, aux_column_width, -hd_center], [-aux_z_min, aux_z_min, -hd_center], [-0.5, -x_min_r, -x_min_r], @@ -1139,17 +1141,17 @@ def create_tile( x_max_z_min = _np.array( [ [z_min_r, -z_min_r, -0.5], - [seperator_distance, -aux_column_width, -0.5], + [separator_distance, -aux_column_width, -0.5], [0.5, -aux_column_width, -0.5], [z_min_r, z_min_r, -0.5], - [seperator_distance, aux_column_width, -0.5], + [separator_distance, aux_column_width, -0.5], [0.5, aux_column_width, -0.5], [aux_z_min, -aux_z_min, -hd_center], [hd_center, -aux_column_width, -hd_center], - [0.5, -aux_column_width, -seperator_distance], + [0.5, -aux_column_width, -separator_distance], [aux_z_min, aux_z_min, -hd_center], [hd_center, aux_column_width, -hd_center], - [0.5, aux_column_width, -seperator_distance], + [0.5, aux_column_width, -separator_distance], [center_r, -center_r, -center_r], [hd_center, -aux_x_max, -aux_x_max], [0.5, -x_max_r, -x_max_r], @@ -1171,17 +1173,17 @@ def create_tile( [-0.5, x_min_r, x_min_r], [-hd_center, aux_x_min, aux_x_min], [-center_r, center_r, center_r], - [-0.5, -aux_column_width, seperator_distance], + [-0.5, -aux_column_width, separator_distance], [-hd_center, -aux_column_width, hd_center], [-aux_z_max, -aux_z_max, hd_center], - [-0.5, aux_column_width, seperator_distance], + [-0.5, aux_column_width, separator_distance], [-hd_center, aux_column_width, hd_center], [-aux_z_max, aux_z_max, hd_center], [-0.5, -aux_column_width, 0.5], - [-seperator_distance, -aux_column_width, 0.5], + [-separator_distance, -aux_column_width, 0.5], [-z_max_r, -z_max_r, 0.5], [-0.5, aux_column_width, 0.5], - [-seperator_distance, aux_column_width, 0.5], + [-separator_distance, aux_column_width, 0.5], [-z_max_r, z_max_r, 0.5], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1200,15 +1202,15 @@ def create_tile( [0.5, x_max_r, x_max_r], [aux_z_max, -aux_z_max, hd_center], [hd_center, -aux_column_width, hd_center], - [0.5, -aux_column_width, seperator_distance], + [0.5, -aux_column_width, separator_distance], [aux_z_max, aux_z_max, hd_center], [hd_center, aux_column_width, hd_center], - [0.5, aux_column_width, seperator_distance], + [0.5, aux_column_width, separator_distance], [z_max_r, -z_max_r, 0.5], - [seperator_distance, -aux_column_width, 0.5], + [separator_distance, -aux_column_width, 0.5], [0.5, -aux_column_width, 0.5], [z_max_r, z_max_r, 0.5], - [seperator_distance, aux_column_width, 0.5], + [separator_distance, aux_column_width, 0.5], [0.5, aux_column_width, 0.5], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1221,12 +1223,12 @@ def create_tile( [ [-aux_column_width, -0.5, -0.5], [aux_column_width, -0.5, -0.5], - [-aux_column_width, -seperator_distance, -0.5], - [aux_column_width, -seperator_distance, -0.5], + [-aux_column_width, -separator_distance, -0.5], + [aux_column_width, -separator_distance, -0.5], [-z_min_r, -z_min_r, -0.5], [z_min_r, -z_min_r, -0.5], - [-aux_column_width, -0.5, -seperator_distance], - [aux_column_width, -0.5, -seperator_distance], + [-aux_column_width, -0.5, -separator_distance], + [aux_column_width, -0.5, -separator_distance], [-aux_column_width, -hd_center, -hd_center], [aux_column_width, -hd_center, -hd_center], [-aux_z_min, -aux_z_min, -hd_center], @@ -1248,16 +1250,16 @@ def create_tile( [ [-z_min_r, z_min_r, -0.5], [z_min_r, z_min_r, -0.5], - [-aux_column_width, seperator_distance, -0.5], - [aux_column_width, seperator_distance, -0.5], + [-aux_column_width, separator_distance, -0.5], + [aux_column_width, separator_distance, -0.5], [-aux_column_width, 0.5, -0.5], [aux_column_width, 0.5, -0.5], [-aux_z_min, aux_z_min, -hd_center], [aux_z_min, aux_z_min, -hd_center], [-aux_column_width, hd_center, -hd_center], [aux_column_width, hd_center, -hd_center], - [-aux_column_width, 0.5, -seperator_distance], - [aux_column_width, 0.5, -seperator_distance], + [-aux_column_width, 0.5, -separator_distance], + [aux_column_width, 0.5, -separator_distance], [-center_r, center_r, -center_r], [center_r, center_r, -center_r], [-aux_y_max, hd_center, -aux_y_max], @@ -1279,16 +1281,16 @@ def create_tile( [aux_y_min, -hd_center, aux_y_min], [-center_r, -center_r, center_r], [center_r, -center_r, center_r], - [-aux_column_width, -0.5, seperator_distance], - [aux_column_width, -0.5, seperator_distance], + [-aux_column_width, -0.5, separator_distance], + [aux_column_width, -0.5, separator_distance], [-aux_column_width, -hd_center, hd_center], [aux_column_width, -hd_center, hd_center], [-aux_z_max, -aux_z_max, hd_center], [aux_z_max, -aux_z_max, hd_center], [-aux_column_width, -0.5, 0.5], [aux_column_width, -0.5, 0.5], - [-aux_column_width, -seperator_distance, 0.5], - [aux_column_width, -seperator_distance, 0.5], + [-aux_column_width, -separator_distance, 0.5], + [aux_column_width, -separator_distance, 0.5], [-z_max_r, -z_max_r, 0.5], [z_max_r, -z_max_r, 0.5], ] @@ -1310,12 +1312,12 @@ def create_tile( [aux_z_max, aux_z_max, hd_center], [-aux_column_width, hd_center, hd_center], [aux_column_width, hd_center, hd_center], - [-aux_column_width, 0.5, seperator_distance], - [aux_column_width, 0.5, seperator_distance], + [-aux_column_width, 0.5, separator_distance], + [aux_column_width, 0.5, separator_distance], [-z_max_r, z_max_r, 0.5], [z_max_r, z_max_r, 0.5], - [-aux_column_width, seperator_distance, 0.5], - [aux_column_width, seperator_distance, 0.5], + [-aux_column_width, separator_distance, 0.5], + [aux_column_width, separator_distance, 0.5], [-aux_column_width, 0.5, 0.5], [aux_column_width, 0.5, 0.5], ] @@ -1328,27 +1330,27 @@ def create_tile( x_min_y_min_z_min = _np.array( [ [-0.5, -0.5, -0.5], - [-seperator_distance, -0.5, -0.5], + [-separator_distance, -0.5, -0.5], [-aux_column_width, -0.5, -0.5], - [-0.5, -seperator_distance, -0.5], - [-seperator_distance, -seperator_distance, -0.5], - [-aux_column_width, -seperator_distance, -0.5], + [-0.5, -separator_distance, -0.5], + [-separator_distance, -separator_distance, -0.5], + [-aux_column_width, -separator_distance, -0.5], [-0.5, -aux_column_width, -0.5], - [-seperator_distance, -aux_column_width, -0.5], + [-separator_distance, -aux_column_width, -0.5], [-z_min_r, -z_min_r, -0.5], - [-0.5, -0.5, -seperator_distance], - [-seperator_distance, -0.5, -seperator_distance], - [-aux_column_width, -0.5, -seperator_distance], - [-0.5, -seperator_distance, -seperator_distance], + [-0.5, -0.5, -separator_distance], + [-separator_distance, -0.5, -separator_distance], + [-aux_column_width, -0.5, -separator_distance], + [-0.5, -separator_distance, -separator_distance], [-hd_center, -hd_center, -hd_center], [-aux_column_width, -hd_center, -hd_center], - [-0.5, -aux_column_width, -seperator_distance], + [-0.5, -aux_column_width, -separator_distance], [-hd_center, -aux_column_width, -hd_center], [-aux_z_min, -aux_z_min, -hd_center], [-0.5, -0.5, -aux_column_width], - [-seperator_distance, -0.5, -aux_column_width], + [-separator_distance, -0.5, -aux_column_width], [-y_min_r, -0.5, -y_min_r], - [-0.5, -seperator_distance, -aux_column_width], + [-0.5, -separator_distance, -aux_column_width], [-hd_center, -hd_center, -aux_column_width], [-aux_y_min, -hd_center, -aux_y_min], [-0.5, -x_min_r, -x_min_r], @@ -1364,29 +1366,29 @@ def create_tile( x_max_y_min_z_min = _np.array( [ [aux_column_width, -0.5, -0.5], - [seperator_distance, -0.5, -0.5], + [separator_distance, -0.5, -0.5], [0.5, -0.5, -0.5], - [aux_column_width, -seperator_distance, -0.5], - [seperator_distance, -seperator_distance, -0.5], - [0.5, -seperator_distance, -0.5], + [aux_column_width, -separator_distance, -0.5], + [separator_distance, -separator_distance, -0.5], + [0.5, -separator_distance, -0.5], [z_min_r, -z_min_r, -0.5], - [seperator_distance, -aux_column_width, -0.5], + [separator_distance, -aux_column_width, -0.5], [0.5, -aux_column_width, -0.5], - [aux_column_width, -0.5, -seperator_distance], - [seperator_distance, -0.5, -seperator_distance], - [0.5, -0.5, -seperator_distance], + [aux_column_width, -0.5, -separator_distance], + [separator_distance, -0.5, -separator_distance], + [0.5, -0.5, -separator_distance], [aux_column_width, -hd_center, -hd_center], [hd_center, -hd_center, -hd_center], - [0.5, -seperator_distance, -seperator_distance], + [0.5, -separator_distance, -separator_distance], [aux_z_min, -aux_z_min, -hd_center], [hd_center, -aux_column_width, -hd_center], - [0.5, -aux_column_width, -seperator_distance], + [0.5, -aux_column_width, -separator_distance], [y_min_r, -0.5, -y_min_r], - [seperator_distance, -0.5, -aux_column_width], + [separator_distance, -0.5, -aux_column_width], [0.5, -0.5, -aux_column_width], [aux_y_min, -hd_center, -aux_y_min], [hd_center, -hd_center, -aux_column_width], - [0.5, -seperator_distance, -aux_column_width], + [0.5, -separator_distance, -aux_column_width], [center_r, -center_r, -center_r], [hd_center, -aux_x_max, -aux_x_max], [0.5, -x_max_r, -x_max_r], @@ -1400,31 +1402,31 @@ def create_tile( x_min_y_max_z_min = _np.array( [ [-0.5, aux_column_width, -0.5], - [-seperator_distance, aux_column_width, -0.5], + [-separator_distance, aux_column_width, -0.5], [-z_min_r, z_min_r, -0.5], - [-0.5, seperator_distance, -0.5], - [-seperator_distance, seperator_distance, -0.5], - [-aux_column_width, seperator_distance, -0.5], + [-0.5, separator_distance, -0.5], + [-separator_distance, separator_distance, -0.5], + [-aux_column_width, separator_distance, -0.5], [-0.5, 0.5, -0.5], - [-seperator_distance, 0.5, -0.5], + [-separator_distance, 0.5, -0.5], [-aux_column_width, 0.5, -0.5], - [-0.5, aux_column_width, -seperator_distance], + [-0.5, aux_column_width, -separator_distance], [-hd_center, aux_column_width, -hd_center], [-aux_z_min, aux_z_min, -hd_center], - [-0.5, seperator_distance, -seperator_distance], + [-0.5, separator_distance, -separator_distance], [-hd_center, hd_center, -hd_center], [-aux_column_width, hd_center, -hd_center], - [-0.5, 0.5, -seperator_distance], - [-seperator_distance, 0.5, -seperator_distance], - [-aux_column_width, 0.5, -seperator_distance], + [-0.5, 0.5, -separator_distance], + [-separator_distance, 0.5, -separator_distance], + [-aux_column_width, 0.5, -separator_distance], [-0.5, x_min_r, -x_min_r], [-hd_center, aux_x_min, -aux_x_min], [-center_r, center_r, -center_r], - [-0.5, seperator_distance, -aux_column_width], + [-0.5, separator_distance, -aux_column_width], [-hd_center, hd_center, -aux_column_width], [-aux_y_max, hd_center, -aux_y_max], [-0.5, 0.5, -aux_column_width], - [-seperator_distance, 0.5, -aux_column_width], + [-separator_distance, 0.5, -aux_column_width], [-y_max_r, 0.5, -y_max_r], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1436,31 +1438,31 @@ def create_tile( x_max_y_max_z_min = _np.array( [ [z_min_r, z_min_r, -0.5], - [seperator_distance, aux_column_width, -0.5], + [separator_distance, aux_column_width, -0.5], [0.5, aux_column_width, -0.5], - [aux_column_width, seperator_distance, -0.5], - [seperator_distance, seperator_distance, -0.5], - [0.5, seperator_distance, -0.5], + [aux_column_width, separator_distance, -0.5], + [separator_distance, separator_distance, -0.5], + [0.5, separator_distance, -0.5], [aux_column_width, 0.5, -0.5], - [seperator_distance, 0.5, -0.5], + [separator_distance, 0.5, -0.5], [0.5, 0.5, -0.5], [aux_z_min, aux_z_min, -hd_center], [hd_center, aux_column_width, -hd_center], - [0.5, aux_column_width, -seperator_distance], + [0.5, aux_column_width, -separator_distance], [aux_column_width, hd_center, -hd_center], [hd_center, hd_center, -hd_center], - [0.5, seperator_distance, -seperator_distance], - [aux_column_width, 0.5, -seperator_distance], - [seperator_distance, 0.5, -seperator_distance], - [0.5, 0.5, -seperator_distance], + [0.5, separator_distance, -separator_distance], + [aux_column_width, 0.5, -separator_distance], + [separator_distance, 0.5, -separator_distance], + [0.5, 0.5, -separator_distance], [center_r, center_r, -center_r], [hd_center, aux_x_max, -aux_x_max], [0.5, x_max_r, -x_max_r], [aux_y_max, hd_center, -aux_y_max], [hd_center, hd_center, -aux_column_width], - [0.5, seperator_distance, -aux_column_width], + [0.5, separator_distance, -aux_column_width], [y_max_r, 0.5, -y_max_r], - [seperator_distance, 0.5, -aux_column_width], + [separator_distance, 0.5, -aux_column_width], [0.5, 0.5, -aux_column_width], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1472,31 +1474,31 @@ def create_tile( x_min_y_min_z_max = _np.array( [ [-0.5, -0.5, aux_column_width], - [-seperator_distance, -0.5, aux_column_width], + [-separator_distance, -0.5, aux_column_width], [-y_min_r, -0.5, y_min_r], - [-0.5, -seperator_distance, aux_column_width], + [-0.5, -separator_distance, aux_column_width], [-hd_center, -hd_center, aux_column_width], [-aux_y_min, -hd_center, aux_y_min], [-0.5, -x_min_r, x_min_r], [-hd_center, -aux_x_min, aux_x_min], [-center_r, -center_r, center_r], - [-0.5, -0.5, seperator_distance], - [-seperator_distance, -0.5, seperator_distance], - [-aux_column_width, -0.5, seperator_distance], - [-0.5, -seperator_distance, seperator_distance], + [-0.5, -0.5, separator_distance], + [-separator_distance, -0.5, separator_distance], + [-aux_column_width, -0.5, separator_distance], + [-0.5, -separator_distance, separator_distance], [-hd_center, -hd_center, hd_center], [-aux_column_width, -hd_center, hd_center], - [-0.5, -aux_column_width, seperator_distance], + [-0.5, -aux_column_width, separator_distance], [-hd_center, -aux_column_width, hd_center], [-aux_z_max, -aux_z_max, hd_center], [-0.5, -0.5, 0.5], - [-seperator_distance, -0.5, 0.5], + [-separator_distance, -0.5, 0.5], [-aux_column_width, -0.5, 0.5], - [-0.5, -seperator_distance, 0.5], - [-seperator_distance, -seperator_distance, 0.5], - [-aux_column_width, -seperator_distance, 0.5], + [-0.5, -separator_distance, 0.5], + [-separator_distance, -separator_distance, 0.5], + [-aux_column_width, -separator_distance, 0.5], [-0.5, -aux_column_width, 0.5], - [-seperator_distance, -aux_column_width, 0.5], + [-separator_distance, -aux_column_width, 0.5], [-z_max_r, -z_max_r, 0.5], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1508,31 +1510,31 @@ def create_tile( x_max_y_min_z_max = _np.array( [ [y_min_r, -0.5, y_min_r], - [seperator_distance, -0.5, aux_column_width], + [separator_distance, -0.5, aux_column_width], [0.5, -0.5, aux_column_width], [aux_y_min, -hd_center, aux_y_min], [hd_center, -hd_center, aux_column_width], - [0.5, -seperator_distance, aux_column_width], + [0.5, -separator_distance, aux_column_width], [center_r, -center_r, center_r], [hd_center, -aux_x_max, aux_x_max], [0.5, -x_max_r, x_max_r], - [aux_column_width, -0.5, seperator_distance], - [seperator_distance, -0.5, seperator_distance], - [0.5, -0.5, seperator_distance], + [aux_column_width, -0.5, separator_distance], + [separator_distance, -0.5, separator_distance], + [0.5, -0.5, separator_distance], [aux_column_width, -hd_center, hd_center], [hd_center, -hd_center, hd_center], - [0.5, -seperator_distance, seperator_distance], + [0.5, -separator_distance, separator_distance], [aux_z_max, -aux_z_max, hd_center], [hd_center, -aux_column_width, hd_center], - [0.5, -aux_column_width, seperator_distance], + [0.5, -aux_column_width, separator_distance], [aux_column_width, -0.5, 0.5], - [seperator_distance, -0.5, 0.5], + [separator_distance, -0.5, 0.5], [0.5, -0.5, 0.5], - [aux_column_width, -seperator_distance, 0.5], - [seperator_distance, -seperator_distance, 0.5], - [0.5, -seperator_distance, 0.5], + [aux_column_width, -separator_distance, 0.5], + [separator_distance, -separator_distance, 0.5], + [0.5, -separator_distance, 0.5], [z_max_r, -z_max_r, 0.5], - [seperator_distance, -aux_column_width, 0.5], + [separator_distance, -aux_column_width, 0.5], [0.5, -aux_column_width, 0.5], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1546,29 +1548,29 @@ def create_tile( [-0.5, x_min_r, x_min_r], [-hd_center, aux_x_min, aux_x_min], [-center_r, center_r, center_r], - [-0.5, seperator_distance, aux_column_width], + [-0.5, separator_distance, aux_column_width], [-hd_center, hd_center, aux_column_width], [-aux_y_max, hd_center, aux_y_max], [-0.5, 0.5, aux_column_width], - [-seperator_distance, 0.5, aux_column_width], + [-separator_distance, 0.5, aux_column_width], [-y_max_r, 0.5, y_max_r], - [-0.5, aux_column_width, seperator_distance], + [-0.5, aux_column_width, separator_distance], [-hd_center, aux_column_width, hd_center], [-aux_z_max, aux_z_max, hd_center], - [-0.5, seperator_distance, seperator_distance], + [-0.5, separator_distance, separator_distance], [-hd_center, hd_center, hd_center], [-aux_column_width, hd_center, hd_center], - [-0.5, 0.5, seperator_distance], - [-seperator_distance, 0.5, seperator_distance], - [-aux_column_width, 0.5, seperator_distance], + [-0.5, 0.5, separator_distance], + [-separator_distance, 0.5, separator_distance], + [-aux_column_width, 0.5, separator_distance], [-0.5, aux_column_width, 0.5], - [-seperator_distance, aux_column_width, 0.5], + [-separator_distance, aux_column_width, 0.5], [-z_max_r, z_max_r, 0.5], - [-0.5, seperator_distance, 0.5], - [-seperator_distance, seperator_distance, 0.5], - [-aux_column_width, seperator_distance, 0.5], + [-0.5, separator_distance, 0.5], + [-separator_distance, separator_distance, 0.5], + [-aux_column_width, separator_distance, 0.5], [-0.5, 0.5, 0.5], - [-seperator_distance, 0.5, 0.5], + [-separator_distance, 0.5, 0.5], [-aux_column_width, 0.5, 0.5], ] ) + _np.array([0.5, 0.5, 0.5]) @@ -1584,27 +1586,27 @@ def create_tile( [0.5, x_max_r, x_max_r], [aux_y_max, hd_center, aux_y_max], [hd_center, hd_center, aux_column_width], - [0.5, seperator_distance, aux_column_width], + [0.5, separator_distance, aux_column_width], [y_max_r, 0.5, y_max_r], - [seperator_distance, 0.5, aux_column_width], + [separator_distance, 0.5, aux_column_width], [0.5, 0.5, aux_column_width], [aux_z_max, aux_z_max, hd_center], [hd_center, aux_column_width, hd_center], - [0.5, aux_column_width, seperator_distance], + [0.5, aux_column_width, separator_distance], [aux_column_width, hd_center, hd_center], [hd_center, hd_center, hd_center], - [0.5, seperator_distance, seperator_distance], - [aux_column_width, 0.5, seperator_distance], - [seperator_distance, 0.5, seperator_distance], - [0.5, 0.5, seperator_distance], + [0.5, separator_distance, separator_distance], + [aux_column_width, 0.5, separator_distance], + [separator_distance, 0.5, separator_distance], + [0.5, 0.5, separator_distance], [z_max_r, z_max_r, 0.5], - [seperator_distance, aux_column_width, 0.5], + [separator_distance, aux_column_width, 0.5], [0.5, aux_column_width, 0.5], - [aux_column_width, seperator_distance, 0.5], - [seperator_distance, seperator_distance, 0.5], - [0.5, seperator_distance, 0.5], + [aux_column_width, separator_distance, 0.5], + [separator_distance, separator_distance, 0.5], + [0.5, separator_distance, 0.5], [aux_column_width, 0.5, 0.5], - [seperator_distance, 0.5, 0.5], + [separator_distance, 0.5, 0.5], [0.5, 0.5, 0.5], ] ) + _np.array([0.5, 0.5, 0.5]) diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index dac00bd20..7df89d6e8 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -20,6 +20,8 @@ class Snappy(_TileBase): # dummy values - not used _evaluation_points = _np.array([[0.5, 0.5]]) _n_info_per_eval_point = 1 + _sensitivities_implemented = False + _closure_directions = ["y_min", "y_max"] def _closing_tile( self, @@ -362,7 +364,7 @@ def create_tile( if parameters is not None: raise NotImplementedError( - "Parametriazation is not implemented for this tile yet" + "Parametrization is not implemented for this tile yet" ) if parameter_sensitivities is not None: diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py new file mode 100644 index 000000000..cfb59555e --- /dev/null +++ b/tests/test_microstructure.py @@ -0,0 +1,75 @@ +from inspect import getfullargspec + +import numpy as np + +import splinepy.microstructure as ms + +EPS = 1e-8 + +all_tile_classes = list(ms.tiles.everything().values()) + + +def test_tile_class(): + """Checks if all tile classes have the appropriate members and functions.""" + required_class_variables = { + "_para_dim": int, + "_dim": int, + "_evaluation_points": np.ndarray, + "_n_info_per_eval_point": int, + # "_sensitivities_implemented": bool + } + + # Go through all available tiles + for tile_class in all_tile_classes: + # Get tile class' objects + members = [ + attr for attr in dir(tile_class) if not attr.startswith("__") + ] + + # Class must have function create_tile() + assert hasattr( + tile_class, "create_tile" + ), "Tile class must have create_tile()" + # Tile must be able to take parameters and sensitivities as input + create_parameters = getfullargspec(tile_class.create_tile).args + for required_param in ["parameters", "parameter_sensitivities"]: + assert ( + required_param in create_parameters + ), f"create_tile() must have '{required_param}' as an input parameter" + + # Ensure closure can be correctly handled + if "closure" in create_parameters: + assert "_closure_directions" in members, ( + "Tile class has closure ability. The available closure directions " + + "are missing" + ) + assert hasattr( + tile_class, "_closing_tile" + ), "Tile class has closure ability but no _closing_tile() function!" + + # Check if tile class has all required variables and they are the correct type + for required_variable, var_type in required_class_variables.items(): + assert ( + required_variable in members + ), f"Tile class needs to have member variable '{required_variable}'" + assert isinstance( + eval(f"tile_class.{required_variable}"), var_type + ), f"Variable {required_variable} needs to be of type {var_type}" + + +def test_tile_bounds(): + """Test if tile is still in unit cube at the bounds""" + # TODO + pass + + +def test_tile_derivatives(): + """Testing the correctness of the tile derivatives""" + # TODO + pass + + +def test_tile_closure(): + """Check if closing tiles also lie in unit cube. Maybe also check derivatives.""" + # TODO + pass From 0aa09c871699dd8d1afc475990faf279b2cbb571 Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 9 Aug 2024 16:26:21 +0200 Subject: [PATCH 02/52] Remove hollow cube's rotation parameter check since there is no rotation --- splinepy/microstructure/tiles/hollow_cube.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/splinepy/microstructure/tiles/hollow_cube.py b/splinepy/microstructure/tiles/hollow_cube.py index 028ca0ed4..d94b5e8cc 100644 --- a/splinepy/microstructure/tiles/hollow_cube.py +++ b/splinepy/microstructure/tiles/hollow_cube.py @@ -66,18 +66,9 @@ def create_tile( self.check_params(parameters) - if not ( - _np.all(parameters[:, :2] > 0.0) - and _np.all(parameters[:, :2] < 0.5) - ): + if not _np.all((parameters > 0.0) & (parameters < 0.5)): raise ValueError("The wall thickness must be in (0.0 and 0.5)") - if not _np.all( - (parameters[:, 2:] > _np.deg2rad(-30)) - and (parameters[:, 2:] < _np.deg2rad(30)) - ): - raise ValueError("Rotation is only allowed between +-30 deg") - if self.check_param_derivatives(parameter_sensitivities): n_derivatives = parameter_sensitivities.shape[2] derivatives = [] From 2551b677b4342eaf29a4ea0fe401a6c2a4a9b8f8 Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 9 Aug 2024 16:29:50 +0200 Subject: [PATCH 03/52] WIP add test if all microtiles lie in unit cube (only for default parameters) --- tests/test_microstructure.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index cfb59555e..6e3cd8330 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -16,7 +16,7 @@ def test_tile_class(): "_dim": int, "_evaluation_points": np.ndarray, "_n_info_per_eval_point": int, - # "_sensitivities_implemented": bool + "_sensitivities_implemented": bool, } # Go through all available tiles @@ -58,13 +58,28 @@ def test_tile_class(): def test_tile_bounds(): - """Test if tile is still in unit cube at the bounds""" - # TODO - pass + """Test if tile is still in unit cube at the bounds. Currently only checks + default parameter values.""" + # TODO: also check non-default parameters + + def check_control_points(tile_patches): + """Check if all of tile's control points all lie within unit square/cube""" + # Go through all patches + for tile_patch in tile_patches: + cps = tile_patch.control_points + assert np.all( + (cps >= 0.0) & (cps <= 1.0) + ), "Control points of tile must lie inside the unit square/cube" + + for tile_class in all_tile_classes: + tile_creator = tile_class() + # Create tile with default parameters + tile_patches, _ = tile_creator.create_tile() + check_control_points(tile_patches) def test_tile_derivatives(): - """Testing the correctness of the tile derivatives""" + """Testing the correctness of the tile derivatives using Finite Differences""" # TODO pass From a5373d85c898f81f09870fe906961c1b3d1d1e6e Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 12 Aug 2024 13:31:55 +0200 Subject: [PATCH 04/52] Add test for microstructure closures --- splinepy/microstructure/tiles/armadillo.py | 1 + splinepy/microstructure/tiles/chi.py | 2 +- splinepy/microstructure/tiles/cross_2d.py | 15 ++++------ splinepy/microstructure/tiles/cross_3d.py | 3 ++ .../microstructure/tiles/cross_3d_linear.py | 3 ++ splinepy/microstructure/tiles/snappy.py | 8 ++++-- tests/test_microstructure.py | 28 +++++++++++++++++-- 7 files changed, 43 insertions(+), 17 deletions(-) diff --git a/splinepy/microstructure/tiles/armadillo.py b/splinepy/microstructure/tiles/armadillo.py index 9bbf602da..acf8828be 100644 --- a/splinepy/microstructure/tiles/armadillo.py +++ b/splinepy/microstructure/tiles/armadillo.py @@ -29,6 +29,7 @@ class Armadillo(_TileBase): "z_min", "z_max", ] + _parameter_bounds = [[0.0, 0.5]] def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/chi.py b/splinepy/microstructure/tiles/chi.py index e3cbf708b..707484c38 100644 --- a/splinepy/microstructure/tiles/chi.py +++ b/splinepy/microstructure/tiles/chi.py @@ -20,7 +20,7 @@ class Chi(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = True - _parameter_bounds = {"parameters": [-_np.pi / 2, _np.pi / 2]} + _parameter_bounds = [[-_np.pi / 2, _np.pi / 2]] def create_tile( self, diff --git a/splinepy/microstructure/tiles/cross_2d.py b/splinepy/microstructure/tiles/cross_2d.py index cf4a988d2..147da3cee 100644 --- a/splinepy/microstructure/tiles/cross_2d.py +++ b/splinepy/microstructure/tiles/cross_2d.py @@ -26,9 +26,11 @@ class Cross2D(_TileBase): ] ) _n_info_per_eval_point = 1 - _parameter_bounds = {"center_expansion": [0.5, 1.5]} _sensitivities_implemented = True _closure_directions = ["x_min", "x_max", "y_min", "y_max"] + _parameter_bounds = [ + [0.0, 0.5] + ] * 4 # valid for default center_expansion=1.0 def _closing_tile( self, @@ -420,15 +422,8 @@ def create_tile( if not isinstance(center_expansion, float): raise ValueError("Invalid Type") - center_expansion_bounds = self._parameter_bounds["center_expansion"] - if not ( - (center_expansion > center_expansion_bounds[0]) - and (center_expansion < center_expansion_bounds[1]) - ): - error_message = ( - "Center Expansion must be in (" - + f"{center_expansion_bounds[0]}, {center_expansion_bounds[1]})" - ) + if not ((center_expansion > 0.5) and (center_expansion < 1.5)): + error_message = "Center Expansion must be in (0.5, 1.5)" raise ValueError(error_message) max_radius = min(0.5, (0.5 / center_expansion)) diff --git a/splinepy/microstructure/tiles/cross_3d.py b/splinepy/microstructure/tiles/cross_3d.py index 01282c6f3..435ac3811 100644 --- a/splinepy/microstructure/tiles/cross_3d.py +++ b/splinepy/microstructure/tiles/cross_3d.py @@ -30,6 +30,9 @@ class Cross3D(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = True _closure_directions = ["z_min", "z_max"] + _parameter_bounds = [ + [0.0, 0.5] + ] * 6 # valid for default center_expansion=1.0 def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/cross_3d_linear.py b/splinepy/microstructure/tiles/cross_3d_linear.py index 952738afe..535592aa4 100644 --- a/splinepy/microstructure/tiles/cross_3d_linear.py +++ b/splinepy/microstructure/tiles/cross_3d_linear.py @@ -30,6 +30,9 @@ class Cross3DLinear(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = True _closure_directions = ["z_min", "z_max"] + _parameter_bounds = [ + [0.0, 0.5] + ] * 6 # valid for default center_expansion=1.0 def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index 7df89d6e8..60cab586f 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -63,7 +63,9 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - self.check_params(parameters) + # TODO: parameters are not implemented, therefore do not check params + if parameters is not None: + self.check_params(parameters) if parameter_sensitivities is not None: raise NotImplementedError( @@ -222,7 +224,6 @@ def _closing_tile( spline_list.append( _Bezier(degrees=[3, 1], control_points=spline_10) ) - return spline_list elif closure == "y_max": spline_1 = _np.array( [ @@ -288,12 +289,13 @@ def _closing_tile( spline_list.append( _Bezier(degrees=[3, 1], control_points=spline_5) ) - return (spline_list, None) else: raise ValueError( "Closing tile is only implemented for y-enclosure" ) + return (spline_list, None) + def create_tile( self, parameters=None, diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 6e3cd8330..b287b5b09 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -81,10 +81,32 @@ def check_control_points(tile_patches): def test_tile_derivatives(): """Testing the correctness of the tile derivatives using Finite Differences""" # TODO - pass + for tile_class in all_tile_classes: + tile_creator = tile_class() + # Skip test if tile class has no implemented sensitivities + if not tile_creator._sensitivities_implemented: + continue + pass def test_tile_closure(): """Check if closing tiles also lie in unit cube. Maybe also check derivatives.""" - # TODO - pass + # TODO: check closure also for extreme values of parameters + for tile_class in all_tile_classes: + # Skip tile if if does not support closure + if "_closure_directions" not in dir(tile_class): + continue + tile_creator = tile_class() + # Go through all implemented closure directions + for closure_direction in tile_creator._closure_directions: + tile_patches, sensitivities = tile_creator.create_tile( + closure=closure_direction + ) + assert ( + sensitivities is None + ), "Ensure sensitivities for closure are None if no sensitivities are asked" + for tile_patch in tile_patches: + cps = tile_patch.control_points + assert np.all( + (cps >= 0.0) & (cps <= 1.0) + ), "Control points of tile must lie inside the unit square/cube" From 7859a87ec9a2cd09db97ef44c3549a5a7eea4b1c Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 12 Aug 2024 15:54:45 +0200 Subject: [PATCH 05/52] Add test for non-default parameters of microtiles --- splinepy/microstructure/tiles/armadillo.py | 1 + splinepy/microstructure/tiles/chi.py | 4 +- splinepy/microstructure/tiles/cross_2d.py | 1 + splinepy/microstructure/tiles/cross_3d.py | 1 + .../microstructure/tiles/cross_3d_linear.py | 1 + splinepy/microstructure/tiles/cube_void.py | 13 +++- .../microstructure/tiles/double_lattice.py | 2 + splinepy/microstructure/tiles/ellips_v_oid.py | 10 +++ splinepy/microstructure/tiles/hollow_cube.py | 2 + .../microstructure/tiles/hollow_octagon.py | 2 + .../tiles/hollow_octagon_extrude.py | 6 +- .../microstructure/tiles/inverse_cross_3d.py | 4 +- splinepy/microstructure/tiles/snappy.py | 2 + tests/test_microstructure.py | 76 +++++++++++++++---- 14 files changed, 104 insertions(+), 21 deletions(-) diff --git a/splinepy/microstructure/tiles/armadillo.py b/splinepy/microstructure/tiles/armadillo.py index acf8828be..7137f6565 100644 --- a/splinepy/microstructure/tiles/armadillo.py +++ b/splinepy/microstructure/tiles/armadillo.py @@ -30,6 +30,7 @@ class Armadillo(_TileBase): "z_max", ] _parameter_bounds = [[0.0, 0.5]] + _parameters_shape = (1, 1) def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/chi.py b/splinepy/microstructure/tiles/chi.py index 707484c38..dcc2c971f 100644 --- a/splinepy/microstructure/tiles/chi.py +++ b/splinepy/microstructure/tiles/chi.py @@ -19,8 +19,8 @@ class Chi(_TileBase): _evaluation_points = _np.array([[0.5, 0.5]]) _n_info_per_eval_point = 1 _sensitivities_implemented = True - _parameter_bounds = [[-_np.pi / 2, _np.pi / 2]] + _parameters_shape = (1, 1) def create_tile( self, @@ -51,7 +51,7 @@ def create_tile( ) parameters = _np.array([[_np.pi / 8]]) else: - angle_bounds = self._parameter_bounds["parameters"] + angle_bounds = self._parameter_bounds[0] if not ( _np.all(parameters >= angle_bounds[0]) and _np.all(parameters < angle_bounds[1]) diff --git a/splinepy/microstructure/tiles/cross_2d.py b/splinepy/microstructure/tiles/cross_2d.py index 147da3cee..2fe51c2be 100644 --- a/splinepy/microstructure/tiles/cross_2d.py +++ b/splinepy/microstructure/tiles/cross_2d.py @@ -31,6 +31,7 @@ class Cross2D(_TileBase): _parameter_bounds = [ [0.0, 0.5] ] * 4 # valid for default center_expansion=1.0 + _parameters_shape = (4, 1) def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/cross_3d.py b/splinepy/microstructure/tiles/cross_3d.py index 435ac3811..fba595111 100644 --- a/splinepy/microstructure/tiles/cross_3d.py +++ b/splinepy/microstructure/tiles/cross_3d.py @@ -33,6 +33,7 @@ class Cross3D(_TileBase): _parameter_bounds = [ [0.0, 0.5] ] * 6 # valid for default center_expansion=1.0 + _parameters_shape = (6, 1) def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/cross_3d_linear.py b/splinepy/microstructure/tiles/cross_3d_linear.py index 535592aa4..22c0f7959 100644 --- a/splinepy/microstructure/tiles/cross_3d_linear.py +++ b/splinepy/microstructure/tiles/cross_3d_linear.py @@ -33,6 +33,7 @@ class Cross3DLinear(_TileBase): _parameter_bounds = [ [0.0, 0.5] ] * 6 # valid for default center_expansion=1.0 + _parameters_shape = (6, 1) def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/cube_void.py b/splinepy/microstructure/tiles/cube_void.py index a8da85df6..6fd8e04c6 100644 --- a/splinepy/microstructure/tiles/cube_void.py +++ b/splinepy/microstructure/tiles/cube_void.py @@ -26,6 +26,15 @@ class CubeVoid(_TileBase): _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 4 _sensitivities_implemented = True + # TODO: clever parameter bounds and checks if given parametrization would + # still lie in unit cube + _parameter_bounds = [ + [0.0, 1.0], + [0.0, 1.0], + [-_np.pi / 2, _np.pi / 2], + [-_np.pi / 2, _np.pi / 2], + ] + _parameters_shape = (1, 1, 4) # Aux values _sphere_ctps = _np.array( @@ -92,7 +101,9 @@ def create_tile( derivatives : list> / None """ # set to default if nothing is given if parameters is None: - parameters = _np.array([0.5, 0.5, 0, 0]).reshape(1, 1, 4) + parameters = _np.array([0.5, 0.5, 0, 0]).reshape( + self._parameters_shape + ) # Create center ellipsoid # RotY * RotX * DIAG(r_x, r_yz) * T_base diff --git a/splinepy/microstructure/tiles/double_lattice.py b/splinepy/microstructure/tiles/double_lattice.py index ffb2166b2..e040078f9 100644 --- a/splinepy/microstructure/tiles/double_lattice.py +++ b/splinepy/microstructure/tiles/double_lattice.py @@ -21,6 +21,8 @@ class DoubleLattice(_TileBase): _evaluation_points = _np.array([[0.5, 0.5]]) _n_info_per_eval_point = 2 _sensitivities_implemented = True + _parameter_bounds = [[0.0, 1 / (2 * (1 + _np.sqrt(2)))]] * 2 + _parameters_shape = (1, 2) def create_tile( self, diff --git a/splinepy/microstructure/tiles/ellips_v_oid.py b/splinepy/microstructure/tiles/ellips_v_oid.py index ec7a5cfe9..4f5c830c6 100644 --- a/splinepy/microstructure/tiles/ellips_v_oid.py +++ b/splinepy/microstructure/tiles/ellips_v_oid.py @@ -28,6 +28,16 @@ class EllipsVoid(_TileBase): _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 4 _sensitivities_implemented = True + # TODO: clever parameter bounds and checks if given parametrization would + # still lie in unit cube + # Due to ellipsoid, control points very easily lie outside unit cube + _parameter_bounds = [ + [0.0, 1.0], + [0.0, 1.0], + [-_np.pi / 2, _np.pi / 2], + [-_np.pi / 2, _np.pi / 2], + ] + _parameters_shape = (1, 1, 4) # Aux values _c0 = 0.5 / 3**0.5 diff --git a/splinepy/microstructure/tiles/hollow_cube.py b/splinepy/microstructure/tiles/hollow_cube.py index d94b5e8cc..a93e3b457 100644 --- a/splinepy/microstructure/tiles/hollow_cube.py +++ b/splinepy/microstructure/tiles/hollow_cube.py @@ -29,6 +29,8 @@ class HollowCube(_TileBase): ) _n_info_per_eval_point = 1 _sensitivities_implemented = True + _parameter_bounds = [[0.0, 0.5]] * 7 + _parameters_shape = (7, 1) def create_tile( self, diff --git a/splinepy/microstructure/tiles/hollow_octagon.py b/splinepy/microstructure/tiles/hollow_octagon.py index 44b31a65a..1b9489fcc 100644 --- a/splinepy/microstructure/tiles/hollow_octagon.py +++ b/splinepy/microstructure/tiles/hollow_octagon.py @@ -20,6 +20,8 @@ class HollowOctagon(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = False _closure_directions = ["x_min", "x_max", "y_min", "y_max"] + _parameter_bounds = [[0.0, 0.5]] + _parameters_shape = (1, 1) def _closing_tile( self, diff --git a/splinepy/microstructure/tiles/hollow_octagon_extrude.py b/splinepy/microstructure/tiles/hollow_octagon_extrude.py index dbf5f1901..1c935be0f 100644 --- a/splinepy/microstructure/tiles/hollow_octagon_extrude.py +++ b/splinepy/microstructure/tiles/hollow_octagon_extrude.py @@ -20,6 +20,8 @@ class HollowOctagonExtrude(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = False _closure_directions = ["x_min", "x_max", "y_min", "y_max"] + _parameter_bounds = [[0.0, 0.5]] + _parameters_shape = (1, 1) def create_tile( self, @@ -75,9 +77,9 @@ def create_tile( self.check_params(parameters) v_h_void = parameters[0, 0] - if not ((v_h_void > 0.01) and (v_h_void < 0.5)): + if not ((v_h_void > 0.0) and (v_h_void < 0.5)): raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" + "The thickness of the wall must be in (0.0 and 0.5)" ) v_zero = 0.0 diff --git a/splinepy/microstructure/tiles/inverse_cross_3d.py b/splinepy/microstructure/tiles/inverse_cross_3d.py index a633632fc..6e4f0e010 100644 --- a/splinepy/microstructure/tiles/inverse_cross_3d.py +++ b/splinepy/microstructure/tiles/inverse_cross_3d.py @@ -34,6 +34,8 @@ class InverseCross3D(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = False _closure_directions = ["z_min", "z_max"] + _parameter_bounds = [[0.2, 0.3]] * 6 # For default values + _parameters_shape = (6, 1) def _closing_tile( self, @@ -909,7 +911,7 @@ def create_tile( branches separator_distance : float Control point distance to separation layer of biquadratic degrees, - determines the minimum branch thickness (defaults to 0.4) + determines the minimum branch thickness (defaults to 0.3) center_expansion : float thickness of center is expanded by a factor (default to 1.0), which determines the maximum branch thickness diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index 60cab586f..84eba670d 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -22,6 +22,8 @@ class Snappy(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = False _closure_directions = ["y_min", "y_max"] + _parameter_bounds = [] + _parameters_shape = () def _closing_tile( self, diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index b287b5b09..8d7846ded 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -3,12 +3,43 @@ import numpy as np import splinepy.microstructure as ms +from splinepy.utils.data import cartesian_product as _cartesian_product EPS = 1e-8 all_tile_classes = list(ms.tiles.everything().values()) +def check_control_points(tile_patches): + """Check if all of tile's control points all lie within unit square/cube""" + # Go through all patches + for tile_patch in tile_patches: + cps = tile_patch.control_points + assert np.all( + (cps >= 0.0 - EPS) & (cps <= 1.0 + EPS) + ), "Control points of tile must lie inside the unit square/cube" + + +def make_bounds_feasible(bounds): + """Bounds are given are understood as open set of min. and max. values. Therefore, + convert bounds to open set of these values. + + Parameters + ------------ + bounds: list> + Values of bounds + + Returns + ---------- + feasible_bounds: np.ndarray + Values of bounds + """ + feasible_bounds = [ + [min_value + EPS, max_value - EPS] for min_value, max_value in bounds + ] + return np.array(feasible_bounds) + + def test_tile_class(): """Checks if all tile classes have the appropriate members and functions.""" required_class_variables = { @@ -60,23 +91,41 @@ def test_tile_class(): def test_tile_bounds(): """Test if tile is still in unit cube at the bounds. Currently only checks default parameter values.""" - # TODO: also check non-default parameters - - def check_control_points(tile_patches): - """Check if all of tile's control points all lie within unit square/cube""" - # Go through all patches - for tile_patch in tile_patches: - cps = tile_patch.control_points - assert np.all( - (cps >= 0.0) & (cps <= 1.0) - ), "Control points of tile must lie inside the unit square/cube" + # Skip certain tile classes for testing + skip_tiles = [ + ms.tiles.EllipsVoid, # Control points easily lie outside unitcube + ms.tiles.Snappy, # Has no parameters + ] for tile_class in all_tile_classes: + # Skip certain classes for testing + skip_tile_class = False + for skip_tile in skip_tiles: + if tile_class is skip_tile: + skip_tile_class = True + break + if skip_tile_class: + continue + tile_creator = tile_class() # Create tile with default parameters tile_patches, _ = tile_creator.create_tile() check_control_points(tile_patches) + # Go through all extremes of parameters and ensure that also they create + # tiles within unit square/cube + feasible_parameter_bounds = make_bounds_feasible( + tile_creator._parameter_bounds + ) + all_parameter_bounds = _cartesian_product(feasible_parameter_bounds) + for parameter_extremes in all_parameter_bounds: + tile_patches, _ = tile_creator.create_tile( + parameters=parameter_extremes.reshape( + tile_creator._parameters_shape + ) + ) + check_control_points(tile_patches) + def test_tile_derivatives(): """Testing the correctness of the tile derivatives using Finite Differences""" @@ -105,8 +154,5 @@ def test_tile_closure(): assert ( sensitivities is None ), "Ensure sensitivities for closure are None if no sensitivities are asked" - for tile_patch in tile_patches: - cps = tile_patch.control_points - assert np.all( - (cps >= 0.0) & (cps <= 1.0) - ), "Control points of tile must lie inside the unit square/cube" + + check_control_points(tile_patches) From 6a6d40270ff5ffcd17f4ca7102229981a6b4f8a4 Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 12 Aug 2024 16:10:04 +0200 Subject: [PATCH 06/52] Add test for non-default parameters plus closure of microtiles --- .../microstructure/tiles/hollow_octagon.py | 4 +-- tests/test_microstructure.py | 34 ++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/splinepy/microstructure/tiles/hollow_octagon.py b/splinepy/microstructure/tiles/hollow_octagon.py index 1b9489fcc..f3dbfd5e8 100644 --- a/splinepy/microstructure/tiles/hollow_octagon.py +++ b/splinepy/microstructure/tiles/hollow_octagon.py @@ -77,9 +77,9 @@ def _closing_tile( ) v_h_void = parameters[0, 0] - if not ((v_h_void > 0.01) and (v_h_void < 0.5)): + if not ((v_h_void > 0.0) and (v_h_void < 0.5)): raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" + "The thickness of the wall must be in (0.0 and 0.5)" ) spline_list = [] diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 8d7846ded..7e83795d3 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -140,7 +140,12 @@ def test_tile_derivatives(): def test_tile_closure(): """Check if closing tiles also lie in unit cube. Maybe also check derivatives.""" - # TODO: check closure also for extreme values of parameters + # Skip certain tile classes for testing + skip_tiles = [ + ms.tiles.EllipsVoid, # Control points easily lie outside unitcube + ms.tiles.Snappy, # Has no parameters + ] + for tile_class in all_tile_classes: # Skip tile if if does not support closure if "_closure_directions" not in dir(tile_class): @@ -156,3 +161,30 @@ def test_tile_closure(): ), "Ensure sensitivities for closure are None if no sensitivities are asked" check_control_points(tile_patches) + + # Also check non-default parameters + # Skip certain classes for testing + skip_tile_class = False + for skip_tile in skip_tiles: + if tile_class is skip_tile: + skip_tile_class = True + break + if skip_tile_class: + continue + + # Go through all extremes of parameters and ensure that also they create + # tiles within unit square/cube + feasible_parameter_bounds = make_bounds_feasible( + tile_creator._parameter_bounds + ) + all_parameter_bounds = _cartesian_product(feasible_parameter_bounds) + # Go through all implemented closure directions + for closure_direction in tile_creator._closure_directions: + for parameter_extremes in all_parameter_bounds: + tile_patches, _ = tile_creator.create_tile( + parameters=parameter_extremes.reshape( + tile_creator._parameters_shape + ), + closure=closure_direction, + ) + check_control_points(tile_patches) From a3f9d12c6f64c74630e06d02251a5ab8b3a07d81 Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 12 Aug 2024 16:19:21 +0200 Subject: [PATCH 07/52] Restructure microstructure tests --- tests/test_microstructure.py | 57 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 7e83795d3..a37b43b4e 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -9,6 +9,12 @@ all_tile_classes = list(ms.tiles.everything().values()) +# Skip certain tile classes for parameters testing +skip_tiles = [ + ms.tiles.EllipsVoid, # Control points easily lie outside unitcube + ms.tiles.Snappy, # Has no "parameters" +] + def check_control_points(tile_patches): """Check if all of tile's control points all lie within unit square/cube""" @@ -48,6 +54,8 @@ def test_tile_class(): "_evaluation_points": np.ndarray, "_n_info_per_eval_point": int, "_sensitivities_implemented": bool, + "_parameter_bounds": list, + "_parameters_shape": tuple, } # Go through all available tiles @@ -89,15 +97,14 @@ def test_tile_class(): def test_tile_bounds(): - """Test if tile is still in unit cube at the bounds. Currently only checks - default parameter values.""" - # Skip certain tile classes for testing - skip_tiles = [ - ms.tiles.EllipsVoid, # Control points easily lie outside unitcube - ms.tiles.Snappy, # Has no parameters - ] - + """Test if tile is still in unit cube at the bounds. Checks default and also + non-default parameter values.""" for tile_class in all_tile_classes: + tile_creator = tile_class() + # Create tile with default parameters + tile_patches, _ = tile_creator.create_tile() + check_control_points(tile_patches) + # Skip certain classes for testing skip_tile_class = False for skip_tile in skip_tiles: @@ -107,11 +114,6 @@ def test_tile_bounds(): if skip_tile_class: continue - tile_creator = tile_class() - # Create tile with default parameters - tile_patches, _ = tile_creator.create_tile() - check_control_points(tile_patches) - # Go through all extremes of parameters and ensure that also they create # tiles within unit square/cube feasible_parameter_bounds = make_bounds_feasible( @@ -127,24 +129,8 @@ def test_tile_bounds(): check_control_points(tile_patches) -def test_tile_derivatives(): - """Testing the correctness of the tile derivatives using Finite Differences""" - # TODO - for tile_class in all_tile_classes: - tile_creator = tile_class() - # Skip test if tile class has no implemented sensitivities - if not tile_creator._sensitivities_implemented: - continue - pass - - def test_tile_closure(): - """Check if closing tiles also lie in unit cube. Maybe also check derivatives.""" - # Skip certain tile classes for testing - skip_tiles = [ - ms.tiles.EllipsVoid, # Control points easily lie outside unitcube - ms.tiles.Snappy, # Has no parameters - ] + """Check if closing tiles also lie in unit cube. TODO: also check derivatives.""" for tile_class in all_tile_classes: # Skip tile if if does not support closure @@ -188,3 +174,14 @@ def test_tile_closure(): closure=closure_direction, ) check_control_points(tile_patches) + + +def test_tile_derivatives(): + """Testing the correctness of the tile derivatives using Finite Differences""" + # TODO + for tile_class in all_tile_classes: + tile_creator = tile_class() + # Skip test if tile class has no implemented sensitivities + if not tile_creator._sensitivities_implemented: + continue + pass From 693acc01be0df16ea19899bfa841d8ec1e986e36 Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 26 Aug 2024 10:42:31 +0200 Subject: [PATCH 08/52] Add test for tile derivatives (WIP) --- splinepy/microstructure/tiles/chi.py | 2 +- splinepy/microstructure/tiles/cube_void.py | 2 +- splinepy/microstructure/tiles/ellips_v_oid.py | 2 +- tests/test_microstructure.py | 97 ++++++++++++++++++- 4 files changed, 96 insertions(+), 7 deletions(-) diff --git a/splinepy/microstructure/tiles/chi.py b/splinepy/microstructure/tiles/chi.py index dcc2c971f..827c7b8d3 100644 --- a/splinepy/microstructure/tiles/chi.py +++ b/splinepy/microstructure/tiles/chi.py @@ -16,7 +16,7 @@ class Chi(_TileBase): _dim = 2 _para_dim = 1 - _evaluation_points = _np.array([[0.5, 0.5]]) + _evaluation_points = _np.array([[0.5]]) _n_info_per_eval_point = 1 _sensitivities_implemented = True _parameter_bounds = [[-_np.pi / 2, _np.pi / 2]] diff --git a/splinepy/microstructure/tiles/cube_void.py b/splinepy/microstructure/tiles/cube_void.py index 6fd8e04c6..c435b6a88 100644 --- a/splinepy/microstructure/tiles/cube_void.py +++ b/splinepy/microstructure/tiles/cube_void.py @@ -34,7 +34,7 @@ class CubeVoid(_TileBase): [-_np.pi / 2, _np.pi / 2], [-_np.pi / 2, _np.pi / 2], ] - _parameters_shape = (1, 1, 4) + _parameters_shape = (1, 4) # Aux values _sphere_ctps = _np.array( diff --git a/splinepy/microstructure/tiles/ellips_v_oid.py b/splinepy/microstructure/tiles/ellips_v_oid.py index 4f5c830c6..84025d8bf 100644 --- a/splinepy/microstructure/tiles/ellips_v_oid.py +++ b/splinepy/microstructure/tiles/ellips_v_oid.py @@ -37,7 +37,7 @@ class EllipsVoid(_TileBase): [-_np.pi / 2, _np.pi / 2], [-_np.pi / 2, _np.pi / 2], ] - _parameters_shape = (1, 1, 4) + _parameters_shape = (1, 4) # Aux values _c0 = 0.5 / 3**0.5 diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index a37b43b4e..70bf4b2e5 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -176,12 +176,101 @@ def test_tile_closure(): check_control_points(tile_patches) -def test_tile_derivatives(): - """Testing the correctness of the tile derivatives using Finite Differences""" - # TODO +def test_tile_derivatives(np_rng, heps=1e-8): + """Testing the correctness of the tile derivatives using Finite Differences + + Parameters + --------- + heps: float + Perturbation size for finite difference evaluation + """ + # TODO: right now Chi, EllipsVoid and CubeVoid show wrong derivatives + skip_classes = [ms.tiles.Chi, ms.tiles.EllipsVoid, ms.tiles.CubeVoid] + for tile_class in all_tile_classes: + # TODO: right now skip classes with faultily implemented derivatives + if tile_class in skip_classes: + continue + tile_creator = tile_class() # Skip test if tile class has no implemented sensitivities if not tile_creator._sensitivities_implemented: continue - pass + # Choose parameter(s) as mean of extreme values + parameter_bounds = tile_creator._parameter_bounds + parameters = np.mean(np.array(parameter_bounds), axis=1).reshape( + tile_creator._parameters_shape + ) + # Create 3D identity matrix + n_eval_points = tile_creator._evaluation_points.shape[0] + n_info_per_eval_point = tile_creator._n_info_per_eval_point + parameter_sensitivities = np.zeros( + (n_eval_points, n_info_per_eval_point, 1) + ) + idx = np.arange(np.min(parameter_sensitivities.shape)) + parameter_sensitivities[idx, idx, :] = 1 + splines, derivatives = tile_creator.create_tile( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) + # Evaluate splines and derivatives at random points + eval_points = np_rng.random((4, splines[0].para_dim)) + deriv_evaluations = [ + deriv.evaluate(eval_points) for deriv in derivatives[0] + ] + spline_orig_evaluations = [ + spl.evaluate(eval_points) for spl in splines + ] + + parameters_perturbed = parameters.copy() + parameters_perturbed += heps + splines_perturbed, _ = tile_creator.create_tile( + parameters=parameters_perturbed + ) + spline_perturbed_evaluations = [ + spl.evaluate(eval_points) for spl in splines_perturbed + ] + fd_sensitivities = [ + (spl_pert - spl_orig) / heps + for spl_pert, spl_orig in zip( + spline_perturbed_evaluations, spline_orig_evaluations + ) + ] + + # Go through all the parameters individually + for i_parameter in range(n_info_per_eval_point): + # Get derivatives w.r.t. one parameter + parameter_sensitivities = np.zeros( + (n_eval_points, n_info_per_eval_point, 1) + ) + parameter_sensitivities[:, i_parameter, :] = 1 + _, derivatives = tile_creator.create_tile( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) + deriv_evaluations = [ + deriv.evaluate(eval_points) for deriv in derivatives[0] + ] + # Perform finite difference evaluation + parameters_perturbed = parameters.copy() + parameters_perturbed[:, i_parameter] += heps + splines_perturbed, _ = tile_creator.create_tile( + parameters=parameters_perturbed + ) + spline_perturbed_evaluations = [ + spl.evaluate(eval_points) for spl in splines_perturbed + ] + fd_sensitivities = [ + (spl_pert - spl_orig) / heps + for spl_pert, spl_orig in zip( + spline_perturbed_evaluations, spline_orig_evaluations + ) + ] + # Check every patch + for deriv_orig, deriv_fd in zip( + deriv_evaluations, fd_sensitivities + ): + assert np.allclose(deriv_orig, deriv_fd), ( + "Implemented derivative calculation does not match the derivative " + + "obtained using Finite Differences" + ) From c7c25741268ae10e17fea33a8d41b449da94036e Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 26 Aug 2024 14:28:44 +0200 Subject: [PATCH 09/52] Add derivative of HollowOctagon tile --- .../microstructure/tiles/hollow_octagon.py | 202 ++++++++++-------- tests/test_microstructure.py | 15 +- 2 files changed, 122 insertions(+), 95 deletions(-) diff --git a/splinepy/microstructure/tiles/hollow_octagon.py b/splinepy/microstructure/tiles/hollow_octagon.py index f3dbfd5e8..b05f6b74e 100644 --- a/splinepy/microstructure/tiles/hollow_octagon.py +++ b/splinepy/microstructure/tiles/hollow_octagon.py @@ -18,7 +18,7 @@ class HollowOctagon(_TileBase): _para_dim = 2 _evaluation_points = _np.array([[0.5, 0.5]]) _n_info_per_eval_point = 1 - _sensitivities_implemented = False + _sensitivities_implemented = True _closure_directions = ["x_min", "x_max", "y_min", "y_max"] _parameter_bounds = [[0.0, 0.5]] _parameters_shape = (1, 1) @@ -87,7 +87,7 @@ def _closing_tile( v_one_half = 0.5 v_one = 1.0 v_outer_c_h = contact_length * 0.5 - v_inner_c_h = contact_length * parameters[0, 0] + v_inner_c_h = contact_length * v_h_void if closure == "x_min": # set points: @@ -407,7 +407,7 @@ def _closing_tile( def create_tile( self, parameters=None, - parameter_sensitivities=None, # TODO + parameter_sensitivities=None, contact_length=0.2, closure=None, **kwargs, # noqa ARG002 @@ -456,13 +456,15 @@ def create_tile( ) if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None self.check_params(parameters) + self.check_param_derivatives(parameter_sensitivities) - v_h_void = parameters[0, 0] if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): raise ValueError( "The thickness of the wall must be in (0.01 and 0.49)" @@ -476,103 +478,125 @@ def create_tile( closure=closure, ) - v_zero = 0.0 - v_one_half = 0.5 - v_one = 1.0 - v_outer_c_h = contact_length * 0.5 - v_inner_c_h = contact_length * parameters[0, 0] + splines = [] + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + v_zero = 0.0 + v_one_half = 0.5 + v_one = 1.0 + v_h_void = parameters[0, 0] + v_outer_c_h = contact_length * 0.5 + v_inner_c_h = contact_length * v_h_void + else: + v_zero = 0.0 + v_one_half = 0.0 + v_one = 0.0 + v_h_void = parameter_sensitivities[0, 0, i_derivative - 1] + v_outer_c_h = 0.0 + v_inner_c_h = contact_length * v_h_void + + spline_list = [] - spline_list = [] + # set points: + right = _np.array( + [ + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + ] + ) - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - ] - ) + right_top = _np.array( + [ + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + ] + ) - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - ] - ) + top = _np.array( + [ + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + ] + ) - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - ] - ) + bottom_left = _np.array( + [ + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, -v_outer_c_h + v_one_half], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + ] + ) - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, -v_outer_c_h + v_one_half], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - ] - ) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + ] + ) - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + ] + ) - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + ] + ) - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + bottom_right = _np.array( + [ + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_zero], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - ] - ) + spline_list.append(_Bezier(degrees=[1, 1], control_points=right)) - spline_list.append(_Bezier(degrees=[1, 1], control_points=right)) + spline_list.append( + _Bezier(degrees=[1, 1], control_points=right_top) + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=right_top)) + spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom)) - spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom)) + spline_list.append( + _Bezier(degrees=[1, 1], control_points=bottom_left) + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom_left)) + spline_list.append(_Bezier(degrees=[1, 1], control_points=left)) - spline_list.append(_Bezier(degrees=[1, 1], control_points=left)) + spline_list.append( + _Bezier(degrees=[1, 1], control_points=top_left) + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=top_left)) + spline_list.append(_Bezier(degrees=[1, 1], control_points=top)) - spline_list.append(_Bezier(degrees=[1, 1], control_points=top)) + spline_list.append( + _Bezier(degrees=[1, 1], control_points=bottom_right) + ) - spline_list.append( - _Bezier(degrees=[1, 1], control_points=bottom_right) - ) + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) - return (spline_list, None) + return (splines, derivatives) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 70bf4b2e5..1a2b54371 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -196,11 +196,14 @@ def test_tile_derivatives(np_rng, heps=1e-8): # Skip test if tile class has no implemented sensitivities if not tile_creator._sensitivities_implemented: continue - # Choose parameter(s) as mean of extreme values - parameter_bounds = tile_creator._parameter_bounds - parameters = np.mean(np.array(parameter_bounds), axis=1).reshape( - tile_creator._parameters_shape - ) + + # Choose random parameter(s) within bounds + parameter_bounds = np.array(tile_creator._parameter_bounds) + parameters = parameter_bounds[:, 0] + np_rng.random( + len(parameter_bounds) + ) * np.ptp(parameter_bounds, axis=1) + parameters = parameters.reshape(tile_creator._parameters_shape) + # Create 3D identity matrix n_eval_points = tile_creator._evaluation_points.shape[0] n_info_per_eval_point = tile_creator._n_info_per_eval_point @@ -213,7 +216,7 @@ def test_tile_derivatives(np_rng, heps=1e-8): parameters=parameters, parameter_sensitivities=parameter_sensitivities, ) - # Evaluate splines and derivatives at random points + # Evaluate splines and derivatives at multiple random points eval_points = np_rng.random((4, splines[0].para_dim)) deriv_evaluations = [ deriv.evaluate(eval_points) for deriv in derivatives[0] From 82caf4fce33ea6af43f9dc6ffd341eb296c423da Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 26 Aug 2024 14:40:26 +0200 Subject: [PATCH 10/52] Add derivatives for closure of HollowOctagon tile --- .../microstructure/tiles/hollow_octagon.py | 631 +++++++++--------- 1 file changed, 318 insertions(+), 313 deletions(-) diff --git a/splinepy/microstructure/tiles/hollow_octagon.py b/splinepy/microstructure/tiles/hollow_octagon.py index b05f6b74e..22ace6555 100644 --- a/splinepy/microstructure/tiles/hollow_octagon.py +++ b/splinepy/microstructure/tiles/hollow_octagon.py @@ -26,7 +26,7 @@ class HollowOctagon(_TileBase): def _closing_tile( self, parameters=None, - parameter_sensitivities=None, # TODO + parameter_sensitivities=None, contact_length=0.2, closure=None, ): @@ -70,11 +70,14 @@ def _closing_tile( ) self.check_params(parameters) + self.check_param_derivatives(parameter_sensitivities) if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None v_h_void = parameters[0, 0] if not ((v_h_void > 0.0) and (v_h_void < 0.5)): @@ -82,327 +85,339 @@ def _closing_tile( "The thickness of the wall must be in (0.0 and 0.5)" ) - spline_list = [] - v_zero = 0.0 - v_one_half = 0.5 - v_one = 1.0 - v_outer_c_h = contact_length * 0.5 - v_inner_c_h = contact_length * v_h_void - - if closure == "x_min": - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - ] - ) - - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - ] - ) - - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - ] - ) - - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - ] - ) - - left = _np.array( - [ - [v_zero, v_zero], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_one], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + splines = [] + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + v_zero = 0.0 + v_one_half = 0.5 + v_one = 1.0 + v_outer_c_h = contact_length * 0.5 + v_inner_c_h = contact_length * v_h_void + else: + v_zero = 0.0 + v_one_half = 0.0 + v_one = 0.0 + v_h_void = parameter_sensitivities[0, 0, i_derivative - 1] + v_outer_c_h = 0.0 + v_inner_c_h = contact_length * v_h_void - top_left = _np.array( - [ - [v_zero, v_one], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + spline_list = [] - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + if closure == "x_min": + # set points: + right = _np.array( + [ + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - ] - ) + right_top = _np.array( + [ + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + ] + ) - elif closure == "x_max": - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, v_zero], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_one], - ] - ) + top = _np.array( + [ + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + ] + ) - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_one], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - ] - ) + bottom_left = _np.array( + [ + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, v_zero], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + ] + ) - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - ] - ) + left = _np.array( + [ + [v_zero, v_zero], + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, v_one], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + ] + ) - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, -v_outer_c_h + v_one_half], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - ] - ) + top_left = _np.array( + [ + [v_zero, v_one], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + ] + ) - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + ] + ) - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + bottom_right = _np.array( + [ + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_zero], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + ] + ) - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + elif closure == "x_max": + right = _np.array( + [ + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, v_zero], + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_one], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, v_zero], - ] - ) + right_top = _np.array( + [ + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_one], + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + ] + ) - elif closure == "y_min": - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - ] - ) + top = _np.array( + [ + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + ] + ) - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - ] - ) + bottom_left = _np.array( + [ + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, -v_outer_c_h + v_one_half], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + ] + ) - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - ] - ) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + ] + ) - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, -v_outer_c_h + v_one_half], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_zero, v_zero], - ] - ) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + ] + ) - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + ] + ) - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + bottom_right = _np.array( + [ + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_zero], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, v_zero], + ] + ) - bottom = _np.array( - [ - [v_one, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_zero, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + elif closure == "y_min": + # set points: + right = _np.array( + [ + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_one, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - ] - ) + right_top = _np.array( + [ + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + ] + ) - elif closure == "y_max": - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - ] - ) + top = _np.array( + [ + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + ] + ) - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_one, v_one], - ] - ) + bottom_left = _np.array( + [ + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, -v_outer_c_h + v_one_half], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [v_zero, v_zero], + ] + ) - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_one, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_zero, v_one], - ] - ) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + ] + ) - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, -v_outer_c_h + v_one_half], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - ] - ) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + [-v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + ] + ) - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + bottom = _np.array( + [ + [v_one, v_zero], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [v_zero, v_zero], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + ] + ) - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_zero, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + bottom_right = _np.array( + [ + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [v_one, v_zero], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + ] + ) - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + elif closure == "y_max": + # set points: + right = _np.array( + [ + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - ] - ) + right_top = _np.array( + [ + [v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_one, v_outer_c_h + v_one_half], + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_one, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=right)) + top = _np.array( + [ + [v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_one, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + [v_zero, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=right_top)) + bottom_left = _np.array( + [ + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, -v_outer_c_h + v_one_half], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom)) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom_left)) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half], + [v_zero, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=left)) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [-v_outer_c_h + v_one_half, v_zero], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=top_left)) + bottom_right = _np.array( + [ + [v_inner_c_h + v_one_half, -v_h_void + v_one_half], + [v_outer_c_h + v_one_half, v_zero], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half], + [v_one, -v_outer_c_h + v_one_half], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=top)) + for control_points in [ + right, + right_top, + bottom, + bottom_left, + left, + top_left, + top, + bottom_right, + ]: + spline_list.append( + _Bezier(degrees=[1, 1], control_points=control_points) + ) - spline_list.append( - _Bezier(degrees=[1, 1], control_points=bottom_right) - ) + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) - return (spline_list, None) + return (splines, derivatives) def create_tile( self, @@ -473,7 +488,7 @@ def create_tile( if closure is not None: return self._closing_tile( parameters=parameters, - parameter_sensitivities=parameter_sensitivities, # TODO + parameter_sensitivities=parameter_sensitivities, contact_length=contact_length, closure=closure, ) @@ -570,29 +585,19 @@ def create_tile( ] ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=right)) - - spline_list.append( - _Bezier(degrees=[1, 1], control_points=right_top) - ) - - spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom)) - - spline_list.append( - _Bezier(degrees=[1, 1], control_points=bottom_left) - ) - - spline_list.append(_Bezier(degrees=[1, 1], control_points=left)) - - spline_list.append( - _Bezier(degrees=[1, 1], control_points=top_left) - ) - - spline_list.append(_Bezier(degrees=[1, 1], control_points=top)) - - spline_list.append( - _Bezier(degrees=[1, 1], control_points=bottom_right) - ) + for control_points in [ + right, + right_top, + bottom, + bottom_left, + left, + top_left, + top, + bottom_right, + ]: + spline_list.append( + _Bezier(degrees=[1, 1], control_points=control_points) + ) if i_derivative == 0: splines = spline_list.copy() From 364c21389f140cd2074ce9e5cde1f4e022740fca Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 26 Aug 2024 15:22:35 +0200 Subject: [PATCH 11/52] Add derivatives for Armadillo tile --- splinepy/microstructure/tiles/armadillo.py | 10086 +++++++++---------- 1 file changed, 5028 insertions(+), 5058 deletions(-) diff --git a/splinepy/microstructure/tiles/armadillo.py b/splinepy/microstructure/tiles/armadillo.py index 7137f6565..e9fe2a50c 100644 --- a/splinepy/microstructure/tiles/armadillo.py +++ b/splinepy/microstructure/tiles/armadillo.py @@ -20,7 +20,7 @@ class Armadillo(_TileBase): _dim = 3 _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 1 - _sensitivities_implemented = False + _sensitivities_implemented = True _closure_directions = [ "x_min", "x_max", @@ -35,7 +35,7 @@ class Armadillo(_TileBase): def _closing_tile( self, parameters=None, - parameter_sensitivities=None, # TODO + parameter_sensitivities=None, contact_length=0.3, closure=None, **kwargs, # noqa ARG002 @@ -85,4088 +85,5043 @@ def _closing_tile( ) self.check_params(parameters) + self.check_param_derivatives(parameter_sensitivities) if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): raise ValueError( "The thickness of the wall must be in (0.01 and 0.49)" ) - v_wall_thickness = parameters[0, 0] - spline_list = [] - v_zero = 0.0 - v_one_half = 0.5 - v_one = 1.0 - v_half_contact_length = contact_length * 0.5 - v_inner_half_contact_length = contact_length * parameters[0, 0] - - if closure == "x_min": - # set points: - right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], + splines = [] + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + v_wall_thickness = parameters[0, 0] + v_zero = 0.0 + v_one_half = 0.5 + v_one = 1.0 + v_half_contact_length = contact_length * 0.5 + v_inner_half_contact_length = contact_length * v_wall_thickness + else: + v_wall_thickness = parameter_sensitivities[ + 0, 0, i_derivative - 1 ] - ) + v_zero = 0.0 + v_one_half = 0.0 + v_one = 0.0 + v_half_contact_length = 0.0 + v_inner_half_contact_length = contact_length * v_wall_thickness + + spline_list = [] + + if closure == "x_min": + # set points: + right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) - connection_front_right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) + connection_front_right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) - front = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) + front = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) - connection_back_left = _np.array( - [ - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_zero, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - ] - ) + connection_back_left = _np.array( + [ + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + ] + ) - left = _np.array( - [ - [ - v_zero, - v_one, - v_one, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_one, - v_zero, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_zero, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + left = _np.array( + [ + [ + v_zero, + v_one, + v_one, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_one, + v_zero, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_front_left = _np.array( - [ - [ - v_zero, - v_one, - v_one, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_one, - v_zero, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_front_left = _np.array( + [ + [ + v_zero, + v_one, + v_one, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_one, + v_zero, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - back = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + back = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_back_right = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) + connection_back_right = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) - bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - top = _np.array( - [ - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - ] - ) + top = _np.array( + [ + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + ] + ) - connection_front_bottom = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + connection_front_bottom = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - connection_front_top = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - ] - ) + connection_front_top = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + ] + ) - connection_back_bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_back_bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_back_top = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - ] - ) + connection_back_top = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + ] + ) - connection_top_right = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) + connection_top_right = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) - connection_top_left = _np.array( - [ - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_zero, - v_one, - v_one, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) + connection_top_left = _np.array( + [ + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_zero, + v_one, + v_one, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) - connection_bottom_left = _np.array( - [ - [ - v_zero, - v_one, - v_zero, - ], - [ - v_zero, - v_zero, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + connection_bottom_left = _np.array( + [ + [ + v_zero, + v_one, + v_zero, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - connection_bottom_right = _np.array( - [ - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - elif closure == "x_max": - # set points: - right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_zero, - v_one, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_zero, - v_zero, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_one, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_zero, - ], - ] - ) - - connection_front_right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_one, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) - - front = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) - - connection_back_left = _np.array( - [ - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - ] - ) - - left = _np.array( - [ - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_front_left = _np.array( - [ - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - back = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_back_right = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_zero, - v_one, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_zero, - v_zero, - ], - ] - ) - - bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - top = _np.array( - [ - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - ] - ) - - connection_front_bottom = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - connection_front_top = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - ] - ) - - connection_back_bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_back_top = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_top_right = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_one, - v_one, - ], - [ - v_one, - v_zero, - v_one, - ], - [ - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_top_left = _np.array( - [ - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_bottom_left = _np.array( - [ - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - connection_bottom_right = _np.array( - [ - [ - v_one, - v_one, - v_zero, - ], - [ - v_one, - v_zero, - v_zero, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - elif closure == "y_min": - # set points: - right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) - - connection_front_right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) - - front = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) - - connection_back_left = _np.array( - [ - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_zero, - ], - ] - ) - - left = _np.array( - [ - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_front_left = _np.array( - [ - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - back = _np.array( - [ - [ - v_one, - v_zero, - v_one, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_zero, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_zero, - v_zero, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_back_right = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_zero, - v_one, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_zero, - v_zero, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) - - bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - top = _np.array( - [ - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - ] - ) - - connection_front_bottom = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - connection_front_top = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - ] - ) - - connection_back_bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one, - v_zero, - v_zero, - ], - [ - v_zero, - v_zero, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_back_top = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_zero, - v_one, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_top_right = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_top_left = _np.array( - [ - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_bottom_left = _np.array( - [ - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - connection_bottom_right = _np.array( - [ - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - elif closure == "y_max": - # set points: - # set points: - right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) - - connection_front_right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_one, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_zero, - ], - ] - ) - - front = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_one, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_zero, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_one, - v_one, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_one, - v_zero, - ], - ] - ) - - connection_back_left = _np.array( - [ - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - ] - ) - - left = _np.array( - [ - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_bottom_right = _np.array( + [ + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - connection_top_left = _np.array( - [ - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_one, - v_one, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_one, - v_zero, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + elif closure == "x_max": + # set points: + right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_zero, + v_one, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_zero, + v_zero, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_one, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_zero, + ], + ] + ) - back = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_front_right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_one, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) - connection_back_right = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) + front = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) - bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + connection_back_left = _np.array( + [ + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + ] + ) - top = _np.array( - [ - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - ] - ) + left = _np.array( + [ + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_front_bottom = _np.array( - [ - [ - v_one, - v_one, - v_zero, - ], - [ - v_zero, - v_one, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + connection_front_left = _np.array( + [ + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_front_top = _np.array( - [ - [ - v_one, - v_one, - v_one, - ], - [ - v_zero, - v_one, - v_one, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - ] - ) + back = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_back_right = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_zero, + v_one, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_zero, + v_zero, + ], + ] + ) + + bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + top = _np.array( + [ + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + ] + ) + + connection_front_bottom = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_front_top = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + ] + ) + + connection_back_bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_back_top = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_top_right = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_one, + v_one, + ], + [ + v_one, + v_zero, + v_one, + ], + [ + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_top_left = _np.array( + [ + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_bottom_left = _np.array( + [ + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_bottom_right = _np.array( + [ + [ + v_one, + v_one, + v_zero, + ], + [ + v_one, + v_zero, + v_zero, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + elif closure == "y_min": + # set points: + right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) + + connection_front_right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) + + front = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) + + connection_back_left = _np.array( + [ + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_zero, + ], + ] + ) + + left = _np.array( + [ + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_back_bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_front_left = _np.array( + [ + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_back_top = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - ] - ) + back = _np.array( + [ + [ + v_one, + v_zero, + v_one, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_zero, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_top_right = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) + connection_back_right = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_zero, + v_one, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_zero, + v_zero, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) - connection_front_left = _np.array( - [ - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) + bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - connection_bottom_left = _np.array( - [ - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + top = _np.array( + [ + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + ] + ) + + connection_front_bottom = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_front_top = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + ] + ) + + connection_back_bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one, + v_zero, + v_zero, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_back_top = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_zero, + v_one, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_top_right = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_top_left = _np.array( + [ + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_bottom_left = _np.array( + [ + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_bottom_right = _np.array( + [ + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + elif closure == "y_max": + # set points: + # set points: + right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) + + connection_front_right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_one, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_zero, + ], + ] + ) + + front = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_one, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_zero, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_one, + v_one, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_one, + v_zero, + ], + ] + ) + + connection_back_left = _np.array( + [ + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + ] + ) + + left = _np.array( + [ + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_top_left = _np.array( + [ + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_one, + v_one, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_one, + v_zero, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + back = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_bottom_right = _np.array( - [ - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + connection_back_right = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) - elif closure == "z_max": - # set points: - right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) + bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - connection_front_right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) + top = _np.array( + [ + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + ] + ) - front = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) + connection_front_bottom = _np.array( + [ + [ + v_one, + v_one, + v_zero, + ], + [ + v_zero, + v_one, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - connection_back_left = _np.array( - [ - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - ] - ) + connection_front_top = _np.array( + [ + [ + v_one, + v_one, + v_one, + ], + [ + v_zero, + v_one, + v_one, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + ] + ) + + connection_back_bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_back_top = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_top_right = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_front_left = _np.array( + [ + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_bottom_left = _np.array( + [ + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_bottom_right = _np.array( + [ + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + elif closure == "z_max": + # set points: + right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) + + connection_front_right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) + + front = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) + + connection_back_left = _np.array( + [ + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + ] + ) + + left = _np.array( + [ + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_front_left = _np.array( + [ + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + back = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_back_right = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) + + bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - left = _np.array( - [ - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + top = _np.array( + [ + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_one, + v_one, + ], + [ + v_zero, + v_one, + v_one, + ], + [ + v_one, + v_zero, + v_one, + ], + [ + v_zero, + v_zero, + v_one, + ], + ] + ) - connection_front_left = _np.array( - [ - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_front_bottom = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) - back = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_front_top = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_one, + ], + [ + v_zero, + v_one, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + ] + ) - connection_back_right = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) + connection_back_bottom = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + connection_back_top = _np.array( + [ + [ + v_one, + v_zero, + v_one, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_top_right = _np.array( + [ + [ + v_one, + v_one, + v_one, + ], + [ + v_one, + v_zero, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_top_left = _np.array( + [ + [ + v_zero, + v_one, + v_one, + ], + [ + v_zero, + v_zero, + v_one, + ], + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) + + connection_bottom_left = _np.array( + [ + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_bottom_right = _np.array( + [ + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + elif closure == "z_min": + # set points: + # set points: + right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) + + connection_front_right = _np.array( + [ + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) + + front = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + ] + ) + + connection_back_left = _np.array( + [ + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + ] + ) + + left = _np.array( + [ + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_front_left = _np.array( + [ + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_zero, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + -v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + back = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + ] + ) + + connection_back_right = _np.array( + [ + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + -v_wall_thickness + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half + v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + ] + ) + + bottom = _np.array( + [ + [ + v_one, + v_one, + v_zero, + ], + [ + v_zero, + v_one, + v_zero, + ], + [ + v_one, + v_zero, + v_zero, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + top = _np.array( + [ + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + ] + ) + + connection_front_bottom = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half - v_half_contact_length, + ], + [ + v_one, + v_one, + v_zero, + ], + [ + v_zero, + v_one, + v_zero, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_front_top = _np.array( + [ + [ + v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_one, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + ] + ) - top = _np.array( - [ - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_one, - v_one, - ], - [ - v_zero, - v_one, - v_one, - ], - [ - v_one, - v_zero, - v_one, - ], - [ - v_zero, - v_zero, - v_one, - ], - ] - ) + connection_back_bottom = _np.array( + [ + [ + v_one, + v_zero, + v_zero, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + v_one_half + v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half - v_half_contact_length, + v_zero, + v_one_half - v_half_contact_length, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + ], + ] + ) - connection_front_bottom = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) + connection_back_top = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + -v_half_contact_length + v_one_half, + v_zero, + v_one_half + v_half_contact_length, + ], + [ + v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + [ + -v_inner_half_contact_length + v_one_half, + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + ], + ] + ) - connection_front_top = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_one, - v_one, - ], - [ - v_zero, - v_one, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - ] - ) + connection_top_right = _np.array( + [ + [ + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half + v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) - connection_back_bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - ] - ) + connection_top_left = _np.array( + [ + [ + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + v_one, + ], + [ + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + v_one, + ], + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half + v_wall_thickness, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + ], + ] + ) - connection_back_top = _np.array( - [ - [ - v_one, - v_zero, - v_one, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - ] - ) + connection_bottom_left = _np.array( + [ + [ + v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, + ], + [ + v_zero, + v_one, + v_zero, + ], + [ + v_zero, + v_zero, + v_zero, + ], + [ + v_one_half - v_wall_thickness, + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_wall_thickness, + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half - v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + connection_bottom_right = _np.array( + [ + [ + v_one, + v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_one, + -v_half_contact_length + v_one_half, + v_one_half - v_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_wall_thickness + v_one_half, + -v_inner_half_contact_length + v_one_half, + v_one_half - v_inner_half_contact_length, + ], + [ + v_one, + v_one, + v_zero, + ], + [ + v_one, + v_zero, + v_zero, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half + v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + [ + v_one_half + v_inner_half_contact_length, + v_one_half - v_inner_half_contact_length, + v_one_half - v_wall_thickness, + ], + ] + ) + + for control_points in [ + right, + connection_front_right, + front, + connection_back_left, + left, + connection_front_left, + back, + connection_back_right, + bottom, + top, + connection_front_bottom, + connection_front_top, + connection_back_bottom, + connection_back_top, + connection_top_right, + connection_top_left, + connection_bottom_left, + connection_bottom_right, + ]: + spline_list.append( + _Bezier(degrees=[1, 1, 1], control_points=control_points) + ) + + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) + + return (splines, derivatives) + + def create_tile( + self, + parameters=None, + parameter_sensitivities=None, # TODO + contact_length=0.3, + closure=None, + **kwargs, # noqa ARG002 + ): + """Create a microtile based on the parameters that describe the wall + thicknesses. + + Thickness parameters are used to describe the inner radius of the + outward facing branches + + Parameters + ---------- + parameters : np.array + One evaluation point with one parameter is used. This parameter + describes the thickness of the wall. The parameters must be a + two-dimensional np.array, where the value must be between 0.01 + and 0.49 + parameter_sensitivities: np.ndarray + Describes the parameter sensitivities with respect to some design + variable. In case the design variables directly apply to the + parameter itself, they evaluate as delta_ij + contact_length : float + the length of the wall that contacts the other microstructure + closure : str + parametric dimension that needs to be closed, given in the form + "x_min", "x_max", etc. - connection_top_right = _np.array( - [ - [ - v_one, - v_one, - v_one, - ], - [ - v_one, - v_zero, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] + Returns + ------- + microtile_list : list(splines) + derivative_list : list / None + """ + + if not isinstance(contact_length, float): + raise ValueError("Invalid Type for radius") + + if not ((contact_length > 0) and (contact_length < 0.99)): + raise ValueError("The length of a side must be in (0.01, 0.99)") + + if parameters is None: + self._logd("Setting parameters to default values (0.2)") + parameters = _np.array( + _np.ones( + (len(self._evaluation_points), self._n_info_per_eval_point) + ) + * 0.2 ) - connection_top_left = _np.array( - [ - [ - v_zero, - v_one, - v_one, - ], - [ - v_zero, - v_zero, - v_one, - ], - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] + self.check_params(parameters) + self.check_param_derivatives(parameter_sensitivities) + + if parameter_sensitivities is not None: + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None + + if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): + raise ValueError( + "The thickness of the wall must be in (0.01 and 0.49)" ) - connection_bottom_left = _np.array( - [ - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] + if closure is not None: + return self._closing_tile( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + contact_length=contact_length, + closure=closure, + **kwargs, ) - connection_bottom_right = _np.array( - [ - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], + splines = [] + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + v_wall_thickness = parameters[0, 0] + v_zero = 0.0 + v_one_half = 0.5 + v_one = 1.0 + v_half_contact_length = contact_length * 0.5 + v_inner_half_contact_length = contact_length * v_wall_thickness + else: + v_wall_thickness = parameter_sensitivities[ + 0, 0, i_derivative - 1 ] - ) + v_zero = 0.0 + v_one_half = 0.0 + v_one = 0.0 + v_half_contact_length = 0.0 + v_inner_half_contact_length = contact_length * v_wall_thickness + + spline_list = [] - elif closure == "z_min": - # set points: # set points: right = _np.array( [ @@ -4531,23 +5486,23 @@ def _closing_tile( bottom = _np.array( [ [ - v_one, - v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, v_zero, ], [ - v_zero, - v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, v_zero, ], [ - v_one, - v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, v_zero, ], [ - v_zero, - v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, v_zero, ], [ @@ -4631,13 +5586,13 @@ def _closing_tile( v_one_half - v_half_contact_length, ], [ - v_one, - v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, v_zero, ], [ - v_zero, - v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, v_zero, ], [ @@ -4711,13 +5666,13 @@ def _closing_tile( connection_back_bottom = _np.array( [ [ - v_one, - v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, v_zero, ], [ - v_zero, - v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, v_zero, ], [ @@ -4901,13 +5856,13 @@ def _closing_tile( v_one_half - v_half_contact_length, ], [ - v_zero, - v_one, + v_one_half - v_half_contact_length, + v_one_half + v_half_contact_length, v_zero, ], [ - v_zero, - v_zero, + v_one_half - v_half_contact_length, + v_one_half - v_half_contact_length, v_zero, ], [ @@ -4956,13 +5911,13 @@ def _closing_tile( v_one_half - v_inner_half_contact_length, ], [ - v_one, - v_one, + v_one_half + v_half_contact_length, + v_one_half + v_half_contact_length, v_zero, ], [ - v_one, - v_zero, + v_one_half + v_half_contact_length, + v_one_half - v_half_contact_length, v_zero, ], [ @@ -4978,1018 +5933,33 @@ def _closing_tile( ] ) - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_bottom_left) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_bottom_right) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_bottom) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_bottom) - ) - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_top) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_top) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_top_right) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_left) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=right)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_right) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=back)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_left) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=left)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_top_left) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=front)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_right) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=bottom)) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=top)) - - return (spline_list, None) - - def create_tile( - self, - parameters=None, - parameter_sensitivities=None, # TODO - contact_length=0.3, - closure=None, - **kwargs, # noqa ARG002 - ): - """Create a microtile based on the parameters that describe the wall - thicknesses. - - Thickness parameters are used to describe the inner radius of the - outward facing branches - - Parameters - ---------- - parameters : np.array - One evaluation point with one parameter is used. This parameter - describes the thickness of the wall. The parameters must be a - two-dimensional np.array, where the value must be between 0.01 - and 0.49 - parameter_sensitivities: np.ndarray - Describes the parameter sensitivities with respect to some design - variable. In case the design variables directly apply to the - parameter itself, they evaluate as delta_ij - contact_length : float - the length of the wall that contacts the other microstructure - closure : str - parametric dimension that needs to be closed, given in the form - "x_min", "x_max", etc. - - Returns - ------- - microtile_list : list(splines) - derivative_list : list / None - """ - - if not isinstance(contact_length, float): - raise ValueError("Invalid Type for radius") - - if not ((contact_length > 0) and (contact_length < 0.99)): - raise ValueError("The length of a side must be in (0.01, 0.99)") - - if parameters is None: - self._logd("Setting parameters to default values (0.2)") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) + for control_points in [ + right, + connection_front_right, + front, + connection_back_left, + left, + connection_front_left, + back, + connection_back_right, + bottom, + top, + connection_front_bottom, + connection_front_top, + connection_back_bottom, + connection_back_top, + connection_top_right, + connection_top_left, + connection_bottom_left, + connection_bottom_right, + ]: + spline_list.append( + _Bezier(degrees=[1, 1, 1], control_points=control_points) ) - * 0.2 - ) - - self.check_params(parameters) - - if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" - ) - - if closure is not None: - return self._closing_tile( - parameters=parameters, - parameter_sensitivities=parameter_sensitivities, - contact_length=contact_length, - closure=closure, - **kwargs, - ) - - v_wall_thickness = parameters[0, 0] - v_zero = 0.0 - v_one_half = 0.5 - v_one = 1.0 - v_half_contact_length = contact_length * 0.5 - v_half_contact_length = contact_length * 0.5 - v_inner_half_contact_length = contact_length * parameters[0, 0] - - spline_list = [] - - # set points: - right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) - - connection_front_right = _np.array( - [ - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) - - front = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - ] - ) - - connection_back_left = _np.array( - [ - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - ] - ) - - left = _np.array( - [ - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_front_left = _np.array( - [ - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_zero, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - -v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - back = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_back_right = _np.array( - [ - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - -v_wall_thickness + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half + v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - ] - ) - - bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - top = _np.array( - [ - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - ] - ) - - connection_front_bottom = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - connection_front_top = _np.array( - [ - [ - v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_one, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - ] - ) - - connection_back_bottom = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_zero, - v_one_half - v_half_contact_length, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - ], - ] - ) - - connection_back_top = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - -v_half_contact_length + v_one_half, - v_zero, - v_one_half + v_half_contact_length, - ], - [ - v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - [ - -v_inner_half_contact_length + v_one_half, - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_top_right = _np.array( - [ - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half + v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_top_left = _np.array( - [ - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_one, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_one, - ], - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half + v_wall_thickness, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - ], - ] - ) - - connection_bottom_left = _np.array( - [ - [ - v_zero, - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_zero, - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - ], - [ - v_one_half - v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half - v_wall_thickness, - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_wall_thickness, - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half - v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - connection_bottom_right = _np.array( - [ - [ - v_one, - v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_one, - -v_half_contact_length + v_one_half, - v_one_half - v_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_wall_thickness + v_one_half, - -v_inner_half_contact_length + v_one_half, - v_one_half - v_inner_half_contact_length, - ], - [ - v_one_half + v_half_contact_length, - v_one_half + v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_half_contact_length, - v_one_half - v_half_contact_length, - v_zero, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half + v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - [ - v_one_half + v_inner_half_contact_length, - v_one_half - v_inner_half_contact_length, - v_one_half - v_wall_thickness, - ], - ] - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=right)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_right) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=back)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_left) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=left)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_left) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=front)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_right) - ) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=bottom)) - - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=top)) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_top) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_front_bottom) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_bottom) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_back_top) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_top_right) - ) - - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_top_left) - ) - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_bottom_left) - ) - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=connection_bottom_right) - ) + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) - return (spline_list, None) + return (splines, derivatives) From 88ba9dc1b66e11498f794b2c6a055324eb2bdb4f Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 26 Aug 2024 15:38:20 +0200 Subject: [PATCH 12/52] Fix typo which led to error --- examples/show_microstructures.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/show_microstructures.py b/examples/show_microstructures.py index 35d6d22b8..14d74dc04 100644 --- a/examples/show_microstructures.py +++ b/examples/show_microstructures.py @@ -346,13 +346,13 @@ def foo(x): generator.parametrization_function = foo inverse_microstructure = generator.create( - closing_face="z", seperator_distance=0.4, center_expansion=1.3 + closing_face="z", separator_distance=0.4, center_expansion=1.3 ) # Plot the results _, showables_inverse = generator.show( closing_face="z", - seperator_distance=0.4, + separator_distance=0.4, center_expansion=1.3, title="Parametrized Inverse Microstructure", control_points=False, @@ -365,7 +365,7 @@ def foo(x): # Corresponding Structure generator.microtile = splinepy.microstructure.tiles.get("Cross3D") microstructure = generator.create( - closing_face="z", seperator_distance=0.4, center_expansion=1.3 + closing_face="z", separator_distance=0.4, center_expansion=1.3 ) _, showables = generator.show( closing_face="z", From 601994a6978d70c6a94bd1effadbd6bc31dc818b Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 26 Aug 2024 15:56:20 +0200 Subject: [PATCH 13/52] Add derivatives for HollowOctagonExtrude tile w/o closure --- .../tiles/hollow_octagon_extrude.py | 289 ++++++++++-------- 1 file changed, 158 insertions(+), 131 deletions(-) diff --git a/splinepy/microstructure/tiles/hollow_octagon_extrude.py b/splinepy/microstructure/tiles/hollow_octagon_extrude.py index 1c935be0f..16359ef49 100644 --- a/splinepy/microstructure/tiles/hollow_octagon_extrude.py +++ b/splinepy/microstructure/tiles/hollow_octagon_extrude.py @@ -18,7 +18,8 @@ class HollowOctagonExtrude(_TileBase): _para_dim = 3 _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 1 - _sensitivities_implemented = False + _sensitivities_implemented = True + # TODO: closure in create_tile still missing _closure_directions = ["x_min", "x_max", "y_min", "y_max"] _parameter_bounds = [[0.0, 0.5]] _parameters_shape = (1, 1) @@ -26,7 +27,7 @@ class HollowOctagonExtrude(_TileBase): def create_tile( self, parameters=None, - parameter_sensitivities=None, # TODO + parameter_sensitivities=None, contact_length=0.2, **kwargs, # noqa ARG002 ): @@ -70,11 +71,14 @@ def create_tile( ) if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None self.check_params(parameters) + self.check_param_derivatives(parameter_sensitivities) v_h_void = parameters[0, 0] if not ((v_h_void > 0.0) and (v_h_void < 0.5)): @@ -82,142 +86,165 @@ def create_tile( "The thickness of the wall must be in (0.0 and 0.5)" ) - v_zero = 0.0 - v_one_half = 0.5 - v_one = 1.0 - v_outer_c_h = contact_length * 0.5 - v_inner_c_h = contact_length * parameters[0, 0] - - spline_list = [] - - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_zero], - [v_one, -v_outer_c_h + v_one_half, 0.0], - [v_h_void + v_one_half, v_inner_c_h + v_one_half, 0.0], - [v_one, v_outer_c_h + v_one_half, 0.0], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], - [v_one, -v_outer_c_h + v_one_half, v_one], - [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], - [v_one, v_outer_c_h + v_one_half, v_one], - ] - ) - - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_zero], - [v_one, v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], - [v_outer_c_h + v_one_half, v_one, v_zero], - [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], - [v_one, v_outer_c_h + v_one_half, v_one], - [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], - [v_outer_c_h + v_one_half, v_one, v_one], - ] - ) - - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], - [v_outer_c_h + v_one_half, v_one, v_zero], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], - [-v_outer_c_h + v_one_half, v_one, v_zero], - [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], - [v_outer_c_h + v_one_half, v_one, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], - [-v_outer_c_h + v_one_half, v_one, v_one], - ] - ) + splines = [] + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + v_zero = 0.0 + v_one_half = 0.5 + v_one = 1.0 + v_outer_c_h = contact_length * 0.5 + v_inner_c_h = contact_length * v_h_void + else: + v_zero = 0.0 + v_one_half = 0.0 + v_one = 0.0 + v_h_void = parameter_sensitivities[0, 0, i_derivative - 1] + v_outer_c_h = 0.0 + v_inner_c_h = contact_length * v_h_void + + spline_list = [] - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_zero], - [v_zero, -v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_zero], - [-v_outer_c_h + v_one_half, v_zero, v_zero], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], - [v_zero, -v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], - [-v_outer_c_h + v_one_half, v_zero, v_one], - ] - ) - - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half, v_zero], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_zero], - [v_zero, v_outer_c_h + v_one_half, v_zero], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_zero], - [v_zero, -v_outer_c_h + v_one_half, v_one], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], - [v_zero, v_outer_c_h + v_one_half, v_one], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], - ] - ) - - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half, v_zero], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_zero], - [-v_outer_c_h + v_one_half, v_one, v_zero], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], - [v_zero, v_outer_c_h + v_one_half, v_one], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], - [-v_outer_c_h + v_one_half, v_one, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], - ] - ) - - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_zero], - [-v_outer_c_h + v_one_half, v_zero, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_zero], - [v_outer_c_h + v_one_half, v_zero, v_one], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], - [-v_outer_c_h + v_one_half, v_zero, v_one], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], - ] - ) - - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_zero], - [v_outer_c_h + v_one_half, v_zero, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_zero], - [v_one, -v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], - [v_outer_c_h + v_one_half, v_zero, v_one], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], - [v_one, -v_outer_c_h + v_one_half, v_one], - ] - ) + # set points: + right = _np.array( + [ + [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_zero], + [v_one, -v_outer_c_h + v_one_half, 0.0], + [v_h_void + v_one_half, v_inner_c_h + v_one_half, 0.0], + [v_one, v_outer_c_h + v_one_half, 0.0], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], + [v_one, -v_outer_c_h + v_one_half, v_one], + [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], + [v_one, v_outer_c_h + v_one_half, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=right)) + right_top = _np.array( + [ + [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_zero], + [v_one, v_outer_c_h + v_one_half, v_zero], + [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], + [v_outer_c_h + v_one_half, v_one, v_zero], + [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], + [v_one, v_outer_c_h + v_one_half, v_one], + [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], + [v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=right_top) - ) + top = _np.array( + [ + [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], + [v_outer_c_h + v_one_half, v_one, v_zero], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], + [v_outer_c_h + v_one_half, v_one, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], + [-v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=bottom)) + bottom_left = _np.array( + [ + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], + [-v_outer_c_h + v_one_half, v_zero, v_one], + ] + ) - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=bottom_left) - ) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_outer_c_h + v_one_half, v_zero], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_zero], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [-v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], + [v_zero, v_outer_c_h + v_one_half, v_one], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=left)) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half, v_zero], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_zero], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_zero], + [v_zero, v_outer_c_h + v_one_half, v_one], + [-v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], + [-v_outer_c_h + v_one_half, v_one, v_one], + [-v_inner_c_h + v_one_half, v_h_void + v_one_half, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=top_left)) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero, v_zero], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_zero], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_zero, v_one], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], + [-v_outer_c_h + v_one_half, v_zero, v_one], + [-v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1, 1], control_points=top)) + bottom_right = _np.array( + [ + [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_zero], + [v_outer_c_h + v_one_half, v_zero, v_zero], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_zero], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [v_inner_c_h + v_one_half, -v_h_void + v_one_half, v_one], + [v_outer_c_h + v_one_half, v_zero, v_one], + [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], + [v_one, -v_outer_c_h + v_one_half, v_one], + ] + ) + + for control_points in [ + right, + right_top, + top, + bottom_left, + left, + top_left, + bottom, + bottom_right, + ]: + spline_list.append( + _Bezier(degrees=[1, 1, 1], control_points=control_points) + ) - spline_list.append( - _Bezier(degrees=[1, 1, 1], control_points=bottom_right) - ) + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) - return (spline_list, None) + return (splines, derivatives) def _closing_tile( self, From 4d3f58cc9d20f8b519a7f41cfd4be1555708eebd Mon Sep 17 00:00:00 2001 From: markriegler Date: Tue, 27 Aug 2024 10:19:32 +0200 Subject: [PATCH 14/52] Add test for tile derivatives with tile closure --- tests/test_microstructure.py | 140 ++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 69 deletions(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 1a2b54371..73f8e1b72 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -176,16 +176,25 @@ def test_tile_closure(): check_control_points(tile_patches) -def test_tile_derivatives(np_rng, heps=1e-8): - """Testing the correctness of the tile derivatives using Finite Differences +def test_tile_derivatives(np_rng, heps=1e-8, n_test_points=4): + """Testing the correctness of the tile derivatives using Finite Differences. + This includes every closure and no closure, every parameter and every patch + by evaluating at random points and for random parameters. Parameters --------- heps: float Perturbation size for finite difference evaluation + n_test_points: int + Number of testing points in the parametric domain """ - # TODO: right now Chi, EllipsVoid and CubeVoid show wrong derivatives - skip_classes = [ms.tiles.Chi, ms.tiles.EllipsVoid, ms.tiles.CubeVoid] + # TODO: right now Chi, EllipsVoid, CubeVoid and InverseCross show wrong derivatives + skip_classes = [ + ms.tiles.Chi, + ms.tiles.EllipsVoid, + ms.tiles.CubeVoid, + ms.tiles.InverseCross3D, + ] for tile_class in all_tile_classes: # TODO: right now skip classes with faultily implemented derivatives @@ -204,76 +213,69 @@ def test_tile_derivatives(np_rng, heps=1e-8): ) * np.ptp(parameter_bounds, axis=1) parameters = parameters.reshape(tile_creator._parameters_shape) - # Create 3D identity matrix + # Test no closure as well as ... + closure_directions = [None] + # ... every closure implemented + if "_closure_directions" in dir(tile_creator): + closure_directions += tile_creator._closure_directions + + # Retrieve shape values of parameters n_eval_points = tile_creator._evaluation_points.shape[0] n_info_per_eval_point = tile_creator._n_info_per_eval_point - parameter_sensitivities = np.zeros( - (n_eval_points, n_info_per_eval_point, 1) - ) - idx = np.arange(np.min(parameter_sensitivities.shape)) - parameter_sensitivities[idx, idx, :] = 1 - splines, derivatives = tile_creator.create_tile( - parameters=parameters, - parameter_sensitivities=parameter_sensitivities, - ) - # Evaluate splines and derivatives at multiple random points - eval_points = np_rng.random((4, splines[0].para_dim)) - deriv_evaluations = [ - deriv.evaluate(eval_points) for deriv in derivatives[0] - ] - spline_orig_evaluations = [ - spl.evaluate(eval_points) for spl in splines - ] - parameters_perturbed = parameters.copy() - parameters_perturbed += heps - splines_perturbed, _ = tile_creator.create_tile( - parameters=parameters_perturbed - ) - spline_perturbed_evaluations = [ - spl.evaluate(eval_points) for spl in splines_perturbed - ] - fd_sensitivities = [ - (spl_pert - spl_orig) / heps - for spl_pert, spl_orig in zip( - spline_perturbed_evaluations, spline_orig_evaluations + # Test each closure direction + for closure in closure_directions: + # Evaluate tile with given parameter and closure configuration + splines_orig, _ = tile_creator.create_tile( + parameters=parameters, closure=closure ) - ] - - # Go through all the parameters individually - for i_parameter in range(n_info_per_eval_point): - # Get derivatives w.r.t. one parameter - parameter_sensitivities = np.zeros( - (n_eval_points, n_info_per_eval_point, 1) + # Set evaluation points as 4 random spots in the parametric space + eval_points = np_rng.random( + (n_test_points, splines_orig[0].para_dim) ) - parameter_sensitivities[:, i_parameter, :] = 1 - _, derivatives = tile_creator.create_tile( - parameters=parameters, - parameter_sensitivities=parameter_sensitivities, - ) - deriv_evaluations = [ - deriv.evaluate(eval_points) for deriv in derivatives[0] + splines_orig_evaluations = [ + spl.evaluate(eval_points) for spl in splines_orig ] - # Perform finite difference evaluation - parameters_perturbed = parameters.copy() - parameters_perturbed[:, i_parameter] += heps - splines_perturbed, _ = tile_creator.create_tile( - parameters=parameters_perturbed - ) - spline_perturbed_evaluations = [ - spl.evaluate(eval_points) for spl in splines_perturbed - ] - fd_sensitivities = [ - (spl_pert - spl_orig) / heps - for spl_pert, spl_orig in zip( - spline_perturbed_evaluations, spline_orig_evaluations + # Go through all the parameters individually + for i_parameter in range(n_info_per_eval_point): + # Get derivatives w.r.t. one parameter + parameter_sensitivities = np.zeros( + (n_eval_points, n_info_per_eval_point, 1) ) - ] - # Check every patch - for deriv_orig, deriv_fd in zip( - deriv_evaluations, fd_sensitivities - ): - assert np.allclose(deriv_orig, deriv_fd), ( - "Implemented derivative calculation does not match the derivative " - + "obtained using Finite Differences" + parameter_sensitivities[:, i_parameter, :] = 1 + _, derivatives = tile_creator.create_tile( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + closure=closure, + ) + deriv_evaluations = [ + deriv.evaluate(eval_points) for deriv in derivatives[0] + ] + # Perform finite difference evaluation + parameters_perturbed = parameters.copy() + parameters_perturbed[:, i_parameter] += heps + splines_perturbed, _ = tile_creator.create_tile( + parameters=parameters_perturbed, closure=closure ) + spline_perturbed_evaluations = [ + spl.evaluate(eval_points) for spl in splines_perturbed + ] + # Evaluate finite difference gradient + fd_sensitivities = [ + (spl_pert - spl_orig) / heps + for spl_pert, spl_orig in zip( + spline_perturbed_evaluations, splines_orig_evaluations + ) + ] + # Check every patch + n_patches = len(fd_sensitivities) + for i_patch, deriv_orig, deriv_fd in zip( + range(n_patches), deriv_evaluations, fd_sensitivities + ): + assert np.allclose(deriv_orig, deriv_fd), ( + "Implemented derivative calculation for tile class" + + f"{tile_class}, parameter " + + f"{i_parameter+1}/{n_info_per_eval_point} at patch " + + f"{i_patch+1}/{n_patches} does not match the derivative " + + "obtained using Finite Differences" + ) From d46121b5ab4370f6748e06e3a518ae4b23ade1b0 Mon Sep 17 00:00:00 2001 From: markriegler Date: Tue, 27 Aug 2024 11:20:15 +0200 Subject: [PATCH 15/52] Restructure and add derivatives for InverseCross3D tile (WIP) --- .../microstructure/tiles/inverse_cross_3d.py | 1368 +++++++++-------- 1 file changed, 712 insertions(+), 656 deletions(-) diff --git a/splinepy/microstructure/tiles/inverse_cross_3d.py b/splinepy/microstructure/tiles/inverse_cross_3d.py index 6e4f0e010..4af1b2ef6 100644 --- a/splinepy/microstructure/tiles/inverse_cross_3d.py +++ b/splinepy/microstructure/tiles/inverse_cross_3d.py @@ -32,7 +32,8 @@ class InverseCross3D(_TileBase): ] ) _n_info_per_eval_point = 1 - _sensitivities_implemented = False + # TODO: implemented sensitivities are not correct + _sensitivities_implemented = True _closure_directions = ["z_min", "z_max"] _parameter_bounds = [[0.2, 0.3]] * 6 # For default values _parameters_shape = (6, 1) @@ -44,7 +45,7 @@ def _closing_tile( closure=None, boundary_width=0.1, filling_height=0.5, - separator_distance=None, + separator_distance=0.3, **kwargs, # noqa ARG002 ): """Create a closing tile to match with closed surface. @@ -73,10 +74,6 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - # Set default values - if separator_distance is None: - separator_distance = 0.3 - if parameters is None: self._logd("Tile request is not parametrized, setting default 0.2") parameters = ( @@ -893,7 +890,7 @@ def create_tile( self, parameters=None, parameter_sensitivities=None, - separator_distance=None, + separator_distance=0.3, center_expansion=1.0, closure=None, **kwargs, # noqa ARG002 @@ -930,13 +927,6 @@ def create_tile( if not ((center_expansion > 0.5) and (center_expansion < 1.5)): raise ValueError("Center Expansion must be in (.5, 1.5)") - # Set default values - if separator_distance is None: - separator_distance = 0.3 - - if center_expansion is None: - center_expansion = 1.0 - # Check if all radii are in allowed range max_radius = min(0.5, (0.5 / center_expansion)) max_radius = min(max_radius, separator_distance) @@ -953,11 +943,14 @@ def create_tile( ) if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None self.check_params(parameters) + self.check_param_derivatives(parameter_sensitivities) if _np.any(parameters < min_radius) or _np.any( parameters > max_radius @@ -976,644 +969,707 @@ def create_tile( **kwargs, ) - [ - x_min_r, - x_max_r, - y_min_r, - y_max_r, - z_min_r, - z_max_r, - ] = parameters.flatten() - - # center radius - center_r = _np.sum(parameters) / 6.0 * center_expansion - - # Auxiliary values for smooothing (mid-branch thickness) - [ - aux_x_min, - aux_x_max, - aux_y_min, - aux_y_max, - aux_z_min, - aux_z_max, - ] = _np.minimum(parameters.ravel(), center_r) - # Branch midlength - hd_center = 0.5 * (0.5 + center_r) - aux_column_width = 0.5 - 2 * (0.5 - separator_distance) + splines = [] + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + [ + x_min_r, + x_max_r, + y_min_r, + y_max_r, + z_min_r, + z_max_r, + ] = parameters.flatten() + + # center radius + center_r = _np.sum(parameters) / 6.0 * center_expansion + + # Auxiliary values for smooothing (mid-branch thickness) + [ + aux_x_min, + aux_x_max, + aux_y_min, + aux_y_max, + aux_z_min, + aux_z_max, + ] = _np.minimum(parameters.ravel(), center_r) + # Branch midlength + hd_center = 0.5 * (0.5 + center_r) + aux_column_width = 0.5 - 2 * (0.5 - separator_distance) + + v_one_half = 0.5 + center_point = _np.array([0.5, 0.5, 0.5]) + else: + sensitivities_i = parameter_sensitivities[ + :, 0, i_derivative - 1 + ] + [ + x_min_r, + x_max_r, + y_min_r, + y_max_r, + z_min_r, + z_max_r, + ] = sensitivities_i + + center_r = _np.mean(sensitivities_i) * center_expansion + [ + aux_x_min, + aux_x_max, + aux_y_min, + aux_y_max, + aux_z_min, + aux_z_max, + ] = _np.where( + parameters.ravel() + < _np.mean(parameters.ravel()) * center_expansion, + sensitivities_i, + center_r, + ) + # Branch midlength + hd_center = center_r / 2.0 + aux_column_width = 0.0 + v_one_half = 0.0 + center_point = _np.zeros(3) + + # Init return type + spline_list = [] + + # Start with branch interconnections + x_min_y_min = ( + _np.array( + [ + [-v_one_half, -v_one_half, -aux_column_width], + [-separator_distance, -v_one_half, -aux_column_width], + [-y_min_r, -v_one_half, -y_min_r], + [-v_one_half, -separator_distance, -aux_column_width], + [-hd_center, -hd_center, -aux_column_width], + [-aux_y_min, -hd_center, -aux_y_min], + [-v_one_half, -x_min_r, -x_min_r], + [-hd_center, -aux_x_min, -aux_x_min], + [-center_r, -center_r, -center_r], + [-v_one_half, -v_one_half, aux_column_width], + [-separator_distance, -v_one_half, aux_column_width], + [-y_min_r, -v_one_half, y_min_r], + [-v_one_half, -separator_distance, aux_column_width], + [-hd_center, -hd_center, aux_column_width], + [-aux_y_min, -hd_center, aux_y_min], + [-v_one_half, -x_min_r, x_min_r], + [-hd_center, -aux_x_min, aux_x_min], + [-center_r, -center_r, center_r], + ] + ) + + center_point + ) - # Init return type - spline_list = [] + x_max_y_min = ( + _np.array( + [ + [y_min_r, -v_one_half, -y_min_r], + [separator_distance, -v_one_half, -aux_column_width], + [v_one_half, -v_one_half, -aux_column_width], + [aux_y_min, -hd_center, -aux_y_min], + [hd_center, -hd_center, -aux_column_width], + [v_one_half, -separator_distance, -aux_column_width], + [center_r, -center_r, -center_r], + [hd_center, -aux_x_max, -aux_x_max], + [v_one_half, -x_max_r, -x_max_r], + [y_min_r, -v_one_half, y_min_r], + [separator_distance, -v_one_half, aux_column_width], + [v_one_half, -v_one_half, aux_column_width], + [aux_y_min, -hd_center, aux_y_min], + [hd_center, -hd_center, aux_column_width], + [v_one_half, -separator_distance, aux_column_width], + [center_r, -center_r, center_r], + [hd_center, -aux_x_max, aux_x_max], + [v_one_half, -x_max_r, x_max_r], + ] + ) + + center_point + ) + + x_min_y_max = ( + _np.array( + [ + [-v_one_half, x_min_r, -x_min_r], + [-hd_center, aux_x_min, -aux_x_min], + [-center_r, center_r, -center_r], + [-v_one_half, separator_distance, -aux_column_width], + [-hd_center, hd_center, -aux_column_width], + [-aux_y_max, hd_center, -aux_y_max], + [-v_one_half, v_one_half, -aux_column_width], + [-separator_distance, v_one_half, -aux_column_width], + [-y_max_r, v_one_half, -y_max_r], + [-v_one_half, x_min_r, x_min_r], + [-hd_center, aux_x_min, aux_x_min], + [-center_r, center_r, center_r], + [-v_one_half, separator_distance, aux_column_width], + [-hd_center, hd_center, aux_column_width], + [-aux_y_max, hd_center, aux_y_max], + [-v_one_half, v_one_half, aux_column_width], + [-separator_distance, v_one_half, aux_column_width], + [-y_max_r, v_one_half, y_max_r], + ] + ) + + center_point + ) + + x_max_y_max = ( + _np.array( + [ + [center_r, center_r, -center_r], + [hd_center, aux_x_max, -aux_x_max], + [v_one_half, x_max_r, -x_max_r], + [aux_y_max, hd_center, -aux_y_max], + [hd_center, hd_center, -aux_column_width], + [v_one_half, separator_distance, -aux_column_width], + [y_max_r, v_one_half, -y_max_r], + [separator_distance, v_one_half, -aux_column_width], + [v_one_half, v_one_half, -aux_column_width], + [center_r, center_r, center_r], + [hd_center, aux_x_max, aux_x_max], + [v_one_half, x_max_r, x_max_r], + [aux_y_max, hd_center, aux_y_max], + [hd_center, hd_center, aux_column_width], + [v_one_half, separator_distance, aux_column_width], + [y_max_r, v_one_half, y_max_r], + [separator_distance, v_one_half, aux_column_width], + [v_one_half, v_one_half, aux_column_width], + ] + ) + + center_point + ) + + x_min_z_min = ( + _np.array( + [ + [-v_one_half, -aux_column_width, -v_one_half], + [-separator_distance, -aux_column_width, -v_one_half], + [-z_min_r, -z_min_r, -v_one_half], + [-v_one_half, aux_column_width, -v_one_half], + [-separator_distance, aux_column_width, -v_one_half], + [-z_min_r, z_min_r, -v_one_half], + [-v_one_half, -aux_column_width, -separator_distance], + [-hd_center, -aux_column_width, -hd_center], + [-aux_z_min, -aux_z_min, -hd_center], + [-v_one_half, aux_column_width, -separator_distance], + [-hd_center, aux_column_width, -hd_center], + [-aux_z_min, aux_z_min, -hd_center], + [-v_one_half, -x_min_r, -x_min_r], + [-hd_center, -aux_x_min, -aux_x_min], + [-center_r, -center_r, -center_r], + [-v_one_half, x_min_r, -x_min_r], + [-hd_center, aux_x_min, -aux_x_min], + [-center_r, center_r, -center_r], + ] + ) + + center_point + ) + + x_max_z_min = ( + _np.array( + [ + [z_min_r, -z_min_r, -v_one_half], + [separator_distance, -aux_column_width, -v_one_half], + [v_one_half, -aux_column_width, -v_one_half], + [z_min_r, z_min_r, -v_one_half], + [separator_distance, aux_column_width, -v_one_half], + [v_one_half, aux_column_width, -v_one_half], + [aux_z_min, -aux_z_min, -hd_center], + [hd_center, -aux_column_width, -hd_center], + [v_one_half, -aux_column_width, -separator_distance], + [aux_z_min, aux_z_min, -hd_center], + [hd_center, aux_column_width, -hd_center], + [v_one_half, aux_column_width, -separator_distance], + [center_r, -center_r, -center_r], + [hd_center, -aux_x_max, -aux_x_max], + [v_one_half, -x_max_r, -x_max_r], + [center_r, center_r, -center_r], + [hd_center, aux_x_max, -aux_x_max], + [v_one_half, x_max_r, -x_max_r], + ] + ) + + center_point + ) + + x_min_z_max = ( + _np.array( + [ + [-v_one_half, -x_min_r, x_min_r], + [-hd_center, -aux_x_min, aux_x_min], + [-center_r, -center_r, center_r], + [-v_one_half, x_min_r, x_min_r], + [-hd_center, aux_x_min, aux_x_min], + [-center_r, center_r, center_r], + [-v_one_half, -aux_column_width, separator_distance], + [-hd_center, -aux_column_width, hd_center], + [-aux_z_max, -aux_z_max, hd_center], + [-v_one_half, aux_column_width, separator_distance], + [-hd_center, aux_column_width, hd_center], + [-aux_z_max, aux_z_max, hd_center], + [-v_one_half, -aux_column_width, v_one_half], + [-separator_distance, -aux_column_width, v_one_half], + [-z_max_r, -z_max_r, v_one_half], + [-v_one_half, aux_column_width, v_one_half], + [-separator_distance, aux_column_width, v_one_half], + [-z_max_r, z_max_r, v_one_half], + ] + ) + + center_point + ) + + x_max_z_max = ( + _np.array( + [ + [center_r, -center_r, center_r], + [hd_center, -aux_x_max, aux_x_max], + [v_one_half, -x_max_r, x_max_r], + [center_r, center_r, center_r], + [hd_center, aux_x_max, aux_x_max], + [v_one_half, x_max_r, x_max_r], + [aux_z_max, -aux_z_max, hd_center], + [hd_center, -aux_column_width, hd_center], + [v_one_half, -aux_column_width, separator_distance], + [aux_z_max, aux_z_max, hd_center], + [hd_center, aux_column_width, hd_center], + [v_one_half, aux_column_width, separator_distance], + [z_max_r, -z_max_r, v_one_half], + [separator_distance, -aux_column_width, v_one_half], + [v_one_half, -aux_column_width, v_one_half], + [z_max_r, z_max_r, v_one_half], + [separator_distance, aux_column_width, v_one_half], + [v_one_half, aux_column_width, v_one_half], + ] + ) + + center_point + ) + + y_min_z_min = ( + _np.array( + [ + [-aux_column_width, -v_one_half, -v_one_half], + [aux_column_width, -v_one_half, -v_one_half], + [-aux_column_width, -separator_distance, -v_one_half], + [aux_column_width, -separator_distance, -v_one_half], + [-z_min_r, -z_min_r, -v_one_half], + [z_min_r, -z_min_r, -v_one_half], + [-aux_column_width, -v_one_half, -separator_distance], + [aux_column_width, -v_one_half, -separator_distance], + [-aux_column_width, -hd_center, -hd_center], + [aux_column_width, -hd_center, -hd_center], + [-aux_z_min, -aux_z_min, -hd_center], + [aux_z_min, -aux_z_min, -hd_center], + [-y_min_r, -v_one_half, -y_min_r], + [y_min_r, -v_one_half, -y_min_r], + [-aux_y_min, -hd_center, -aux_y_min], + [aux_y_min, -hd_center, -aux_y_min], + [-center_r, -center_r, -center_r], + [center_r, -center_r, -center_r], + ] + ) + + center_point + ) + + y_max_z_min = ( + _np.array( + [ + [-z_min_r, z_min_r, -v_one_half], + [z_min_r, z_min_r, -v_one_half], + [-aux_column_width, separator_distance, -v_one_half], + [aux_column_width, separator_distance, -v_one_half], + [-aux_column_width, v_one_half, -v_one_half], + [aux_column_width, v_one_half, -v_one_half], + [-aux_z_min, aux_z_min, -hd_center], + [aux_z_min, aux_z_min, -hd_center], + [-aux_column_width, hd_center, -hd_center], + [aux_column_width, hd_center, -hd_center], + [-aux_column_width, v_one_half, -separator_distance], + [aux_column_width, v_one_half, -separator_distance], + [-center_r, center_r, -center_r], + [center_r, center_r, -center_r], + [-aux_y_max, hd_center, -aux_y_max], + [aux_y_max, hd_center, -aux_y_max], + [-y_max_r, v_one_half, -y_max_r], + [y_max_r, v_one_half, -y_max_r], + ] + ) + + center_point + ) + + y_min_z_max = ( + _np.array( + [ + [-y_min_r, -v_one_half, y_min_r], + [y_min_r, -v_one_half, y_min_r], + [-aux_y_min, -hd_center, aux_y_min], + [aux_y_min, -hd_center, aux_y_min], + [-center_r, -center_r, center_r], + [center_r, -center_r, center_r], + [-aux_column_width, -v_one_half, separator_distance], + [aux_column_width, -v_one_half, separator_distance], + [-aux_column_width, -hd_center, hd_center], + [aux_column_width, -hd_center, hd_center], + [-aux_z_max, -aux_z_max, hd_center], + [aux_z_max, -aux_z_max, hd_center], + [-aux_column_width, -v_one_half, v_one_half], + [aux_column_width, -v_one_half, v_one_half], + [-aux_column_width, -separator_distance, v_one_half], + [aux_column_width, -separator_distance, v_one_half], + [-z_max_r, -z_max_r, v_one_half], + [z_max_r, -z_max_r, v_one_half], + ] + ) + + center_point + ) + + y_max_z_max = ( + _np.array( + [ + [-center_r, center_r, center_r], + [center_r, center_r, center_r], + [-aux_y_max, hd_center, aux_y_max], + [aux_y_max, hd_center, aux_y_max], + [-y_max_r, v_one_half, y_max_r], + [y_max_r, v_one_half, y_max_r], + [-aux_z_max, aux_z_max, hd_center], + [aux_z_max, aux_z_max, hd_center], + [-aux_column_width, hd_center, hd_center], + [aux_column_width, hd_center, hd_center], + [-aux_column_width, v_one_half, separator_distance], + [aux_column_width, v_one_half, separator_distance], + [-z_max_r, z_max_r, v_one_half], + [z_max_r, z_max_r, v_one_half], + [-aux_column_width, separator_distance, v_one_half], + [aux_column_width, separator_distance, v_one_half], + [-aux_column_width, v_one_half, v_one_half], + [aux_column_width, v_one_half, v_one_half], + ] + ) + + center_point + ) + + x_min_y_min_z_min = ( + _np.array( + [ + [-v_one_half, -v_one_half, -v_one_half], + [-separator_distance, -v_one_half, -v_one_half], + [-aux_column_width, -v_one_half, -v_one_half], + [-v_one_half, -separator_distance, -v_one_half], + [ + -separator_distance, + -separator_distance, + -v_one_half, + ], + [-aux_column_width, -separator_distance, -v_one_half], + [-v_one_half, -aux_column_width, -v_one_half], + [-separator_distance, -aux_column_width, -v_one_half], + [-z_min_r, -z_min_r, -v_one_half], + [-v_one_half, -v_one_half, -separator_distance], + [ + -separator_distance, + -v_one_half, + -separator_distance, + ], + [-aux_column_width, -v_one_half, -separator_distance], + [ + -v_one_half, + -separator_distance, + -separator_distance, + ], + [-hd_center, -hd_center, -hd_center], + [-aux_column_width, -hd_center, -hd_center], + [-v_one_half, -aux_column_width, -separator_distance], + [-hd_center, -aux_column_width, -hd_center], + [-aux_z_min, -aux_z_min, -hd_center], + [-v_one_half, -v_one_half, -aux_column_width], + [-separator_distance, -v_one_half, -aux_column_width], + [-y_min_r, -v_one_half, -y_min_r], + [-v_one_half, -separator_distance, -aux_column_width], + [-hd_center, -hd_center, -aux_column_width], + [-aux_y_min, -hd_center, -aux_y_min], + [-v_one_half, -x_min_r, -x_min_r], + [-hd_center, -aux_x_min, -aux_x_min], + [-center_r, -center_r, -center_r], + ] + ) + + center_point + ) + + x_max_y_min_z_min = ( + _np.array( + [ + [aux_column_width, -v_one_half, -v_one_half], + [separator_distance, -v_one_half, -v_one_half], + [v_one_half, -v_one_half, -v_one_half], + [aux_column_width, -separator_distance, -v_one_half], + [separator_distance, -separator_distance, -v_one_half], + [v_one_half, -separator_distance, -v_one_half], + [z_min_r, -z_min_r, -v_one_half], + [separator_distance, -aux_column_width, -v_one_half], + [v_one_half, -aux_column_width, -v_one_half], + [aux_column_width, -v_one_half, -separator_distance], + [separator_distance, -v_one_half, -separator_distance], + [v_one_half, -v_one_half, -separator_distance], + [aux_column_width, -hd_center, -hd_center], + [hd_center, -hd_center, -hd_center], + [v_one_half, -separator_distance, -separator_distance], + [aux_z_min, -aux_z_min, -hd_center], + [hd_center, -aux_column_width, -hd_center], + [v_one_half, -aux_column_width, -separator_distance], + [y_min_r, -v_one_half, -y_min_r], + [separator_distance, -v_one_half, -aux_column_width], + [v_one_half, -v_one_half, -aux_column_width], + [aux_y_min, -hd_center, -aux_y_min], + [hd_center, -hd_center, -aux_column_width], + [v_one_half, -separator_distance, -aux_column_width], + [center_r, -center_r, -center_r], + [hd_center, -aux_x_max, -aux_x_max], + [v_one_half, -x_max_r, -x_max_r], + ] + ) + + center_point + ) + + x_min_y_max_z_min = ( + _np.array( + [ + [-v_one_half, aux_column_width, -v_one_half], + [-separator_distance, aux_column_width, -v_one_half], + [-z_min_r, z_min_r, -v_one_half], + [-v_one_half, separator_distance, -v_one_half], + [-separator_distance, separator_distance, -v_one_half], + [-aux_column_width, separator_distance, -v_one_half], + [-v_one_half, v_one_half, -v_one_half], + [-separator_distance, v_one_half, -v_one_half], + [-aux_column_width, v_one_half, -v_one_half], + [-v_one_half, aux_column_width, -separator_distance], + [-hd_center, aux_column_width, -hd_center], + [-aux_z_min, aux_z_min, -hd_center], + [-v_one_half, separator_distance, -separator_distance], + [-hd_center, hd_center, -hd_center], + [-aux_column_width, hd_center, -hd_center], + [-v_one_half, v_one_half, -separator_distance], + [-separator_distance, v_one_half, -separator_distance], + [-aux_column_width, v_one_half, -separator_distance], + [-v_one_half, x_min_r, -x_min_r], + [-hd_center, aux_x_min, -aux_x_min], + [-center_r, center_r, -center_r], + [-v_one_half, separator_distance, -aux_column_width], + [-hd_center, hd_center, -aux_column_width], + [-aux_y_max, hd_center, -aux_y_max], + [-v_one_half, v_one_half, -aux_column_width], + [-separator_distance, v_one_half, -aux_column_width], + [-y_max_r, v_one_half, -y_max_r], + ] + ) + + center_point + ) + + x_max_y_max_z_min = ( + _np.array( + [ + [z_min_r, z_min_r, -v_one_half], + [separator_distance, aux_column_width, -v_one_half], + [v_one_half, aux_column_width, -v_one_half], + [aux_column_width, separator_distance, -v_one_half], + [separator_distance, separator_distance, -v_one_half], + [v_one_half, separator_distance, -v_one_half], + [aux_column_width, v_one_half, -v_one_half], + [separator_distance, v_one_half, -v_one_half], + [v_one_half, v_one_half, -v_one_half], + [aux_z_min, aux_z_min, -hd_center], + [hd_center, aux_column_width, -hd_center], + [v_one_half, aux_column_width, -separator_distance], + [aux_column_width, hd_center, -hd_center], + [hd_center, hd_center, -hd_center], + [v_one_half, separator_distance, -separator_distance], + [aux_column_width, v_one_half, -separator_distance], + [separator_distance, v_one_half, -separator_distance], + [v_one_half, v_one_half, -separator_distance], + [center_r, center_r, -center_r], + [hd_center, aux_x_max, -aux_x_max], + [v_one_half, x_max_r, -x_max_r], + [aux_y_max, hd_center, -aux_y_max], + [hd_center, hd_center, -aux_column_width], + [v_one_half, separator_distance, -aux_column_width], + [y_max_r, v_one_half, -y_max_r], + [separator_distance, v_one_half, -aux_column_width], + [v_one_half, v_one_half, -aux_column_width], + ] + ) + + center_point + ) + + x_min_y_min_z_max = ( + _np.array( + [ + [-v_one_half, -v_one_half, aux_column_width], + [-separator_distance, -v_one_half, aux_column_width], + [-y_min_r, -v_one_half, y_min_r], + [-v_one_half, -separator_distance, aux_column_width], + [-hd_center, -hd_center, aux_column_width], + [-aux_y_min, -hd_center, aux_y_min], + [-v_one_half, -x_min_r, x_min_r], + [-hd_center, -aux_x_min, aux_x_min], + [-center_r, -center_r, center_r], + [-v_one_half, -v_one_half, separator_distance], + [-separator_distance, -v_one_half, separator_distance], + [-aux_column_width, -v_one_half, separator_distance], + [-v_one_half, -separator_distance, separator_distance], + [-hd_center, -hd_center, hd_center], + [-aux_column_width, -hd_center, hd_center], + [-v_one_half, -aux_column_width, separator_distance], + [-hd_center, -aux_column_width, hd_center], + [-aux_z_max, -aux_z_max, hd_center], + [-v_one_half, -v_one_half, v_one_half], + [-separator_distance, -v_one_half, v_one_half], + [-aux_column_width, -v_one_half, v_one_half], + [-v_one_half, -separator_distance, v_one_half], + [-separator_distance, -separator_distance, v_one_half], + [-aux_column_width, -separator_distance, v_one_half], + [-v_one_half, -aux_column_width, v_one_half], + [-separator_distance, -aux_column_width, v_one_half], + [-z_max_r, -z_max_r, v_one_half], + ] + ) + + center_point + ) + + x_max_y_min_z_max = ( + _np.array( + [ + [y_min_r, -v_one_half, y_min_r], + [separator_distance, -v_one_half, aux_column_width], + [v_one_half, -v_one_half, aux_column_width], + [aux_y_min, -hd_center, aux_y_min], + [hd_center, -hd_center, aux_column_width], + [v_one_half, -separator_distance, aux_column_width], + [center_r, -center_r, center_r], + [hd_center, -aux_x_max, aux_x_max], + [v_one_half, -x_max_r, x_max_r], + [aux_column_width, -v_one_half, separator_distance], + [separator_distance, -v_one_half, separator_distance], + [v_one_half, -v_one_half, separator_distance], + [aux_column_width, -hd_center, hd_center], + [hd_center, -hd_center, hd_center], + [v_one_half, -separator_distance, separator_distance], + [aux_z_max, -aux_z_max, hd_center], + [hd_center, -aux_column_width, hd_center], + [v_one_half, -aux_column_width, separator_distance], + [aux_column_width, -v_one_half, v_one_half], + [separator_distance, -v_one_half, v_one_half], + [v_one_half, -v_one_half, v_one_half], + [aux_column_width, -separator_distance, v_one_half], + [separator_distance, -separator_distance, v_one_half], + [v_one_half, -separator_distance, v_one_half], + [z_max_r, -z_max_r, v_one_half], + [separator_distance, -aux_column_width, v_one_half], + [v_one_half, -aux_column_width, v_one_half], + ] + ) + + center_point + ) + + x_min_y_max_z_max = ( + _np.array( + [ + [-v_one_half, x_min_r, x_min_r], + [-hd_center, aux_x_min, aux_x_min], + [-center_r, center_r, center_r], + [-v_one_half, separator_distance, aux_column_width], + [-hd_center, hd_center, aux_column_width], + [-aux_y_max, hd_center, aux_y_max], + [-v_one_half, v_one_half, aux_column_width], + [-separator_distance, v_one_half, aux_column_width], + [-y_max_r, v_one_half, y_max_r], + [-v_one_half, aux_column_width, separator_distance], + [-hd_center, aux_column_width, hd_center], + [-aux_z_max, aux_z_max, hd_center], + [-v_one_half, separator_distance, separator_distance], + [-hd_center, hd_center, hd_center], + [-aux_column_width, hd_center, hd_center], + [-v_one_half, v_one_half, separator_distance], + [-separator_distance, v_one_half, separator_distance], + [-aux_column_width, v_one_half, separator_distance], + [-v_one_half, aux_column_width, v_one_half], + [-separator_distance, aux_column_width, v_one_half], + [-z_max_r, z_max_r, v_one_half], + [-v_one_half, separator_distance, v_one_half], + [-separator_distance, separator_distance, v_one_half], + [-aux_column_width, separator_distance, v_one_half], + [-v_one_half, v_one_half, v_one_half], + [-separator_distance, v_one_half, v_one_half], + [-aux_column_width, v_one_half, v_one_half], + ] + ) + + center_point + ) + + x_max_y_max_z_max = ( + _np.array( + [ + [center_r, center_r, center_r], + [hd_center, aux_x_max, aux_x_max], + [v_one_half, x_max_r, x_max_r], + [aux_y_max, hd_center, aux_y_max], + [hd_center, hd_center, aux_column_width], + [v_one_half, separator_distance, aux_column_width], + [y_max_r, v_one_half, y_max_r], + [separator_distance, v_one_half, aux_column_width], + [v_one_half, v_one_half, aux_column_width], + [aux_z_max, aux_z_max, hd_center], + [hd_center, aux_column_width, hd_center], + [v_one_half, aux_column_width, separator_distance], + [aux_column_width, hd_center, hd_center], + [hd_center, hd_center, hd_center], + [v_one_half, separator_distance, separator_distance], + [aux_column_width, v_one_half, separator_distance], + [separator_distance, v_one_half, separator_distance], + [v_one_half, v_one_half, separator_distance], + [z_max_r, z_max_r, v_one_half], + [separator_distance, aux_column_width, v_one_half], + [v_one_half, aux_column_width, v_one_half], + [aux_column_width, separator_distance, v_one_half], + [separator_distance, separator_distance, v_one_half], + [v_one_half, separator_distance, v_one_half], + [aux_column_width, v_one_half, v_one_half], + [separator_distance, v_one_half, v_one_half], + [v_one_half, v_one_half, v_one_half], + ] + ) + + center_point + ) + + # Append the control points to the spline list + for control_points, degrees in [ + (x_min_y_min, [2, 2, 1]), + (x_max_y_min, [2, 2, 1]), + (x_min_y_max, [2, 2, 1]), + (x_max_y_max, [2, 2, 1]), + (x_min_z_min, [2, 1, 2]), + (x_max_z_min, [2, 1, 2]), + (x_min_z_max, [2, 1, 2]), + (x_max_z_max, [2, 1, 2]), + (y_min_z_min, [1, 2, 2]), + (y_max_z_min, [1, 2, 2]), + (y_min_z_max, [1, 2, 2]), + (y_max_z_max, [1, 2, 2]), + (x_min_y_min_z_min, [2, 2, 2]), + (x_max_y_min_z_min, [2, 2, 2]), + (x_min_y_max_z_min, [2, 2, 2]), + (x_max_y_max_z_min, [2, 2, 2]), + (x_min_y_min_z_max, [2, 2, 2]), + (x_max_y_min_z_max, [2, 2, 2]), + (x_min_y_max_z_max, [2, 2, 2]), + (x_max_y_max_z_max, [2, 2, 2]), + ]: + spline_list.append( + _Bezier(degrees=degrees, control_points=control_points) + ) + + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) - # Start with branch interconnections - x_min_y_min = _np.array( - [ - [-0.5, -0.5, -aux_column_width], - [-separator_distance, -0.5, -aux_column_width], - [-y_min_r, -0.5, -y_min_r], - [-0.5, -separator_distance, -aux_column_width], - [-hd_center, -hd_center, -aux_column_width], - [-aux_y_min, -hd_center, -aux_y_min], - [-0.5, -x_min_r, -x_min_r], - [-hd_center, -aux_x_min, -aux_x_min], - [-center_r, -center_r, -center_r], - [-0.5, -0.5, aux_column_width], - [-separator_distance, -0.5, aux_column_width], - [-y_min_r, -0.5, y_min_r], - [-0.5, -separator_distance, aux_column_width], - [-hd_center, -hd_center, aux_column_width], - [-aux_y_min, -hd_center, aux_y_min], - [-0.5, -x_min_r, x_min_r], - [-hd_center, -aux_x_min, aux_x_min], - [-center_r, -center_r, center_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 1], control_points=x_min_y_min) - ) - - x_max_y_min = _np.array( - [ - [y_min_r, -0.5, -y_min_r], - [separator_distance, -0.5, -aux_column_width], - [0.5, -0.5, -aux_column_width], - [aux_y_min, -hd_center, -aux_y_min], - [hd_center, -hd_center, -aux_column_width], - [0.5, -separator_distance, -aux_column_width], - [center_r, -center_r, -center_r], - [hd_center, -aux_x_max, -aux_x_max], - [0.5, -x_max_r, -x_max_r], - [y_min_r, -0.5, y_min_r], - [separator_distance, -0.5, aux_column_width], - [0.5, -0.5, aux_column_width], - [aux_y_min, -hd_center, aux_y_min], - [hd_center, -hd_center, aux_column_width], - [0.5, -separator_distance, aux_column_width], - [center_r, -center_r, center_r], - [hd_center, -aux_x_max, aux_x_max], - [0.5, -x_max_r, x_max_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 1], control_points=x_max_y_min) - ) - - x_min_y_max = _np.array( - [ - [-0.5, x_min_r, -x_min_r], - [-hd_center, aux_x_min, -aux_x_min], - [-center_r, center_r, -center_r], - [-0.5, separator_distance, -aux_column_width], - [-hd_center, hd_center, -aux_column_width], - [-aux_y_max, hd_center, -aux_y_max], - [-0.5, 0.5, -aux_column_width], - [-separator_distance, 0.5, -aux_column_width], - [-y_max_r, 0.5, -y_max_r], - [-0.5, x_min_r, x_min_r], - [-hd_center, aux_x_min, aux_x_min], - [-center_r, center_r, center_r], - [-0.5, separator_distance, aux_column_width], - [-hd_center, hd_center, aux_column_width], - [-aux_y_max, hd_center, aux_y_max], - [-0.5, 0.5, aux_column_width], - [-separator_distance, 0.5, aux_column_width], - [-y_max_r, 0.5, y_max_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 1], control_points=x_min_y_max) - ) - - x_max_y_max = _np.array( - [ - [center_r, center_r, -center_r], - [hd_center, aux_x_max, -aux_x_max], - [0.5, x_max_r, -x_max_r], - [aux_y_max, hd_center, -aux_y_max], - [hd_center, hd_center, -aux_column_width], - [0.5, separator_distance, -aux_column_width], - [y_max_r, 0.5, -y_max_r], - [separator_distance, 0.5, -aux_column_width], - [0.5, 0.5, -aux_column_width], - [center_r, center_r, center_r], - [hd_center, aux_x_max, aux_x_max], - [0.5, x_max_r, x_max_r], - [aux_y_max, hd_center, aux_y_max], - [hd_center, hd_center, aux_column_width], - [0.5, separator_distance, aux_column_width], - [y_max_r, 0.5, y_max_r], - [separator_distance, 0.5, aux_column_width], - [0.5, 0.5, aux_column_width], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 1], control_points=x_max_y_max) - ) - - x_min_z_min = _np.array( - [ - [-0.5, -aux_column_width, -0.5], - [-separator_distance, -aux_column_width, -0.5], - [-z_min_r, -z_min_r, -0.5], - [-0.5, aux_column_width, -0.5], - [-separator_distance, aux_column_width, -0.5], - [-z_min_r, z_min_r, -0.5], - [-0.5, -aux_column_width, -separator_distance], - [-hd_center, -aux_column_width, -hd_center], - [-aux_z_min, -aux_z_min, -hd_center], - [-0.5, aux_column_width, -separator_distance], - [-hd_center, aux_column_width, -hd_center], - [-aux_z_min, aux_z_min, -hd_center], - [-0.5, -x_min_r, -x_min_r], - [-hd_center, -aux_x_min, -aux_x_min], - [-center_r, -center_r, -center_r], - [-0.5, x_min_r, -x_min_r], - [-hd_center, aux_x_min, -aux_x_min], - [-center_r, center_r, -center_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 1, 2], control_points=x_min_z_min) - ) - - x_max_z_min = _np.array( - [ - [z_min_r, -z_min_r, -0.5], - [separator_distance, -aux_column_width, -0.5], - [0.5, -aux_column_width, -0.5], - [z_min_r, z_min_r, -0.5], - [separator_distance, aux_column_width, -0.5], - [0.5, aux_column_width, -0.5], - [aux_z_min, -aux_z_min, -hd_center], - [hd_center, -aux_column_width, -hd_center], - [0.5, -aux_column_width, -separator_distance], - [aux_z_min, aux_z_min, -hd_center], - [hd_center, aux_column_width, -hd_center], - [0.5, aux_column_width, -separator_distance], - [center_r, -center_r, -center_r], - [hd_center, -aux_x_max, -aux_x_max], - [0.5, -x_max_r, -x_max_r], - [center_r, center_r, -center_r], - [hd_center, aux_x_max, -aux_x_max], - [0.5, x_max_r, -x_max_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 1, 2], control_points=x_max_z_min) - ) - - x_min_z_max = _np.array( - [ - [-0.5, -x_min_r, x_min_r], - [-hd_center, -aux_x_min, aux_x_min], - [-center_r, -center_r, center_r], - [-0.5, x_min_r, x_min_r], - [-hd_center, aux_x_min, aux_x_min], - [-center_r, center_r, center_r], - [-0.5, -aux_column_width, separator_distance], - [-hd_center, -aux_column_width, hd_center], - [-aux_z_max, -aux_z_max, hd_center], - [-0.5, aux_column_width, separator_distance], - [-hd_center, aux_column_width, hd_center], - [-aux_z_max, aux_z_max, hd_center], - [-0.5, -aux_column_width, 0.5], - [-separator_distance, -aux_column_width, 0.5], - [-z_max_r, -z_max_r, 0.5], - [-0.5, aux_column_width, 0.5], - [-separator_distance, aux_column_width, 0.5], - [-z_max_r, z_max_r, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 1, 2], control_points=x_min_z_max) - ) - - x_max_z_max = _np.array( - [ - [center_r, -center_r, center_r], - [hd_center, -aux_x_max, aux_x_max], - [0.5, -x_max_r, x_max_r], - [center_r, center_r, center_r], - [hd_center, aux_x_max, aux_x_max], - [0.5, x_max_r, x_max_r], - [aux_z_max, -aux_z_max, hd_center], - [hd_center, -aux_column_width, hd_center], - [0.5, -aux_column_width, separator_distance], - [aux_z_max, aux_z_max, hd_center], - [hd_center, aux_column_width, hd_center], - [0.5, aux_column_width, separator_distance], - [z_max_r, -z_max_r, 0.5], - [separator_distance, -aux_column_width, 0.5], - [0.5, -aux_column_width, 0.5], - [z_max_r, z_max_r, 0.5], - [separator_distance, aux_column_width, 0.5], - [0.5, aux_column_width, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 1, 2], control_points=x_max_z_max) - ) - - y_min_z_min = _np.array( - [ - [-aux_column_width, -0.5, -0.5], - [aux_column_width, -0.5, -0.5], - [-aux_column_width, -separator_distance, -0.5], - [aux_column_width, -separator_distance, -0.5], - [-z_min_r, -z_min_r, -0.5], - [z_min_r, -z_min_r, -0.5], - [-aux_column_width, -0.5, -separator_distance], - [aux_column_width, -0.5, -separator_distance], - [-aux_column_width, -hd_center, -hd_center], - [aux_column_width, -hd_center, -hd_center], - [-aux_z_min, -aux_z_min, -hd_center], - [aux_z_min, -aux_z_min, -hd_center], - [-y_min_r, -0.5, -y_min_r], - [y_min_r, -0.5, -y_min_r], - [-aux_y_min, -hd_center, -aux_y_min], - [aux_y_min, -hd_center, -aux_y_min], - [-center_r, -center_r, -center_r], - [center_r, -center_r, -center_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[1, 2, 2], control_points=y_min_z_min) - ) - - y_max_z_min = _np.array( - [ - [-z_min_r, z_min_r, -0.5], - [z_min_r, z_min_r, -0.5], - [-aux_column_width, separator_distance, -0.5], - [aux_column_width, separator_distance, -0.5], - [-aux_column_width, 0.5, -0.5], - [aux_column_width, 0.5, -0.5], - [-aux_z_min, aux_z_min, -hd_center], - [aux_z_min, aux_z_min, -hd_center], - [-aux_column_width, hd_center, -hd_center], - [aux_column_width, hd_center, -hd_center], - [-aux_column_width, 0.5, -separator_distance], - [aux_column_width, 0.5, -separator_distance], - [-center_r, center_r, -center_r], - [center_r, center_r, -center_r], - [-aux_y_max, hd_center, -aux_y_max], - [aux_y_max, hd_center, -aux_y_max], - [-y_max_r, 0.5, -y_max_r], - [y_max_r, 0.5, -y_max_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[1, 2, 2], control_points=y_max_z_min) - ) - - y_min_z_max = _np.array( - [ - [-y_min_r, -0.5, y_min_r], - [y_min_r, -0.5, y_min_r], - [-aux_y_min, -hd_center, aux_y_min], - [aux_y_min, -hd_center, aux_y_min], - [-center_r, -center_r, center_r], - [center_r, -center_r, center_r], - [-aux_column_width, -0.5, separator_distance], - [aux_column_width, -0.5, separator_distance], - [-aux_column_width, -hd_center, hd_center], - [aux_column_width, -hd_center, hd_center], - [-aux_z_max, -aux_z_max, hd_center], - [aux_z_max, -aux_z_max, hd_center], - [-aux_column_width, -0.5, 0.5], - [aux_column_width, -0.5, 0.5], - [-aux_column_width, -separator_distance, 0.5], - [aux_column_width, -separator_distance, 0.5], - [-z_max_r, -z_max_r, 0.5], - [z_max_r, -z_max_r, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[1, 2, 2], control_points=y_min_z_max) - ) - - y_max_z_max = _np.array( - [ - [-center_r, center_r, center_r], - [center_r, center_r, center_r], - [-aux_y_max, hd_center, aux_y_max], - [aux_y_max, hd_center, aux_y_max], - [-y_max_r, 0.5, y_max_r], - [y_max_r, 0.5, y_max_r], - [-aux_z_max, aux_z_max, hd_center], - [aux_z_max, aux_z_max, hd_center], - [-aux_column_width, hd_center, hd_center], - [aux_column_width, hd_center, hd_center], - [-aux_column_width, 0.5, separator_distance], - [aux_column_width, 0.5, separator_distance], - [-z_max_r, z_max_r, 0.5], - [z_max_r, z_max_r, 0.5], - [-aux_column_width, separator_distance, 0.5], - [aux_column_width, separator_distance, 0.5], - [-aux_column_width, 0.5, 0.5], - [aux_column_width, 0.5, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[1, 2, 2], control_points=y_max_z_max) - ) - - x_min_y_min_z_min = _np.array( - [ - [-0.5, -0.5, -0.5], - [-separator_distance, -0.5, -0.5], - [-aux_column_width, -0.5, -0.5], - [-0.5, -separator_distance, -0.5], - [-separator_distance, -separator_distance, -0.5], - [-aux_column_width, -separator_distance, -0.5], - [-0.5, -aux_column_width, -0.5], - [-separator_distance, -aux_column_width, -0.5], - [-z_min_r, -z_min_r, -0.5], - [-0.5, -0.5, -separator_distance], - [-separator_distance, -0.5, -separator_distance], - [-aux_column_width, -0.5, -separator_distance], - [-0.5, -separator_distance, -separator_distance], - [-hd_center, -hd_center, -hd_center], - [-aux_column_width, -hd_center, -hd_center], - [-0.5, -aux_column_width, -separator_distance], - [-hd_center, -aux_column_width, -hd_center], - [-aux_z_min, -aux_z_min, -hd_center], - [-0.5, -0.5, -aux_column_width], - [-separator_distance, -0.5, -aux_column_width], - [-y_min_r, -0.5, -y_min_r], - [-0.5, -separator_distance, -aux_column_width], - [-hd_center, -hd_center, -aux_column_width], - [-aux_y_min, -hd_center, -aux_y_min], - [-0.5, -x_min_r, -x_min_r], - [-hd_center, -aux_x_min, -aux_x_min], - [-center_r, -center_r, -center_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_min_y_min_z_min) - ) - - x_max_y_min_z_min = _np.array( - [ - [aux_column_width, -0.5, -0.5], - [separator_distance, -0.5, -0.5], - [0.5, -0.5, -0.5], - [aux_column_width, -separator_distance, -0.5], - [separator_distance, -separator_distance, -0.5], - [0.5, -separator_distance, -0.5], - [z_min_r, -z_min_r, -0.5], - [separator_distance, -aux_column_width, -0.5], - [0.5, -aux_column_width, -0.5], - [aux_column_width, -0.5, -separator_distance], - [separator_distance, -0.5, -separator_distance], - [0.5, -0.5, -separator_distance], - [aux_column_width, -hd_center, -hd_center], - [hd_center, -hd_center, -hd_center], - [0.5, -separator_distance, -separator_distance], - [aux_z_min, -aux_z_min, -hd_center], - [hd_center, -aux_column_width, -hd_center], - [0.5, -aux_column_width, -separator_distance], - [y_min_r, -0.5, -y_min_r], - [separator_distance, -0.5, -aux_column_width], - [0.5, -0.5, -aux_column_width], - [aux_y_min, -hd_center, -aux_y_min], - [hd_center, -hd_center, -aux_column_width], - [0.5, -separator_distance, -aux_column_width], - [center_r, -center_r, -center_r], - [hd_center, -aux_x_max, -aux_x_max], - [0.5, -x_max_r, -x_max_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_max_y_min_z_min) - ) - - x_min_y_max_z_min = _np.array( - [ - [-0.5, aux_column_width, -0.5], - [-separator_distance, aux_column_width, -0.5], - [-z_min_r, z_min_r, -0.5], - [-0.5, separator_distance, -0.5], - [-separator_distance, separator_distance, -0.5], - [-aux_column_width, separator_distance, -0.5], - [-0.5, 0.5, -0.5], - [-separator_distance, 0.5, -0.5], - [-aux_column_width, 0.5, -0.5], - [-0.5, aux_column_width, -separator_distance], - [-hd_center, aux_column_width, -hd_center], - [-aux_z_min, aux_z_min, -hd_center], - [-0.5, separator_distance, -separator_distance], - [-hd_center, hd_center, -hd_center], - [-aux_column_width, hd_center, -hd_center], - [-0.5, 0.5, -separator_distance], - [-separator_distance, 0.5, -separator_distance], - [-aux_column_width, 0.5, -separator_distance], - [-0.5, x_min_r, -x_min_r], - [-hd_center, aux_x_min, -aux_x_min], - [-center_r, center_r, -center_r], - [-0.5, separator_distance, -aux_column_width], - [-hd_center, hd_center, -aux_column_width], - [-aux_y_max, hd_center, -aux_y_max], - [-0.5, 0.5, -aux_column_width], - [-separator_distance, 0.5, -aux_column_width], - [-y_max_r, 0.5, -y_max_r], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_min_y_max_z_min) - ) - - x_max_y_max_z_min = _np.array( - [ - [z_min_r, z_min_r, -0.5], - [separator_distance, aux_column_width, -0.5], - [0.5, aux_column_width, -0.5], - [aux_column_width, separator_distance, -0.5], - [separator_distance, separator_distance, -0.5], - [0.5, separator_distance, -0.5], - [aux_column_width, 0.5, -0.5], - [separator_distance, 0.5, -0.5], - [0.5, 0.5, -0.5], - [aux_z_min, aux_z_min, -hd_center], - [hd_center, aux_column_width, -hd_center], - [0.5, aux_column_width, -separator_distance], - [aux_column_width, hd_center, -hd_center], - [hd_center, hd_center, -hd_center], - [0.5, separator_distance, -separator_distance], - [aux_column_width, 0.5, -separator_distance], - [separator_distance, 0.5, -separator_distance], - [0.5, 0.5, -separator_distance], - [center_r, center_r, -center_r], - [hd_center, aux_x_max, -aux_x_max], - [0.5, x_max_r, -x_max_r], - [aux_y_max, hd_center, -aux_y_max], - [hd_center, hd_center, -aux_column_width], - [0.5, separator_distance, -aux_column_width], - [y_max_r, 0.5, -y_max_r], - [separator_distance, 0.5, -aux_column_width], - [0.5, 0.5, -aux_column_width], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_max_y_max_z_min) - ) - - x_min_y_min_z_max = _np.array( - [ - [-0.5, -0.5, aux_column_width], - [-separator_distance, -0.5, aux_column_width], - [-y_min_r, -0.5, y_min_r], - [-0.5, -separator_distance, aux_column_width], - [-hd_center, -hd_center, aux_column_width], - [-aux_y_min, -hd_center, aux_y_min], - [-0.5, -x_min_r, x_min_r], - [-hd_center, -aux_x_min, aux_x_min], - [-center_r, -center_r, center_r], - [-0.5, -0.5, separator_distance], - [-separator_distance, -0.5, separator_distance], - [-aux_column_width, -0.5, separator_distance], - [-0.5, -separator_distance, separator_distance], - [-hd_center, -hd_center, hd_center], - [-aux_column_width, -hd_center, hd_center], - [-0.5, -aux_column_width, separator_distance], - [-hd_center, -aux_column_width, hd_center], - [-aux_z_max, -aux_z_max, hd_center], - [-0.5, -0.5, 0.5], - [-separator_distance, -0.5, 0.5], - [-aux_column_width, -0.5, 0.5], - [-0.5, -separator_distance, 0.5], - [-separator_distance, -separator_distance, 0.5], - [-aux_column_width, -separator_distance, 0.5], - [-0.5, -aux_column_width, 0.5], - [-separator_distance, -aux_column_width, 0.5], - [-z_max_r, -z_max_r, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_min_y_min_z_max) - ) - - x_max_y_min_z_max = _np.array( - [ - [y_min_r, -0.5, y_min_r], - [separator_distance, -0.5, aux_column_width], - [0.5, -0.5, aux_column_width], - [aux_y_min, -hd_center, aux_y_min], - [hd_center, -hd_center, aux_column_width], - [0.5, -separator_distance, aux_column_width], - [center_r, -center_r, center_r], - [hd_center, -aux_x_max, aux_x_max], - [0.5, -x_max_r, x_max_r], - [aux_column_width, -0.5, separator_distance], - [separator_distance, -0.5, separator_distance], - [0.5, -0.5, separator_distance], - [aux_column_width, -hd_center, hd_center], - [hd_center, -hd_center, hd_center], - [0.5, -separator_distance, separator_distance], - [aux_z_max, -aux_z_max, hd_center], - [hd_center, -aux_column_width, hd_center], - [0.5, -aux_column_width, separator_distance], - [aux_column_width, -0.5, 0.5], - [separator_distance, -0.5, 0.5], - [0.5, -0.5, 0.5], - [aux_column_width, -separator_distance, 0.5], - [separator_distance, -separator_distance, 0.5], - [0.5, -separator_distance, 0.5], - [z_max_r, -z_max_r, 0.5], - [separator_distance, -aux_column_width, 0.5], - [0.5, -aux_column_width, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_max_y_min_z_max) - ) - - x_min_y_max_z_max = _np.array( - [ - [-0.5, x_min_r, x_min_r], - [-hd_center, aux_x_min, aux_x_min], - [-center_r, center_r, center_r], - [-0.5, separator_distance, aux_column_width], - [-hd_center, hd_center, aux_column_width], - [-aux_y_max, hd_center, aux_y_max], - [-0.5, 0.5, aux_column_width], - [-separator_distance, 0.5, aux_column_width], - [-y_max_r, 0.5, y_max_r], - [-0.5, aux_column_width, separator_distance], - [-hd_center, aux_column_width, hd_center], - [-aux_z_max, aux_z_max, hd_center], - [-0.5, separator_distance, separator_distance], - [-hd_center, hd_center, hd_center], - [-aux_column_width, hd_center, hd_center], - [-0.5, 0.5, separator_distance], - [-separator_distance, 0.5, separator_distance], - [-aux_column_width, 0.5, separator_distance], - [-0.5, aux_column_width, 0.5], - [-separator_distance, aux_column_width, 0.5], - [-z_max_r, z_max_r, 0.5], - [-0.5, separator_distance, 0.5], - [-separator_distance, separator_distance, 0.5], - [-aux_column_width, separator_distance, 0.5], - [-0.5, 0.5, 0.5], - [-separator_distance, 0.5, 0.5], - [-aux_column_width, 0.5, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_min_y_max_z_max) - ) - - x_max_y_max_z_max = _np.array( - [ - [center_r, center_r, center_r], - [hd_center, aux_x_max, aux_x_max], - [0.5, x_max_r, x_max_r], - [aux_y_max, hd_center, aux_y_max], - [hd_center, hd_center, aux_column_width], - [0.5, separator_distance, aux_column_width], - [y_max_r, 0.5, y_max_r], - [separator_distance, 0.5, aux_column_width], - [0.5, 0.5, aux_column_width], - [aux_z_max, aux_z_max, hd_center], - [hd_center, aux_column_width, hd_center], - [0.5, aux_column_width, separator_distance], - [aux_column_width, hd_center, hd_center], - [hd_center, hd_center, hd_center], - [0.5, separator_distance, separator_distance], - [aux_column_width, 0.5, separator_distance], - [separator_distance, 0.5, separator_distance], - [0.5, 0.5, separator_distance], - [z_max_r, z_max_r, 0.5], - [separator_distance, aux_column_width, 0.5], - [0.5, aux_column_width, 0.5], - [aux_column_width, separator_distance, 0.5], - [separator_distance, separator_distance, 0.5], - [0.5, separator_distance, 0.5], - [aux_column_width, 0.5, 0.5], - [separator_distance, 0.5, 0.5], - [0.5, 0.5, 0.5], - ] - ) + _np.array([0.5, 0.5, 0.5]) - - spline_list.append( - _Bezier(degrees=[2, 2, 2], control_points=x_max_y_max_z_max) - ) - return (spline_list, None) + return splines, derivatives From 24d15d678c4aa56a67a4841b6ed4449ee3d4cddb Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 9 Oct 2024 13:54:52 +0200 Subject: [PATCH 16/52] Fix derivative of Chi tile --- splinepy/microstructure/tiles/chi.py | 7 ++++--- tests/test_microstructure.py | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/splinepy/microstructure/tiles/chi.py b/splinepy/microstructure/tiles/chi.py index 827c7b8d3..0bcd215e9 100644 --- a/splinepy/microstructure/tiles/chi.py +++ b/splinepy/microstructure/tiles/chi.py @@ -83,12 +83,13 @@ def create_tile( s = r * _np.sin(alpha) c = r * _np.cos(alpha) else: - alpha = parameter_sensitivities[0, 0, i_derivative - 1] + alpha = parameters[0, 0] + _np.pi / 4 + dalpha = float(parameter_sensitivities[0, 0, i_derivative - 1]) v_one_half = 0.0 v_zero = 0.0 r = _np.sqrt(0.125) - s = r * _np.cos(alpha) - c = -r * _np.sin(alpha) + s = dalpha * r * _np.cos(alpha) + c = dalpha * -r * _np.sin(alpha) # Init return value spline_list = [] diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 73f8e1b72..edaf0b477 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -188,9 +188,8 @@ def test_tile_derivatives(np_rng, heps=1e-8, n_test_points=4): n_test_points: int Number of testing points in the parametric domain """ - # TODO: right now Chi, EllipsVoid, CubeVoid and InverseCross show wrong derivatives + # TODO: right now EllipsVoid, CubeVoid and InverseCross show wrong derivatives skip_classes = [ - ms.tiles.Chi, ms.tiles.EllipsVoid, ms.tiles.CubeVoid, ms.tiles.InverseCross3D, From c38a2e089190349a33e6abfe819d17998e687ec8 Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 9 Oct 2024 15:47:47 +0200 Subject: [PATCH 17/52] Add/fix derivative of tile InverseCross3D --- .../microstructure/tiles/inverse_cross_3d.py | 1920 +++++++++-------- tests/test_microstructure.py | 8 +- 2 files changed, 1038 insertions(+), 890 deletions(-) diff --git a/splinepy/microstructure/tiles/inverse_cross_3d.py b/splinepy/microstructure/tiles/inverse_cross_3d.py index 4af1b2ef6..4787cd3b2 100644 --- a/splinepy/microstructure/tiles/inverse_cross_3d.py +++ b/splinepy/microstructure/tiles/inverse_cross_3d.py @@ -89,9 +89,13 @@ def _closing_tile( self.check_params(parameters) if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) + self.check_param_derivatives(parameter_sensitivities) + + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): raise ValueError("Thickness out of range (0, .5)") @@ -102,789 +106,933 @@ def _closing_tile( if not (0.0 < float(filling_height) < 1.0): raise ValueError("Filling must be in (0,1)") - # Precompute auxiliary values - inv_filling_height = 1.0 - filling_height - ctps_mid_height_top = (1 + filling_height) * 0.5 - ctps_mid_height_bottom = 1.0 - ctps_mid_height_top - center_width = 1.0 - 2 * boundary_width - r_center = center_width * 0.5 - half_r_center = (r_center + 0.5) * 0.5 - aux_column_width = 0.5 - 2 * (0.5 - separator_distance) - - spline_list = [] - if closure == "z_min": - branch_thickness = parameters.flatten()[5] - branch_neighbor_x_min_ctps = _np.array( - [ - [-0.5, -r_center, filling_height], - [-half_r_center, -r_center, filling_height], - [-r_center, -r_center, filling_height], - [-0.5, r_center, filling_height], - [-half_r_center, r_center, filling_height], - [-r_center, r_center, filling_height], - [-0.5, -aux_column_width, ctps_mid_height_top], - [ - -separator_distance, - -aux_column_width, - ctps_mid_height_top, - ], - [ - -branch_thickness, - -branch_thickness, - ctps_mid_height_top, - ], - [-0.5, aux_column_width, ctps_mid_height_top], - [ - -separator_distance, - aux_column_width, - ctps_mid_height_top, - ], - [-branch_thickness, branch_thickness, ctps_mid_height_top], - [-0.5, -aux_column_width, 1.0], - [-separator_distance, -aux_column_width, 1.0], - [-branch_thickness, -branch_thickness, 1.0], - [-0.5, aux_column_width, 1.0], - [-separator_distance, aux_column_width, 1.0], - [-branch_thickness, branch_thickness, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + splines = [] + + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + # Auxiliary values + fill_height_aux = filling_height + sep_distance_aux = separator_distance + inv_filling_height = 1.0 - filling_height + ctps_mid_height_top = (1 + filling_height) * 0.5 + ctps_mid_height_bottom = 1.0 - ctps_mid_height_top + center_width = 1.0 - 2 * boundary_width + r_center = center_width * 0.5 + half_r_center = (r_center + 0.5) * 0.5 + aux_column_width = 0.5 - 2 * (0.5 - separator_distance) + v_zero = 0.0 + v_one_half = 0.5 + v_one = 1.0 + if closure == "z_min": + branch_thickness = parameters.flatten()[5] + elif closure == "z_max": + branch_thickness = parameters.flatten()[4] + else: + fill_height_aux = 0.0 + sep_distance_aux = 0.0 + inv_filling_height = 0.0 + ctps_mid_height_top = 0.0 + ctps_mid_height_bottom = 0.0 + center_width = 0.0 + r_center = 0.0 + half_r_center = 0.0 + aux_column_width = 0.0 + v_zero, v_one_half, v_one = [0.0] * 3 + if closure == "z_min": + branch_thickness = parameter_sensitivities.flatten()[5] + elif closure == "z_max": + branch_thickness = parameter_sensitivities.flatten()[4] + spline_list = [] + if closure == "z_min": + branch_neighbor_x_min_ctps = _np.array( + [ + [-v_one_half, -r_center, fill_height_aux], + [-half_r_center, -r_center, fill_height_aux], + [-r_center, -r_center, fill_height_aux], + [-v_one_half, r_center, fill_height_aux], + [-half_r_center, r_center, fill_height_aux], + [-r_center, r_center, fill_height_aux], + [-v_one_half, -aux_column_width, ctps_mid_height_top], + [ + -sep_distance_aux, + -aux_column_width, + ctps_mid_height_top, + ], + [ + -branch_thickness, + -branch_thickness, + ctps_mid_height_top, + ], + [-v_one_half, aux_column_width, ctps_mid_height_top], + [ + -sep_distance_aux, + aux_column_width, + ctps_mid_height_top, + ], + [ + -branch_thickness, + branch_thickness, + ctps_mid_height_top, + ], + [-v_one_half, -aux_column_width, v_one], + [-sep_distance_aux, -aux_column_width, v_one], + [-branch_thickness, -branch_thickness, v_one], + [-v_one_half, aux_column_width, v_one], + [-sep_distance_aux, aux_column_width, v_one], + [-branch_thickness, branch_thickness, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 1, 2], - control_points=branch_neighbor_x_min_ctps, + spline_list.append( + _Bezier( + degrees=[2, 1, 2], + control_points=branch_neighbor_x_min_ctps, + ) ) - ) - branch_neighbor_x_max_ctps = _np.array( - [ - [r_center, -r_center, filling_height], - [half_r_center, -r_center, filling_height], - [0.5, -r_center, filling_height], - [r_center, r_center, filling_height], - [half_r_center, r_center, filling_height], - [0.5, r_center, filling_height], - [branch_thickness, -branch_thickness, ctps_mid_height_top], - [ - separator_distance, - -aux_column_width, - ctps_mid_height_top, - ], - [0.5, -aux_column_width, ctps_mid_height_top], - [branch_thickness, branch_thickness, ctps_mid_height_top], + branch_neighbor_x_max_ctps = _np.array( [ - separator_distance, - aux_column_width, - ctps_mid_height_top, - ], - [0.5, aux_column_width, ctps_mid_height_top], - [branch_thickness, -branch_thickness, 1.0], - [separator_distance, -aux_column_width, 1.0], - [0.5, -aux_column_width, 1.0], - [branch_thickness, branch_thickness, 1.0], - [separator_distance, aux_column_width, 1.0], - [0.5, aux_column_width, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + [r_center, -r_center, fill_height_aux], + [half_r_center, -r_center, fill_height_aux], + [v_one_half, -r_center, fill_height_aux], + [r_center, r_center, fill_height_aux], + [half_r_center, r_center, fill_height_aux], + [v_one_half, r_center, fill_height_aux], + [ + branch_thickness, + -branch_thickness, + ctps_mid_height_top, + ], + [ + sep_distance_aux, + -aux_column_width, + ctps_mid_height_top, + ], + [v_one_half, -aux_column_width, ctps_mid_height_top], + [ + branch_thickness, + branch_thickness, + ctps_mid_height_top, + ], + [ + sep_distance_aux, + aux_column_width, + ctps_mid_height_top, + ], + [v_one_half, aux_column_width, ctps_mid_height_top], + [branch_thickness, -branch_thickness, v_one], + [sep_distance_aux, -aux_column_width, v_one], + [v_one_half, -aux_column_width, v_one], + [branch_thickness, branch_thickness, v_one], + [sep_distance_aux, aux_column_width, v_one], + [v_one_half, aux_column_width, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 1, 2], - control_points=branch_neighbor_x_max_ctps, + spline_list.append( + _Bezier( + degrees=[2, 1, 2], + control_points=branch_neighbor_x_max_ctps, + ) ) - ) - branch_neighbor_y_min_ctps = _np.array( - [ - [-r_center, -0.5, filling_height], - [r_center, -0.5, filling_height], - [-r_center, -half_r_center, filling_height], - [r_center, -half_r_center, filling_height], - [-r_center, -r_center, filling_height], - [r_center, -r_center, filling_height], - [-aux_column_width, -0.5, ctps_mid_height_top], - [aux_column_width, -0.5, ctps_mid_height_top], - [ - -aux_column_width, - -separator_distance, - ctps_mid_height_top, - ], + branch_neighbor_y_min_ctps = _np.array( [ - aux_column_width, - -separator_distance, - ctps_mid_height_top, - ], - [ - -branch_thickness, - -branch_thickness, - ctps_mid_height_top, - ], - [branch_thickness, -branch_thickness, ctps_mid_height_top], - [-aux_column_width, -0.5, 1.0], - [aux_column_width, -0.5, 1.0], - [-aux_column_width, -separator_distance, 1.0], - [aux_column_width, -separator_distance, 1.0], - [-branch_thickness, -branch_thickness, 1.0], - [branch_thickness, -branch_thickness, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + [-r_center, -v_one_half, fill_height_aux], + [r_center, -v_one_half, fill_height_aux], + [-r_center, -half_r_center, fill_height_aux], + [r_center, -half_r_center, fill_height_aux], + [-r_center, -r_center, fill_height_aux], + [r_center, -r_center, fill_height_aux], + [-aux_column_width, -v_one_half, ctps_mid_height_top], + [aux_column_width, -v_one_half, ctps_mid_height_top], + [ + -aux_column_width, + -sep_distance_aux, + ctps_mid_height_top, + ], + [ + aux_column_width, + -sep_distance_aux, + ctps_mid_height_top, + ], + [ + -branch_thickness, + -branch_thickness, + ctps_mid_height_top, + ], + [ + branch_thickness, + -branch_thickness, + ctps_mid_height_top, + ], + [-aux_column_width, -v_one_half, v_one], + [aux_column_width, -v_one_half, v_one], + [-aux_column_width, -sep_distance_aux, v_one], + [aux_column_width, -sep_distance_aux, v_one], + [-branch_thickness, -branch_thickness, v_one], + [branch_thickness, -branch_thickness, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[1, 2, 2], - control_points=branch_neighbor_y_min_ctps, + spline_list.append( + _Bezier( + degrees=[1, 2, 2], + control_points=branch_neighbor_y_min_ctps, + ) ) - ) - branch_neighbor_y_max_ctps = _np.array( - [ - [-r_center, r_center, filling_height], - [r_center, r_center, filling_height], - [-r_center, half_r_center, filling_height], - [r_center, half_r_center, filling_height], - [-r_center, 0.5, filling_height], - [r_center, 0.5, filling_height], - [-branch_thickness, branch_thickness, ctps_mid_height_top], - [branch_thickness, branch_thickness, ctps_mid_height_top], - [ - -aux_column_width, - separator_distance, - ctps_mid_height_top, - ], + branch_neighbor_y_max_ctps = _np.array( [ - aux_column_width, - separator_distance, - ctps_mid_height_top, - ], - [-aux_column_width, 0.5, ctps_mid_height_top], - [aux_column_width, 0.5, ctps_mid_height_top], - [-branch_thickness, branch_thickness, 1.0], - [branch_thickness, branch_thickness, 1.0], - [-aux_column_width, separator_distance, 1.0], - [aux_column_width, separator_distance, 1.0], - [-aux_column_width, 0.5, 1.0], - [aux_column_width, 0.5, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + [-r_center, r_center, fill_height_aux], + [r_center, r_center, fill_height_aux], + [-r_center, half_r_center, fill_height_aux], + [r_center, half_r_center, fill_height_aux], + [-r_center, v_one_half, fill_height_aux], + [r_center, v_one_half, fill_height_aux], + [ + -branch_thickness, + branch_thickness, + ctps_mid_height_top, + ], + [ + branch_thickness, + branch_thickness, + ctps_mid_height_top, + ], + [ + -aux_column_width, + sep_distance_aux, + ctps_mid_height_top, + ], + [ + aux_column_width, + sep_distance_aux, + ctps_mid_height_top, + ], + [-aux_column_width, v_one_half, ctps_mid_height_top], + [aux_column_width, v_one_half, ctps_mid_height_top], + [-branch_thickness, branch_thickness, v_one], + [branch_thickness, branch_thickness, v_one], + [-aux_column_width, sep_distance_aux, v_one], + [aux_column_width, sep_distance_aux, v_one], + [-aux_column_width, v_one_half, v_one], + [aux_column_width, v_one_half, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[1, 2, 2], - control_points=branch_neighbor_y_max_ctps, + spline_list.append( + _Bezier( + degrees=[1, 2, 2], + control_points=branch_neighbor_y_max_ctps, + ) ) - ) - branch_x_min_y_min_ctps = _np.array( - [ - [-0.5, -0.5, filling_height], - [-half_r_center, -0.5, filling_height], - [-r_center, -0.5, filling_height], - [-0.5, -half_r_center, filling_height], - [-half_r_center, -half_r_center, filling_height], - [-r_center, -half_r_center, filling_height], - [-0.5, -r_center, filling_height], - [-half_r_center, -r_center, filling_height], - [-r_center, -r_center, filling_height], - [-0.5, -0.5, ctps_mid_height_top], - [-separator_distance, -0.5, ctps_mid_height_top], - [-aux_column_width, -0.5, ctps_mid_height_top], - [-0.5, -separator_distance, ctps_mid_height_top], - [ - -separator_distance, - -separator_distance, - ctps_mid_height_top, - ], - [ - -aux_column_width, - -separator_distance, - ctps_mid_height_top, - ], - [-0.5, -aux_column_width, ctps_mid_height_top], - [ - -separator_distance, - -aux_column_width, - ctps_mid_height_top, - ], - [ - -branch_thickness, - -branch_thickness, - ctps_mid_height_top, - ], - [-0.5, -0.5, 1.0], - [-separator_distance, -0.5, 1.0], - [-aux_column_width, -0.5, 1.0], - [-0.5, -separator_distance, 1.0], - [-separator_distance, -separator_distance, 1.0], - [-aux_column_width, -separator_distance, 1.0], - [-0.5, -aux_column_width, 1.0], - [-separator_distance, -aux_column_width, 1.0], - [-branch_thickness, -branch_thickness, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_min_y_min_ctps = _np.array( + [ + [-v_one_half, -v_one_half, fill_height_aux], + [-half_r_center, -v_one_half, fill_height_aux], + [-r_center, -v_one_half, fill_height_aux], + [-v_one_half, -half_r_center, fill_height_aux], + [-half_r_center, -half_r_center, fill_height_aux], + [-r_center, -half_r_center, fill_height_aux], + [-v_one_half, -r_center, fill_height_aux], + [-half_r_center, -r_center, fill_height_aux], + [-r_center, -r_center, fill_height_aux], + [-v_one_half, -v_one_half, ctps_mid_height_top], + [-sep_distance_aux, -v_one_half, ctps_mid_height_top], + [-aux_column_width, -v_one_half, ctps_mid_height_top], + [-v_one_half, -sep_distance_aux, ctps_mid_height_top], + [ + -sep_distance_aux, + -sep_distance_aux, + ctps_mid_height_top, + ], + [ + -aux_column_width, + -sep_distance_aux, + ctps_mid_height_top, + ], + [-v_one_half, -aux_column_width, ctps_mid_height_top], + [ + -sep_distance_aux, + -aux_column_width, + ctps_mid_height_top, + ], + [ + -branch_thickness, + -branch_thickness, + ctps_mid_height_top, + ], + [-v_one_half, -v_one_half, v_one], + [-sep_distance_aux, -v_one_half, v_one], + [-aux_column_width, -v_one_half, v_one], + [-v_one_half, -sep_distance_aux, v_one], + [-sep_distance_aux, -sep_distance_aux, v_one], + [-aux_column_width, -sep_distance_aux, v_one], + [-v_one_half, -aux_column_width, v_one], + [-sep_distance_aux, -aux_column_width, v_one], + [-branch_thickness, -branch_thickness, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_min_y_min_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_min_y_min_ctps, + ) ) - ) - branch_x_min_y_max_ctps = _np.array( - [ - [-0.5, r_center, filling_height], - [-half_r_center, r_center, filling_height], - [-r_center, r_center, filling_height], - [-0.5, half_r_center, filling_height], - [-half_r_center, half_r_center, filling_height], - [-r_center, half_r_center, filling_height], - [-0.5, 0.5, filling_height], - [-half_r_center, 0.5, filling_height], - [-r_center, 0.5, filling_height], - [-0.5, aux_column_width, ctps_mid_height_top], - [ - -separator_distance, - aux_column_width, - ctps_mid_height_top, - ], - [-branch_thickness, branch_thickness, ctps_mid_height_top], - [-0.5, separator_distance, ctps_mid_height_top], - [ - -separator_distance, - separator_distance, - ctps_mid_height_top, - ], - [ - -aux_column_width, - separator_distance, - ctps_mid_height_top, - ], - [-0.5, 0.5, ctps_mid_height_top], - [-separator_distance, 0.5, ctps_mid_height_top], - [-aux_column_width, 0.5, ctps_mid_height_top], - [-0.5, aux_column_width, 1.0], - [-separator_distance, aux_column_width, 1.0], - [-branch_thickness, branch_thickness, 1.0], - [-0.5, separator_distance, 1.0], - [-separator_distance, separator_distance, 1.0], - [-aux_column_width, separator_distance, 1.0], - [-0.5, 0.5, 1.0], - [-separator_distance, 0.5, 1.0], - [-aux_column_width, 0.5, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_min_y_max_ctps = _np.array( + [ + [-v_one_half, r_center, fill_height_aux], + [-half_r_center, r_center, fill_height_aux], + [-r_center, r_center, fill_height_aux], + [-v_one_half, half_r_center, fill_height_aux], + [-half_r_center, half_r_center, fill_height_aux], + [-r_center, half_r_center, fill_height_aux], + [-v_one_half, v_one_half, fill_height_aux], + [-half_r_center, v_one_half, fill_height_aux], + [-r_center, v_one_half, fill_height_aux], + [-v_one_half, aux_column_width, ctps_mid_height_top], + [ + -sep_distance_aux, + aux_column_width, + ctps_mid_height_top, + ], + [ + -branch_thickness, + branch_thickness, + ctps_mid_height_top, + ], + [-v_one_half, sep_distance_aux, ctps_mid_height_top], + [ + -sep_distance_aux, + sep_distance_aux, + ctps_mid_height_top, + ], + [ + -aux_column_width, + sep_distance_aux, + ctps_mid_height_top, + ], + [-v_one_half, v_one_half, ctps_mid_height_top], + [-sep_distance_aux, v_one_half, ctps_mid_height_top], + [-aux_column_width, v_one_half, ctps_mid_height_top], + [-v_one_half, aux_column_width, v_one], + [-sep_distance_aux, aux_column_width, v_one], + [-branch_thickness, branch_thickness, v_one], + [-v_one_half, sep_distance_aux, v_one], + [-sep_distance_aux, sep_distance_aux, v_one], + [-aux_column_width, sep_distance_aux, v_one], + [-v_one_half, v_one_half, v_one], + [-sep_distance_aux, v_one_half, v_one], + [-aux_column_width, v_one_half, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_min_y_max_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_min_y_max_ctps, + ) ) - ) - branch_x_max_y_min_ctps = _np.array( - [ - [r_center, -0.5, filling_height], - [half_r_center, -0.5, filling_height], - [0.5, -0.5, filling_height], - [r_center, -half_r_center, filling_height], - [half_r_center, -half_r_center, filling_height], - [0.5, -half_r_center, filling_height], - [r_center, -r_center, filling_height], - [half_r_center, -r_center, filling_height], - [0.5, -r_center, filling_height], - [aux_column_width, -0.5, ctps_mid_height_top], - [separator_distance, -0.5, ctps_mid_height_top], - [0.5, -0.5, ctps_mid_height_top], - [ - aux_column_width, - -separator_distance, - ctps_mid_height_top, - ], - [ - separator_distance, - -separator_distance, - ctps_mid_height_top, - ], - [0.5, -separator_distance, ctps_mid_height_top], - [branch_thickness, -branch_thickness, ctps_mid_height_top], - [ - separator_distance, - -aux_column_width, - ctps_mid_height_top, - ], - [0.5, -aux_column_width, ctps_mid_height_top], - [aux_column_width, -0.5, 1.0], - [separator_distance, -0.5, 1.0], - [0.5, -0.5, 1.0], - [aux_column_width, -separator_distance, 1.0], - [separator_distance, -separator_distance, 1.0], - [0.5, -separator_distance, 1.0], - [branch_thickness, -branch_thickness, 1.0], - [separator_distance, -aux_column_width, 1.0], - [0.5, -aux_column_width, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_max_y_min_ctps = _np.array( + [ + [r_center, -v_one_half, fill_height_aux], + [half_r_center, -v_one_half, fill_height_aux], + [v_one_half, -v_one_half, fill_height_aux], + [r_center, -half_r_center, fill_height_aux], + [half_r_center, -half_r_center, fill_height_aux], + [v_one_half, -half_r_center, fill_height_aux], + [r_center, -r_center, fill_height_aux], + [half_r_center, -r_center, fill_height_aux], + [v_one_half, -r_center, fill_height_aux], + [aux_column_width, -v_one_half, ctps_mid_height_top], + [sep_distance_aux, -v_one_half, ctps_mid_height_top], + [v_one_half, -v_one_half, ctps_mid_height_top], + [ + aux_column_width, + -sep_distance_aux, + ctps_mid_height_top, + ], + [ + sep_distance_aux, + -sep_distance_aux, + ctps_mid_height_top, + ], + [v_one_half, -sep_distance_aux, ctps_mid_height_top], + [ + branch_thickness, + -branch_thickness, + ctps_mid_height_top, + ], + [ + sep_distance_aux, + -aux_column_width, + ctps_mid_height_top, + ], + [v_one_half, -aux_column_width, ctps_mid_height_top], + [aux_column_width, -v_one_half, v_one], + [sep_distance_aux, -v_one_half, v_one], + [v_one_half, -v_one_half, v_one], + [aux_column_width, -sep_distance_aux, v_one], + [sep_distance_aux, -sep_distance_aux, v_one], + [v_one_half, -sep_distance_aux, v_one], + [branch_thickness, -branch_thickness, v_one], + [sep_distance_aux, -aux_column_width, v_one], + [v_one_half, -aux_column_width, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_max_y_min_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_max_y_min_ctps, + ) ) - ) - branch_x_max_y_max_ctps = _np.array( - [ - [r_center, r_center, filling_height], - [half_r_center, r_center, filling_height], - [0.5, r_center, filling_height], - [r_center, half_r_center, filling_height], - [half_r_center, half_r_center, filling_height], - [0.5, half_r_center, filling_height], - [r_center, 0.5, filling_height], - [half_r_center, 0.5, filling_height], - [0.5, 0.5, filling_height], - [branch_thickness, branch_thickness, ctps_mid_height_top], - [ - separator_distance, - aux_column_width, - ctps_mid_height_top, - ], - [0.5, aux_column_width, ctps_mid_height_top], - [ - aux_column_width, - separator_distance, - ctps_mid_height_top, - ], - [ - separator_distance, - separator_distance, - ctps_mid_height_top, - ], - [0.5, separator_distance, ctps_mid_height_top], - [aux_column_width, 0.5, ctps_mid_height_top], - [separator_distance, 0.5, ctps_mid_height_top], - [0.5, 0.5, ctps_mid_height_top], - [branch_thickness, branch_thickness, 1.0], - [separator_distance, aux_column_width, 1.0], - [0.5, aux_column_width, 1.0], - [aux_column_width, separator_distance, 1.0], - [separator_distance, separator_distance, 1.0], - [0.5, separator_distance, 1.0], - [aux_column_width, 0.5, 1.0], - [separator_distance, 0.5, 1.0], - [0.5, 0.5, 1.0], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_max_y_max_ctps = _np.array( + [ + [r_center, r_center, fill_height_aux], + [half_r_center, r_center, fill_height_aux], + [v_one_half, r_center, fill_height_aux], + [r_center, half_r_center, fill_height_aux], + [half_r_center, half_r_center, fill_height_aux], + [v_one_half, half_r_center, fill_height_aux], + [r_center, v_one_half, fill_height_aux], + [half_r_center, v_one_half, fill_height_aux], + [v_one_half, v_one_half, fill_height_aux], + [ + branch_thickness, + branch_thickness, + ctps_mid_height_top, + ], + [ + sep_distance_aux, + aux_column_width, + ctps_mid_height_top, + ], + [v_one_half, aux_column_width, ctps_mid_height_top], + [ + aux_column_width, + sep_distance_aux, + ctps_mid_height_top, + ], + [ + sep_distance_aux, + sep_distance_aux, + ctps_mid_height_top, + ], + [v_one_half, sep_distance_aux, ctps_mid_height_top], + [aux_column_width, v_one_half, ctps_mid_height_top], + [sep_distance_aux, v_one_half, ctps_mid_height_top], + [v_one_half, v_one_half, ctps_mid_height_top], + [branch_thickness, branch_thickness, v_one], + [sep_distance_aux, aux_column_width, v_one], + [v_one_half, aux_column_width, v_one], + [aux_column_width, sep_distance_aux, v_one], + [sep_distance_aux, sep_distance_aux, v_one], + [v_one_half, sep_distance_aux, v_one], + [aux_column_width, v_one_half, v_one], + [sep_distance_aux, v_one_half, v_one], + [v_one_half, v_one_half, v_one], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_max_y_max_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_max_y_max_ctps, + ) ) - ) - - return (spline_list, None) - elif closure == "z_max": - branch_thickness = parameters.flatten()[4] - branch_neighbor_x_min_ctps = _np.array( - [ - [-0.5, -aux_column_width, 0.0], - [-separator_distance, -aux_column_width, 0.0], - [-branch_thickness, -branch_thickness, 0.0], - [-0.5, aux_column_width, 0.0], - [-separator_distance, aux_column_width, 0.0], - [-branch_thickness, branch_thickness, 0.0], - [-0.5, -aux_column_width, ctps_mid_height_bottom], - [ - -separator_distance, - -aux_column_width, - ctps_mid_height_bottom, - ], - [ - -branch_thickness, - -branch_thickness, - ctps_mid_height_bottom, - ], - [-0.5, aux_column_width, ctps_mid_height_bottom], + elif closure == "z_max": + branch_neighbor_x_min_ctps = _np.array( [ - -separator_distance, - aux_column_width, - ctps_mid_height_bottom, - ], - [ - -branch_thickness, - branch_thickness, - ctps_mid_height_bottom, - ], - [-0.5, -r_center, inv_filling_height], - [-half_r_center, -r_center, inv_filling_height], - [-r_center, -r_center, inv_filling_height], - [-0.5, r_center, inv_filling_height], - [-half_r_center, r_center, inv_filling_height], - [-r_center, r_center, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + [-v_one_half, -aux_column_width, v_zero], + [-sep_distance_aux, -aux_column_width, v_zero], + [-branch_thickness, -branch_thickness, v_zero], + [-v_one_half, aux_column_width, v_zero], + [-sep_distance_aux, aux_column_width, v_zero], + [-branch_thickness, branch_thickness, v_zero], + [ + -v_one_half, + -aux_column_width, + ctps_mid_height_bottom, + ], + [ + -sep_distance_aux, + -aux_column_width, + ctps_mid_height_bottom, + ], + [ + -branch_thickness, + -branch_thickness, + ctps_mid_height_bottom, + ], + [ + -v_one_half, + aux_column_width, + ctps_mid_height_bottom, + ], + [ + -sep_distance_aux, + aux_column_width, + ctps_mid_height_bottom, + ], + [ + -branch_thickness, + branch_thickness, + ctps_mid_height_bottom, + ], + [-v_one_half, -r_center, inv_filling_height], + [-half_r_center, -r_center, inv_filling_height], + [-r_center, -r_center, inv_filling_height], + [-v_one_half, r_center, inv_filling_height], + [-half_r_center, r_center, inv_filling_height], + [-r_center, r_center, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 1, 2], - control_points=branch_neighbor_x_min_ctps, + spline_list.append( + _Bezier( + degrees=[2, 1, 2], + control_points=branch_neighbor_x_min_ctps, + ) ) - ) - branch_neighbor_x_max_ctps = _np.array( - [ - [branch_thickness, -branch_thickness, 0.0], - [separator_distance, -aux_column_width, 0.0], - [0.5, -aux_column_width, 0.0], - [branch_thickness, branch_thickness, 0.0], - [separator_distance, aux_column_width, 0.0], - [0.5, aux_column_width, 0.0], - [ - branch_thickness, - -branch_thickness, - ctps_mid_height_bottom, - ], - [ - separator_distance, - -aux_column_width, - ctps_mid_height_bottom, - ], - [0.5, -aux_column_width, ctps_mid_height_bottom], - [ - branch_thickness, - branch_thickness, - ctps_mid_height_bottom, - ], + branch_neighbor_x_max_ctps = _np.array( [ - separator_distance, - aux_column_width, - ctps_mid_height_bottom, - ], - [0.5, aux_column_width, ctps_mid_height_bottom], - [r_center, -r_center, inv_filling_height], - [half_r_center, -r_center, inv_filling_height], - [0.5, -r_center, inv_filling_height], - [r_center, r_center, inv_filling_height], - [half_r_center, r_center, inv_filling_height], - [0.5, r_center, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + [branch_thickness, -branch_thickness, v_zero], + [sep_distance_aux, -aux_column_width, v_zero], + [v_one_half, -aux_column_width, v_zero], + [branch_thickness, branch_thickness, v_zero], + [sep_distance_aux, aux_column_width, v_zero], + [v_one_half, aux_column_width, v_zero], + [ + branch_thickness, + -branch_thickness, + ctps_mid_height_bottom, + ], + [ + sep_distance_aux, + -aux_column_width, + ctps_mid_height_bottom, + ], + [ + v_one_half, + -aux_column_width, + ctps_mid_height_bottom, + ], + [ + branch_thickness, + branch_thickness, + ctps_mid_height_bottom, + ], + [ + sep_distance_aux, + aux_column_width, + ctps_mid_height_bottom, + ], + [v_one_half, aux_column_width, ctps_mid_height_bottom], + [r_center, -r_center, inv_filling_height], + [half_r_center, -r_center, inv_filling_height], + [v_one_half, -r_center, inv_filling_height], + [r_center, r_center, inv_filling_height], + [half_r_center, r_center, inv_filling_height], + [v_one_half, r_center, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 1, 2], - control_points=branch_neighbor_x_max_ctps, + spline_list.append( + _Bezier( + degrees=[2, 1, 2], + control_points=branch_neighbor_x_max_ctps, + ) ) - ) - branch_neighbor_y_min_ctps = _np.array( - [ - [-aux_column_width, -0.5, 0.0], - [aux_column_width, -0.5, 0.0], - [-aux_column_width, -separator_distance, 0.0], - [aux_column_width, -separator_distance, 0.0], - [-branch_thickness, -branch_thickness, 0.0], - [branch_thickness, -branch_thickness, 0.0], - [-aux_column_width, -0.5, ctps_mid_height_bottom], - [aux_column_width, -0.5, ctps_mid_height_bottom], - [ - -aux_column_width, - -separator_distance, - ctps_mid_height_bottom, - ], + branch_neighbor_y_min_ctps = _np.array( [ - aux_column_width, - -separator_distance, - ctps_mid_height_bottom, - ], - [ - -branch_thickness, - -branch_thickness, - ctps_mid_height_bottom, - ], - [ - branch_thickness, - -branch_thickness, - ctps_mid_height_bottom, - ], - [-r_center, -0.5, inv_filling_height], - [r_center, -0.5, inv_filling_height], - [-r_center, -half_r_center, inv_filling_height], - [r_center, -half_r_center, inv_filling_height], - [-r_center, -r_center, inv_filling_height], - [r_center, -r_center, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + [-aux_column_width, -v_one_half, v_zero], + [aux_column_width, -v_one_half, v_zero], + [-aux_column_width, -sep_distance_aux, v_zero], + [aux_column_width, -sep_distance_aux, v_zero], + [-branch_thickness, -branch_thickness, v_zero], + [branch_thickness, -branch_thickness, v_zero], + [ + -aux_column_width, + -v_one_half, + ctps_mid_height_bottom, + ], + [ + aux_column_width, + -v_one_half, + ctps_mid_height_bottom, + ], + [ + -aux_column_width, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + aux_column_width, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + -branch_thickness, + -branch_thickness, + ctps_mid_height_bottom, + ], + [ + branch_thickness, + -branch_thickness, + ctps_mid_height_bottom, + ], + [-r_center, -v_one_half, inv_filling_height], + [r_center, -v_one_half, inv_filling_height], + [-r_center, -half_r_center, inv_filling_height], + [r_center, -half_r_center, inv_filling_height], + [-r_center, -r_center, inv_filling_height], + [r_center, -r_center, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[1, 2, 2], - control_points=branch_neighbor_y_min_ctps, + spline_list.append( + _Bezier( + degrees=[1, 2, 2], + control_points=branch_neighbor_y_min_ctps, + ) ) - ) - branch_neighbor_y_max_ctps = _np.array( - [ - [-branch_thickness, branch_thickness, 0.0], - [branch_thickness, branch_thickness, 0.0], - [-aux_column_width, separator_distance, 0.0], - [aux_column_width, separator_distance, 0.0], - [-aux_column_width, 0.5, 0.0], - [aux_column_width, 0.5, 0.0], + branch_neighbor_y_max_ctps = _np.array( [ - -branch_thickness, - branch_thickness, - ctps_mid_height_bottom, - ], - [ - branch_thickness, - branch_thickness, - ctps_mid_height_bottom, - ], - [ - -aux_column_width, - separator_distance, - ctps_mid_height_bottom, - ], - [ - aux_column_width, - separator_distance, - ctps_mid_height_bottom, - ], - [-aux_column_width, 0.5, ctps_mid_height_bottom], - [aux_column_width, 0.5, ctps_mid_height_bottom], - [-r_center, r_center, inv_filling_height], - [r_center, r_center, inv_filling_height], - [-r_center, half_r_center, inv_filling_height], - [r_center, half_r_center, inv_filling_height], - [-r_center, 0.5, inv_filling_height], - [r_center, 0.5, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + [-branch_thickness, branch_thickness, v_zero], + [branch_thickness, branch_thickness, v_zero], + [-aux_column_width, sep_distance_aux, v_zero], + [aux_column_width, sep_distance_aux, v_zero], + [-aux_column_width, v_one_half, v_zero], + [aux_column_width, v_one_half, v_zero], + [ + -branch_thickness, + branch_thickness, + ctps_mid_height_bottom, + ], + [ + branch_thickness, + branch_thickness, + ctps_mid_height_bottom, + ], + [ + -aux_column_width, + sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + aux_column_width, + sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + -aux_column_width, + v_one_half, + ctps_mid_height_bottom, + ], + [aux_column_width, v_one_half, ctps_mid_height_bottom], + [-r_center, r_center, inv_filling_height], + [r_center, r_center, inv_filling_height], + [-r_center, half_r_center, inv_filling_height], + [r_center, half_r_center, inv_filling_height], + [-r_center, v_one_half, inv_filling_height], + [r_center, v_one_half, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[1, 2, 2], - control_points=branch_neighbor_y_max_ctps, + spline_list.append( + _Bezier( + degrees=[1, 2, 2], + control_points=branch_neighbor_y_max_ctps, + ) ) - ) - branch_x_min_y_min_ctps = _np.array( - [ - [-0.5, -0.5, 0.0], - [-separator_distance, -0.5, 0.0], - [-aux_column_width, -0.5, 0.0], - [-0.5, -separator_distance, 0.0], - [-separator_distance, -separator_distance, 0.0], - [-aux_column_width, -separator_distance, 0.0], - [-0.5, -aux_column_width, 0.0], - [-separator_distance, -aux_column_width, 0.0], - [-branch_thickness, -branch_thickness, 0.0], - [-0.5, -0.5, ctps_mid_height_bottom], - [-separator_distance, -0.5, ctps_mid_height_bottom], - [-aux_column_width, -0.5, ctps_mid_height_bottom], - [-0.5, -separator_distance, ctps_mid_height_bottom], - [ - -separator_distance, - -separator_distance, - ctps_mid_height_bottom, - ], - [ - -aux_column_width, - -separator_distance, - ctps_mid_height_bottom, - ], - [-0.5, -aux_column_width, ctps_mid_height_bottom], - [ - -separator_distance, - -aux_column_width, - ctps_mid_height_bottom, - ], - [ - -branch_thickness, - -branch_thickness, - ctps_mid_height_bottom, - ], - [-0.5, -0.5, inv_filling_height], - [-half_r_center, -0.5, inv_filling_height], - [-r_center, -0.5, inv_filling_height], - [-0.5, -half_r_center, inv_filling_height], - [-half_r_center, -half_r_center, inv_filling_height], - [-r_center, -half_r_center, inv_filling_height], - [-0.5, -r_center, inv_filling_height], - [-half_r_center, -r_center, inv_filling_height], - [-r_center, -r_center, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_min_y_min_ctps = _np.array( + [ + [-v_one_half, -v_one_half, v_zero], + [-sep_distance_aux, -v_one_half, v_zero], + [-aux_column_width, -v_one_half, v_zero], + [-v_one_half, -sep_distance_aux, v_zero], + [-sep_distance_aux, -sep_distance_aux, v_zero], + [-aux_column_width, -sep_distance_aux, v_zero], + [-v_one_half, -aux_column_width, v_zero], + [-sep_distance_aux, -aux_column_width, v_zero], + [-branch_thickness, -branch_thickness, v_zero], + [-v_one_half, -v_one_half, ctps_mid_height_bottom], + [ + -sep_distance_aux, + -v_one_half, + ctps_mid_height_bottom, + ], + [ + -aux_column_width, + -v_one_half, + ctps_mid_height_bottom, + ], + [ + -v_one_half, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + -sep_distance_aux, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + -aux_column_width, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + -v_one_half, + -aux_column_width, + ctps_mid_height_bottom, + ], + [ + -sep_distance_aux, + -aux_column_width, + ctps_mid_height_bottom, + ], + [ + -branch_thickness, + -branch_thickness, + ctps_mid_height_bottom, + ], + [-v_one_half, -v_one_half, inv_filling_height], + [-half_r_center, -v_one_half, inv_filling_height], + [-r_center, -v_one_half, inv_filling_height], + [-v_one_half, -half_r_center, inv_filling_height], + [-half_r_center, -half_r_center, inv_filling_height], + [-r_center, -half_r_center, inv_filling_height], + [-v_one_half, -r_center, inv_filling_height], + [-half_r_center, -r_center, inv_filling_height], + [-r_center, -r_center, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_min_y_min_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_min_y_min_ctps, + ) ) - ) - branch_x_max_y_max_ctps = _np.array( - [ - [branch_thickness, branch_thickness, 0.0], - [separator_distance, aux_column_width, 0.0], - [0.5, aux_column_width, 0.0], - [aux_column_width, separator_distance, 0.0], - [separator_distance, separator_distance, 0.0], - [0.5, separator_distance, 0.0], - [aux_column_width, 0.5, 0.0], - [separator_distance, 0.5, 0.0], - [0.5, 0.5, 0.0], - [ - branch_thickness, - branch_thickness, - ctps_mid_height_bottom, - ], - [ - separator_distance, - aux_column_width, - ctps_mid_height_bottom, - ], - [0.5, aux_column_width, ctps_mid_height_bottom], - [ - aux_column_width, - separator_distance, - ctps_mid_height_bottom, - ], - [ - separator_distance, - separator_distance, - ctps_mid_height_bottom, - ], - [0.5, separator_distance, ctps_mid_height_bottom], - [aux_column_width, 0.5, ctps_mid_height_bottom], - [separator_distance, 0.5, ctps_mid_height_bottom], - [0.5, 0.5, ctps_mid_height_bottom], - [r_center, r_center, inv_filling_height], - [half_r_center, r_center, inv_filling_height], - [0.5, r_center, inv_filling_height], - [r_center, half_r_center, inv_filling_height], - [half_r_center, half_r_center, inv_filling_height], - [0.5, half_r_center, inv_filling_height], - [r_center, 0.5, inv_filling_height], - [half_r_center, 0.5, inv_filling_height], - [0.5, 0.5, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_max_y_max_ctps = _np.array( + [ + [branch_thickness, branch_thickness, v_zero], + [sep_distance_aux, aux_column_width, v_zero], + [v_one_half, aux_column_width, v_zero], + [aux_column_width, sep_distance_aux, v_zero], + [sep_distance_aux, sep_distance_aux, v_zero], + [v_one_half, sep_distance_aux, v_zero], + [aux_column_width, v_one_half, v_zero], + [sep_distance_aux, v_one_half, v_zero], + [v_one_half, v_one_half, v_zero], + [ + branch_thickness, + branch_thickness, + ctps_mid_height_bottom, + ], + [ + sep_distance_aux, + aux_column_width, + ctps_mid_height_bottom, + ], + [v_one_half, aux_column_width, ctps_mid_height_bottom], + [ + aux_column_width, + sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + sep_distance_aux, + sep_distance_aux, + ctps_mid_height_bottom, + ], + [v_one_half, sep_distance_aux, ctps_mid_height_bottom], + [aux_column_width, v_one_half, ctps_mid_height_bottom], + [sep_distance_aux, v_one_half, ctps_mid_height_bottom], + [v_one_half, v_one_half, ctps_mid_height_bottom], + [r_center, r_center, inv_filling_height], + [half_r_center, r_center, inv_filling_height], + [v_one_half, r_center, inv_filling_height], + [r_center, half_r_center, inv_filling_height], + [half_r_center, half_r_center, inv_filling_height], + [v_one_half, half_r_center, inv_filling_height], + [r_center, v_one_half, inv_filling_height], + [half_r_center, v_one_half, inv_filling_height], + [v_one_half, v_one_half, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_max_y_max_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_max_y_max_ctps, + ) ) - ) - branch_x_max_y_min_ctps = _np.array( - [ - [aux_column_width, -0.5, 0.0], - [separator_distance, -0.5, 0.0], - [0.5, -0.5, 0.0], - [aux_column_width, -separator_distance, 0.0], - [separator_distance, -separator_distance, 0.0], - [0.5, -separator_distance, 0.0], - [branch_thickness, -branch_thickness, 0.0], - [separator_distance, -aux_column_width, 0.0], - [0.5, -aux_column_width, 0.0], - [aux_column_width, -0.5, ctps_mid_height_bottom], - [separator_distance, -0.5, ctps_mid_height_bottom], - [0.5, -0.5, ctps_mid_height_bottom], - [ - aux_column_width, - -separator_distance, - ctps_mid_height_bottom, - ], - [ - separator_distance, - -separator_distance, - ctps_mid_height_bottom, - ], - [0.5, -separator_distance, ctps_mid_height_bottom], - [ - branch_thickness, - -branch_thickness, - ctps_mid_height_bottom, - ], - [ - separator_distance, - -aux_column_width, - ctps_mid_height_bottom, - ], - [0.5, -aux_column_width, ctps_mid_height_bottom], - [r_center, -0.5, inv_filling_height], - [half_r_center, -0.5, inv_filling_height], - [0.5, -0.5, inv_filling_height], - [r_center, -half_r_center, inv_filling_height], - [half_r_center, -half_r_center, inv_filling_height], - [0.5, -half_r_center, inv_filling_height], - [r_center, -r_center, inv_filling_height], - [half_r_center, -r_center, inv_filling_height], - [0.5, -r_center, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_max_y_min_ctps = _np.array( + [ + [aux_column_width, -v_one_half, v_zero], + [sep_distance_aux, -v_one_half, v_zero], + [v_one_half, -v_one_half, v_zero], + [aux_column_width, -sep_distance_aux, v_zero], + [sep_distance_aux, -sep_distance_aux, v_zero], + [v_one_half, -sep_distance_aux, v_zero], + [branch_thickness, -branch_thickness, v_zero], + [sep_distance_aux, -aux_column_width, v_zero], + [v_one_half, -aux_column_width, v_zero], + [ + aux_column_width, + -v_one_half, + ctps_mid_height_bottom, + ], + [ + sep_distance_aux, + -v_one_half, + ctps_mid_height_bottom, + ], + [v_one_half, -v_one_half, ctps_mid_height_bottom], + [ + aux_column_width, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + sep_distance_aux, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + v_one_half, + -sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + branch_thickness, + -branch_thickness, + ctps_mid_height_bottom, + ], + [ + sep_distance_aux, + -aux_column_width, + ctps_mid_height_bottom, + ], + [ + v_one_half, + -aux_column_width, + ctps_mid_height_bottom, + ], + [r_center, -v_one_half, inv_filling_height], + [half_r_center, -v_one_half, inv_filling_height], + [v_one_half, -v_one_half, inv_filling_height], + [r_center, -half_r_center, inv_filling_height], + [half_r_center, -half_r_center, inv_filling_height], + [v_one_half, -half_r_center, inv_filling_height], + [r_center, -r_center, inv_filling_height], + [half_r_center, -r_center, inv_filling_height], + [v_one_half, -r_center, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_max_y_min_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_max_y_min_ctps, + ) ) - ) - branch_x_min_y_max_ctps = _np.array( - [ - [-0.5, aux_column_width, 0.0], - [-separator_distance, aux_column_width, 0.0], - [-branch_thickness, branch_thickness, 0.0], - [-0.5, separator_distance, 0.0], - [-separator_distance, separator_distance, 0.0], - [-aux_column_width, separator_distance, 0.0], - [-0.5, 0.5, 0.0], - [-separator_distance, 0.5, 0.0], - [-aux_column_width, 0.5, 0.0], - [-0.5, aux_column_width, ctps_mid_height_bottom], - [ - -separator_distance, - aux_column_width, - ctps_mid_height_bottom, - ], - [ - -branch_thickness, - branch_thickness, - ctps_mid_height_bottom, - ], - [-0.5, separator_distance, ctps_mid_height_bottom], - [ - -separator_distance, - separator_distance, - ctps_mid_height_bottom, - ], - [ - -aux_column_width, - separator_distance, - ctps_mid_height_bottom, - ], - [-0.5, 0.5, ctps_mid_height_bottom], - [-separator_distance, 0.5, ctps_mid_height_bottom], - [-aux_column_width, 0.5, ctps_mid_height_bottom], - [-0.5, r_center, inv_filling_height], - [-half_r_center, r_center, inv_filling_height], - [-r_center, r_center, inv_filling_height], - [-0.5, half_r_center, inv_filling_height], - [-half_r_center, half_r_center, inv_filling_height], - [-r_center, half_r_center, inv_filling_height], - [-0.5, 0.5, inv_filling_height], - [-half_r_center, 0.5, inv_filling_height], - [-r_center, 0.5, inv_filling_height], - ] - ) + _np.array([0.5, 0.5, 0.0]) + branch_x_min_y_max_ctps = _np.array( + [ + [-v_one_half, aux_column_width, v_zero], + [-sep_distance_aux, aux_column_width, v_zero], + [-branch_thickness, branch_thickness, v_zero], + [-v_one_half, sep_distance_aux, v_zero], + [-sep_distance_aux, sep_distance_aux, v_zero], + [-aux_column_width, sep_distance_aux, v_zero], + [-v_one_half, v_one_half, v_zero], + [-sep_distance_aux, v_one_half, v_zero], + [-aux_column_width, v_one_half, v_zero], + [ + -v_one_half, + aux_column_width, + ctps_mid_height_bottom, + ], + [ + -sep_distance_aux, + aux_column_width, + ctps_mid_height_bottom, + ], + [ + -branch_thickness, + branch_thickness, + ctps_mid_height_bottom, + ], + [ + -v_one_half, + sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + -sep_distance_aux, + sep_distance_aux, + ctps_mid_height_bottom, + ], + [ + -aux_column_width, + sep_distance_aux, + ctps_mid_height_bottom, + ], + [-v_one_half, v_one_half, ctps_mid_height_bottom], + [ + -sep_distance_aux, + v_one_half, + ctps_mid_height_bottom, + ], + [ + -aux_column_width, + v_one_half, + ctps_mid_height_bottom, + ], + [-v_one_half, r_center, inv_filling_height], + [-half_r_center, r_center, inv_filling_height], + [-r_center, r_center, inv_filling_height], + [-v_one_half, half_r_center, inv_filling_height], + [-half_r_center, half_r_center, inv_filling_height], + [-r_center, half_r_center, inv_filling_height], + [-v_one_half, v_one_half, inv_filling_height], + [-half_r_center, v_one_half, inv_filling_height], + [-r_center, v_one_half, inv_filling_height], + ] + ) + _np.array([v_one_half, v_one_half, v_zero]) - spline_list.append( - _Bezier( - degrees=[2, 2, 2], control_points=branch_x_min_y_max_ctps + spline_list.append( + _Bezier( + degrees=[2, 2, 2], + control_points=branch_x_min_y_max_ctps, + ) ) - ) + else: + raise ValueError("Corner Type not supported") - return (spline_list, None) - else: - raise ValueError("Corner Type not supported") + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) + + return (splines, derivatives) def create_tile( self, @@ -922,7 +1070,7 @@ def create_tile( """ if not isinstance(center_expansion, float): - raise ValueError("Invalid Type") + raise ValueError("Invalid type for center_expansion") if not ((center_expansion > 0.5) and (center_expansion < 1.5)): raise ValueError("Center Expansion must be in (.5, 1.5)") @@ -942,16 +1090,17 @@ def create_tile( * 0.2 ) + self.check_params(parameters) + if parameter_sensitivities is not None: + self.check_param_derivatives(parameter_sensitivities) + n_derivatives = parameter_sensitivities.shape[2] derivatives = [] else: n_derivatives = 0 derivatives = None - self.check_params(parameters) - self.check_param_derivatives(parameter_sensitivities) - if _np.any(parameters < min_radius) or _np.any( parameters > max_radius ): @@ -999,6 +1148,8 @@ def create_tile( v_one_half = 0.5 center_point = _np.array([0.5, 0.5, 0.5]) + + sep_distance = separator_distance else: sensitivities_i = parameter_sensitivities[ :, 0, i_derivative - 1 @@ -1032,6 +1183,8 @@ def create_tile( v_one_half = 0.0 center_point = _np.zeros(3) + sep_distance = 0.0 + # Init return type spline_list = [] @@ -1040,18 +1193,18 @@ def create_tile( _np.array( [ [-v_one_half, -v_one_half, -aux_column_width], - [-separator_distance, -v_one_half, -aux_column_width], + [-sep_distance, -v_one_half, -aux_column_width], [-y_min_r, -v_one_half, -y_min_r], - [-v_one_half, -separator_distance, -aux_column_width], + [-v_one_half, -sep_distance, -aux_column_width], [-hd_center, -hd_center, -aux_column_width], [-aux_y_min, -hd_center, -aux_y_min], [-v_one_half, -x_min_r, -x_min_r], [-hd_center, -aux_x_min, -aux_x_min], [-center_r, -center_r, -center_r], [-v_one_half, -v_one_half, aux_column_width], - [-separator_distance, -v_one_half, aux_column_width], + [-sep_distance, -v_one_half, aux_column_width], [-y_min_r, -v_one_half, y_min_r], - [-v_one_half, -separator_distance, aux_column_width], + [-v_one_half, -sep_distance, aux_column_width], [-hd_center, -hd_center, aux_column_width], [-aux_y_min, -hd_center, aux_y_min], [-v_one_half, -x_min_r, x_min_r], @@ -1066,20 +1219,20 @@ def create_tile( _np.array( [ [y_min_r, -v_one_half, -y_min_r], - [separator_distance, -v_one_half, -aux_column_width], + [sep_distance, -v_one_half, -aux_column_width], [v_one_half, -v_one_half, -aux_column_width], [aux_y_min, -hd_center, -aux_y_min], [hd_center, -hd_center, -aux_column_width], - [v_one_half, -separator_distance, -aux_column_width], + [v_one_half, -sep_distance, -aux_column_width], [center_r, -center_r, -center_r], [hd_center, -aux_x_max, -aux_x_max], [v_one_half, -x_max_r, -x_max_r], [y_min_r, -v_one_half, y_min_r], - [separator_distance, -v_one_half, aux_column_width], + [sep_distance, -v_one_half, aux_column_width], [v_one_half, -v_one_half, aux_column_width], [aux_y_min, -hd_center, aux_y_min], [hd_center, -hd_center, aux_column_width], - [v_one_half, -separator_distance, aux_column_width], + [v_one_half, -sep_distance, aux_column_width], [center_r, -center_r, center_r], [hd_center, -aux_x_max, aux_x_max], [v_one_half, -x_max_r, x_max_r], @@ -1094,20 +1247,20 @@ def create_tile( [-v_one_half, x_min_r, -x_min_r], [-hd_center, aux_x_min, -aux_x_min], [-center_r, center_r, -center_r], - [-v_one_half, separator_distance, -aux_column_width], + [-v_one_half, sep_distance, -aux_column_width], [-hd_center, hd_center, -aux_column_width], [-aux_y_max, hd_center, -aux_y_max], [-v_one_half, v_one_half, -aux_column_width], - [-separator_distance, v_one_half, -aux_column_width], + [-sep_distance, v_one_half, -aux_column_width], [-y_max_r, v_one_half, -y_max_r], [-v_one_half, x_min_r, x_min_r], [-hd_center, aux_x_min, aux_x_min], [-center_r, center_r, center_r], - [-v_one_half, separator_distance, aux_column_width], + [-v_one_half, sep_distance, aux_column_width], [-hd_center, hd_center, aux_column_width], [-aux_y_max, hd_center, aux_y_max], [-v_one_half, v_one_half, aux_column_width], - [-separator_distance, v_one_half, aux_column_width], + [-sep_distance, v_one_half, aux_column_width], [-y_max_r, v_one_half, y_max_r], ] ) @@ -1122,18 +1275,18 @@ def create_tile( [v_one_half, x_max_r, -x_max_r], [aux_y_max, hd_center, -aux_y_max], [hd_center, hd_center, -aux_column_width], - [v_one_half, separator_distance, -aux_column_width], + [v_one_half, sep_distance, -aux_column_width], [y_max_r, v_one_half, -y_max_r], - [separator_distance, v_one_half, -aux_column_width], + [sep_distance, v_one_half, -aux_column_width], [v_one_half, v_one_half, -aux_column_width], [center_r, center_r, center_r], [hd_center, aux_x_max, aux_x_max], [v_one_half, x_max_r, x_max_r], [aux_y_max, hd_center, aux_y_max], [hd_center, hd_center, aux_column_width], - [v_one_half, separator_distance, aux_column_width], + [v_one_half, sep_distance, aux_column_width], [y_max_r, v_one_half, y_max_r], - [separator_distance, v_one_half, aux_column_width], + [sep_distance, v_one_half, aux_column_width], [v_one_half, v_one_half, aux_column_width], ] ) @@ -1144,15 +1297,15 @@ def create_tile( _np.array( [ [-v_one_half, -aux_column_width, -v_one_half], - [-separator_distance, -aux_column_width, -v_one_half], + [-sep_distance, -aux_column_width, -v_one_half], [-z_min_r, -z_min_r, -v_one_half], [-v_one_half, aux_column_width, -v_one_half], - [-separator_distance, aux_column_width, -v_one_half], + [-sep_distance, aux_column_width, -v_one_half], [-z_min_r, z_min_r, -v_one_half], - [-v_one_half, -aux_column_width, -separator_distance], + [-v_one_half, -aux_column_width, -sep_distance], [-hd_center, -aux_column_width, -hd_center], [-aux_z_min, -aux_z_min, -hd_center], - [-v_one_half, aux_column_width, -separator_distance], + [-v_one_half, aux_column_width, -sep_distance], [-hd_center, aux_column_width, -hd_center], [-aux_z_min, aux_z_min, -hd_center], [-v_one_half, -x_min_r, -x_min_r], @@ -1170,17 +1323,17 @@ def create_tile( _np.array( [ [z_min_r, -z_min_r, -v_one_half], - [separator_distance, -aux_column_width, -v_one_half], + [sep_distance, -aux_column_width, -v_one_half], [v_one_half, -aux_column_width, -v_one_half], [z_min_r, z_min_r, -v_one_half], - [separator_distance, aux_column_width, -v_one_half], + [sep_distance, aux_column_width, -v_one_half], [v_one_half, aux_column_width, -v_one_half], [aux_z_min, -aux_z_min, -hd_center], [hd_center, -aux_column_width, -hd_center], - [v_one_half, -aux_column_width, -separator_distance], + [v_one_half, -aux_column_width, -sep_distance], [aux_z_min, aux_z_min, -hd_center], [hd_center, aux_column_width, -hd_center], - [v_one_half, aux_column_width, -separator_distance], + [v_one_half, aux_column_width, -sep_distance], [center_r, -center_r, -center_r], [hd_center, -aux_x_max, -aux_x_max], [v_one_half, -x_max_r, -x_max_r], @@ -1201,17 +1354,17 @@ def create_tile( [-v_one_half, x_min_r, x_min_r], [-hd_center, aux_x_min, aux_x_min], [-center_r, center_r, center_r], - [-v_one_half, -aux_column_width, separator_distance], + [-v_one_half, -aux_column_width, sep_distance], [-hd_center, -aux_column_width, hd_center], [-aux_z_max, -aux_z_max, hd_center], - [-v_one_half, aux_column_width, separator_distance], + [-v_one_half, aux_column_width, sep_distance], [-hd_center, aux_column_width, hd_center], [-aux_z_max, aux_z_max, hd_center], [-v_one_half, -aux_column_width, v_one_half], - [-separator_distance, -aux_column_width, v_one_half], + [-sep_distance, -aux_column_width, v_one_half], [-z_max_r, -z_max_r, v_one_half], [-v_one_half, aux_column_width, v_one_half], - [-separator_distance, aux_column_width, v_one_half], + [-sep_distance, aux_column_width, v_one_half], [-z_max_r, z_max_r, v_one_half], ] ) @@ -1229,15 +1382,15 @@ def create_tile( [v_one_half, x_max_r, x_max_r], [aux_z_max, -aux_z_max, hd_center], [hd_center, -aux_column_width, hd_center], - [v_one_half, -aux_column_width, separator_distance], + [v_one_half, -aux_column_width, sep_distance], [aux_z_max, aux_z_max, hd_center], [hd_center, aux_column_width, hd_center], - [v_one_half, aux_column_width, separator_distance], + [v_one_half, aux_column_width, sep_distance], [z_max_r, -z_max_r, v_one_half], - [separator_distance, -aux_column_width, v_one_half], + [sep_distance, -aux_column_width, v_one_half], [v_one_half, -aux_column_width, v_one_half], [z_max_r, z_max_r, v_one_half], - [separator_distance, aux_column_width, v_one_half], + [sep_distance, aux_column_width, v_one_half], [v_one_half, aux_column_width, v_one_half], ] ) @@ -1249,12 +1402,12 @@ def create_tile( [ [-aux_column_width, -v_one_half, -v_one_half], [aux_column_width, -v_one_half, -v_one_half], - [-aux_column_width, -separator_distance, -v_one_half], - [aux_column_width, -separator_distance, -v_one_half], + [-aux_column_width, -sep_distance, -v_one_half], + [aux_column_width, -sep_distance, -v_one_half], [-z_min_r, -z_min_r, -v_one_half], [z_min_r, -z_min_r, -v_one_half], - [-aux_column_width, -v_one_half, -separator_distance], - [aux_column_width, -v_one_half, -separator_distance], + [-aux_column_width, -v_one_half, -sep_distance], + [aux_column_width, -v_one_half, -sep_distance], [-aux_column_width, -hd_center, -hd_center], [aux_column_width, -hd_center, -hd_center], [-aux_z_min, -aux_z_min, -hd_center], @@ -1275,16 +1428,16 @@ def create_tile( [ [-z_min_r, z_min_r, -v_one_half], [z_min_r, z_min_r, -v_one_half], - [-aux_column_width, separator_distance, -v_one_half], - [aux_column_width, separator_distance, -v_one_half], + [-aux_column_width, sep_distance, -v_one_half], + [aux_column_width, sep_distance, -v_one_half], [-aux_column_width, v_one_half, -v_one_half], [aux_column_width, v_one_half, -v_one_half], [-aux_z_min, aux_z_min, -hd_center], [aux_z_min, aux_z_min, -hd_center], [-aux_column_width, hd_center, -hd_center], [aux_column_width, hd_center, -hd_center], - [-aux_column_width, v_one_half, -separator_distance], - [aux_column_width, v_one_half, -separator_distance], + [-aux_column_width, v_one_half, -sep_distance], + [aux_column_width, v_one_half, -sep_distance], [-center_r, center_r, -center_r], [center_r, center_r, -center_r], [-aux_y_max, hd_center, -aux_y_max], @@ -1305,16 +1458,16 @@ def create_tile( [aux_y_min, -hd_center, aux_y_min], [-center_r, -center_r, center_r], [center_r, -center_r, center_r], - [-aux_column_width, -v_one_half, separator_distance], - [aux_column_width, -v_one_half, separator_distance], + [-aux_column_width, -v_one_half, sep_distance], + [aux_column_width, -v_one_half, sep_distance], [-aux_column_width, -hd_center, hd_center], [aux_column_width, -hd_center, hd_center], [-aux_z_max, -aux_z_max, hd_center], [aux_z_max, -aux_z_max, hd_center], [-aux_column_width, -v_one_half, v_one_half], [aux_column_width, -v_one_half, v_one_half], - [-aux_column_width, -separator_distance, v_one_half], - [aux_column_width, -separator_distance, v_one_half], + [-aux_column_width, -sep_distance, v_one_half], + [aux_column_width, -sep_distance, v_one_half], [-z_max_r, -z_max_r, v_one_half], [z_max_r, -z_max_r, v_one_half], ] @@ -1335,12 +1488,12 @@ def create_tile( [aux_z_max, aux_z_max, hd_center], [-aux_column_width, hd_center, hd_center], [aux_column_width, hd_center, hd_center], - [-aux_column_width, v_one_half, separator_distance], - [aux_column_width, v_one_half, separator_distance], + [-aux_column_width, v_one_half, sep_distance], + [aux_column_width, v_one_half, sep_distance], [-z_max_r, z_max_r, v_one_half], [z_max_r, z_max_r, v_one_half], - [-aux_column_width, separator_distance, v_one_half], - [aux_column_width, separator_distance, v_one_half], + [-aux_column_width, sep_distance, v_one_half], + [aux_column_width, sep_distance, v_one_half], [-aux_column_width, v_one_half, v_one_half], [aux_column_width, v_one_half, v_one_half], ] @@ -1352,39 +1505,39 @@ def create_tile( _np.array( [ [-v_one_half, -v_one_half, -v_one_half], - [-separator_distance, -v_one_half, -v_one_half], + [-sep_distance, -v_one_half, -v_one_half], [-aux_column_width, -v_one_half, -v_one_half], - [-v_one_half, -separator_distance, -v_one_half], + [-v_one_half, -sep_distance, -v_one_half], [ - -separator_distance, - -separator_distance, + -sep_distance, + -sep_distance, -v_one_half, ], - [-aux_column_width, -separator_distance, -v_one_half], + [-aux_column_width, -sep_distance, -v_one_half], [-v_one_half, -aux_column_width, -v_one_half], - [-separator_distance, -aux_column_width, -v_one_half], + [-sep_distance, -aux_column_width, -v_one_half], [-z_min_r, -z_min_r, -v_one_half], - [-v_one_half, -v_one_half, -separator_distance], + [-v_one_half, -v_one_half, -sep_distance], [ - -separator_distance, + -sep_distance, -v_one_half, - -separator_distance, + -sep_distance, ], - [-aux_column_width, -v_one_half, -separator_distance], + [-aux_column_width, -v_one_half, -sep_distance], [ -v_one_half, - -separator_distance, - -separator_distance, + -sep_distance, + -sep_distance, ], [-hd_center, -hd_center, -hd_center], [-aux_column_width, -hd_center, -hd_center], - [-v_one_half, -aux_column_width, -separator_distance], + [-v_one_half, -aux_column_width, -sep_distance], [-hd_center, -aux_column_width, -hd_center], [-aux_z_min, -aux_z_min, -hd_center], [-v_one_half, -v_one_half, -aux_column_width], - [-separator_distance, -v_one_half, -aux_column_width], + [-sep_distance, -v_one_half, -aux_column_width], [-y_min_r, -v_one_half, -y_min_r], - [-v_one_half, -separator_distance, -aux_column_width], + [-v_one_half, -sep_distance, -aux_column_width], [-hd_center, -hd_center, -aux_column_width], [-aux_y_min, -hd_center, -aux_y_min], [-v_one_half, -x_min_r, -x_min_r], @@ -1399,29 +1552,29 @@ def create_tile( _np.array( [ [aux_column_width, -v_one_half, -v_one_half], - [separator_distance, -v_one_half, -v_one_half], + [sep_distance, -v_one_half, -v_one_half], [v_one_half, -v_one_half, -v_one_half], - [aux_column_width, -separator_distance, -v_one_half], - [separator_distance, -separator_distance, -v_one_half], - [v_one_half, -separator_distance, -v_one_half], + [aux_column_width, -sep_distance, -v_one_half], + [sep_distance, -sep_distance, -v_one_half], + [v_one_half, -sep_distance, -v_one_half], [z_min_r, -z_min_r, -v_one_half], - [separator_distance, -aux_column_width, -v_one_half], + [sep_distance, -aux_column_width, -v_one_half], [v_one_half, -aux_column_width, -v_one_half], - [aux_column_width, -v_one_half, -separator_distance], - [separator_distance, -v_one_half, -separator_distance], - [v_one_half, -v_one_half, -separator_distance], + [aux_column_width, -v_one_half, -sep_distance], + [sep_distance, -v_one_half, -sep_distance], + [v_one_half, -v_one_half, -sep_distance], [aux_column_width, -hd_center, -hd_center], [hd_center, -hd_center, -hd_center], - [v_one_half, -separator_distance, -separator_distance], + [v_one_half, -sep_distance, -sep_distance], [aux_z_min, -aux_z_min, -hd_center], [hd_center, -aux_column_width, -hd_center], - [v_one_half, -aux_column_width, -separator_distance], + [v_one_half, -aux_column_width, -sep_distance], [y_min_r, -v_one_half, -y_min_r], - [separator_distance, -v_one_half, -aux_column_width], + [sep_distance, -v_one_half, -aux_column_width], [v_one_half, -v_one_half, -aux_column_width], [aux_y_min, -hd_center, -aux_y_min], [hd_center, -hd_center, -aux_column_width], - [v_one_half, -separator_distance, -aux_column_width], + [v_one_half, -sep_distance, -aux_column_width], [center_r, -center_r, -center_r], [hd_center, -aux_x_max, -aux_x_max], [v_one_half, -x_max_r, -x_max_r], @@ -1434,31 +1587,31 @@ def create_tile( _np.array( [ [-v_one_half, aux_column_width, -v_one_half], - [-separator_distance, aux_column_width, -v_one_half], + [-sep_distance, aux_column_width, -v_one_half], [-z_min_r, z_min_r, -v_one_half], - [-v_one_half, separator_distance, -v_one_half], - [-separator_distance, separator_distance, -v_one_half], - [-aux_column_width, separator_distance, -v_one_half], + [-v_one_half, sep_distance, -v_one_half], + [-sep_distance, sep_distance, -v_one_half], + [-aux_column_width, sep_distance, -v_one_half], [-v_one_half, v_one_half, -v_one_half], - [-separator_distance, v_one_half, -v_one_half], + [-sep_distance, v_one_half, -v_one_half], [-aux_column_width, v_one_half, -v_one_half], - [-v_one_half, aux_column_width, -separator_distance], + [-v_one_half, aux_column_width, -sep_distance], [-hd_center, aux_column_width, -hd_center], [-aux_z_min, aux_z_min, -hd_center], - [-v_one_half, separator_distance, -separator_distance], + [-v_one_half, sep_distance, -sep_distance], [-hd_center, hd_center, -hd_center], [-aux_column_width, hd_center, -hd_center], - [-v_one_half, v_one_half, -separator_distance], - [-separator_distance, v_one_half, -separator_distance], - [-aux_column_width, v_one_half, -separator_distance], + [-v_one_half, v_one_half, -sep_distance], + [-sep_distance, v_one_half, -sep_distance], + [-aux_column_width, v_one_half, -sep_distance], [-v_one_half, x_min_r, -x_min_r], [-hd_center, aux_x_min, -aux_x_min], [-center_r, center_r, -center_r], - [-v_one_half, separator_distance, -aux_column_width], + [-v_one_half, sep_distance, -aux_column_width], [-hd_center, hd_center, -aux_column_width], [-aux_y_max, hd_center, -aux_y_max], [-v_one_half, v_one_half, -aux_column_width], - [-separator_distance, v_one_half, -aux_column_width], + [-sep_distance, v_one_half, -aux_column_width], [-y_max_r, v_one_half, -y_max_r], ] ) @@ -1469,31 +1622,31 @@ def create_tile( _np.array( [ [z_min_r, z_min_r, -v_one_half], - [separator_distance, aux_column_width, -v_one_half], + [sep_distance, aux_column_width, -v_one_half], [v_one_half, aux_column_width, -v_one_half], - [aux_column_width, separator_distance, -v_one_half], - [separator_distance, separator_distance, -v_one_half], - [v_one_half, separator_distance, -v_one_half], + [aux_column_width, sep_distance, -v_one_half], + [sep_distance, sep_distance, -v_one_half], + [v_one_half, sep_distance, -v_one_half], [aux_column_width, v_one_half, -v_one_half], - [separator_distance, v_one_half, -v_one_half], + [sep_distance, v_one_half, -v_one_half], [v_one_half, v_one_half, -v_one_half], [aux_z_min, aux_z_min, -hd_center], [hd_center, aux_column_width, -hd_center], - [v_one_half, aux_column_width, -separator_distance], + [v_one_half, aux_column_width, -sep_distance], [aux_column_width, hd_center, -hd_center], [hd_center, hd_center, -hd_center], - [v_one_half, separator_distance, -separator_distance], - [aux_column_width, v_one_half, -separator_distance], - [separator_distance, v_one_half, -separator_distance], - [v_one_half, v_one_half, -separator_distance], + [v_one_half, sep_distance, -sep_distance], + [aux_column_width, v_one_half, -sep_distance], + [sep_distance, v_one_half, -sep_distance], + [v_one_half, v_one_half, -sep_distance], [center_r, center_r, -center_r], [hd_center, aux_x_max, -aux_x_max], [v_one_half, x_max_r, -x_max_r], [aux_y_max, hd_center, -aux_y_max], [hd_center, hd_center, -aux_column_width], - [v_one_half, separator_distance, -aux_column_width], + [v_one_half, sep_distance, -aux_column_width], [y_max_r, v_one_half, -y_max_r], - [separator_distance, v_one_half, -aux_column_width], + [sep_distance, v_one_half, -aux_column_width], [v_one_half, v_one_half, -aux_column_width], ] ) @@ -1504,31 +1657,31 @@ def create_tile( _np.array( [ [-v_one_half, -v_one_half, aux_column_width], - [-separator_distance, -v_one_half, aux_column_width], + [-sep_distance, -v_one_half, aux_column_width], [-y_min_r, -v_one_half, y_min_r], - [-v_one_half, -separator_distance, aux_column_width], + [-v_one_half, -sep_distance, aux_column_width], [-hd_center, -hd_center, aux_column_width], [-aux_y_min, -hd_center, aux_y_min], [-v_one_half, -x_min_r, x_min_r], [-hd_center, -aux_x_min, aux_x_min], [-center_r, -center_r, center_r], - [-v_one_half, -v_one_half, separator_distance], - [-separator_distance, -v_one_half, separator_distance], - [-aux_column_width, -v_one_half, separator_distance], - [-v_one_half, -separator_distance, separator_distance], + [-v_one_half, -v_one_half, sep_distance], + [-sep_distance, -v_one_half, sep_distance], + [-aux_column_width, -v_one_half, sep_distance], + [-v_one_half, -sep_distance, sep_distance], [-hd_center, -hd_center, hd_center], [-aux_column_width, -hd_center, hd_center], - [-v_one_half, -aux_column_width, separator_distance], + [-v_one_half, -aux_column_width, sep_distance], [-hd_center, -aux_column_width, hd_center], [-aux_z_max, -aux_z_max, hd_center], [-v_one_half, -v_one_half, v_one_half], - [-separator_distance, -v_one_half, v_one_half], + [-sep_distance, -v_one_half, v_one_half], [-aux_column_width, -v_one_half, v_one_half], - [-v_one_half, -separator_distance, v_one_half], - [-separator_distance, -separator_distance, v_one_half], - [-aux_column_width, -separator_distance, v_one_half], + [-v_one_half, -sep_distance, v_one_half], + [-sep_distance, -sep_distance, v_one_half], + [-aux_column_width, -sep_distance, v_one_half], [-v_one_half, -aux_column_width, v_one_half], - [-separator_distance, -aux_column_width, v_one_half], + [-sep_distance, -aux_column_width, v_one_half], [-z_max_r, -z_max_r, v_one_half], ] ) @@ -1539,31 +1692,31 @@ def create_tile( _np.array( [ [y_min_r, -v_one_half, y_min_r], - [separator_distance, -v_one_half, aux_column_width], + [sep_distance, -v_one_half, aux_column_width], [v_one_half, -v_one_half, aux_column_width], [aux_y_min, -hd_center, aux_y_min], [hd_center, -hd_center, aux_column_width], - [v_one_half, -separator_distance, aux_column_width], + [v_one_half, -sep_distance, aux_column_width], [center_r, -center_r, center_r], [hd_center, -aux_x_max, aux_x_max], [v_one_half, -x_max_r, x_max_r], - [aux_column_width, -v_one_half, separator_distance], - [separator_distance, -v_one_half, separator_distance], - [v_one_half, -v_one_half, separator_distance], + [aux_column_width, -v_one_half, sep_distance], + [sep_distance, -v_one_half, sep_distance], + [v_one_half, -v_one_half, sep_distance], [aux_column_width, -hd_center, hd_center], [hd_center, -hd_center, hd_center], - [v_one_half, -separator_distance, separator_distance], + [v_one_half, -sep_distance, sep_distance], [aux_z_max, -aux_z_max, hd_center], [hd_center, -aux_column_width, hd_center], - [v_one_half, -aux_column_width, separator_distance], + [v_one_half, -aux_column_width, sep_distance], [aux_column_width, -v_one_half, v_one_half], - [separator_distance, -v_one_half, v_one_half], + [sep_distance, -v_one_half, v_one_half], [v_one_half, -v_one_half, v_one_half], - [aux_column_width, -separator_distance, v_one_half], - [separator_distance, -separator_distance, v_one_half], - [v_one_half, -separator_distance, v_one_half], + [aux_column_width, -sep_distance, v_one_half], + [sep_distance, -sep_distance, v_one_half], + [v_one_half, -sep_distance, v_one_half], [z_max_r, -z_max_r, v_one_half], - [separator_distance, -aux_column_width, v_one_half], + [sep_distance, -aux_column_width, v_one_half], [v_one_half, -aux_column_width, v_one_half], ] ) @@ -1576,29 +1729,29 @@ def create_tile( [-v_one_half, x_min_r, x_min_r], [-hd_center, aux_x_min, aux_x_min], [-center_r, center_r, center_r], - [-v_one_half, separator_distance, aux_column_width], + [-v_one_half, sep_distance, aux_column_width], [-hd_center, hd_center, aux_column_width], [-aux_y_max, hd_center, aux_y_max], [-v_one_half, v_one_half, aux_column_width], - [-separator_distance, v_one_half, aux_column_width], + [-sep_distance, v_one_half, aux_column_width], [-y_max_r, v_one_half, y_max_r], - [-v_one_half, aux_column_width, separator_distance], + [-v_one_half, aux_column_width, sep_distance], [-hd_center, aux_column_width, hd_center], [-aux_z_max, aux_z_max, hd_center], - [-v_one_half, separator_distance, separator_distance], + [-v_one_half, sep_distance, sep_distance], [-hd_center, hd_center, hd_center], [-aux_column_width, hd_center, hd_center], - [-v_one_half, v_one_half, separator_distance], - [-separator_distance, v_one_half, separator_distance], - [-aux_column_width, v_one_half, separator_distance], + [-v_one_half, v_one_half, sep_distance], + [-sep_distance, v_one_half, sep_distance], + [-aux_column_width, v_one_half, sep_distance], [-v_one_half, aux_column_width, v_one_half], - [-separator_distance, aux_column_width, v_one_half], + [-sep_distance, aux_column_width, v_one_half], [-z_max_r, z_max_r, v_one_half], - [-v_one_half, separator_distance, v_one_half], - [-separator_distance, separator_distance, v_one_half], - [-aux_column_width, separator_distance, v_one_half], + [-v_one_half, sep_distance, v_one_half], + [-sep_distance, sep_distance, v_one_half], + [-aux_column_width, sep_distance, v_one_half], [-v_one_half, v_one_half, v_one_half], - [-separator_distance, v_one_half, v_one_half], + [-sep_distance, v_one_half, v_one_half], [-aux_column_width, v_one_half, v_one_half], ] ) @@ -1613,27 +1766,27 @@ def create_tile( [v_one_half, x_max_r, x_max_r], [aux_y_max, hd_center, aux_y_max], [hd_center, hd_center, aux_column_width], - [v_one_half, separator_distance, aux_column_width], + [v_one_half, sep_distance, aux_column_width], [y_max_r, v_one_half, y_max_r], - [separator_distance, v_one_half, aux_column_width], + [sep_distance, v_one_half, aux_column_width], [v_one_half, v_one_half, aux_column_width], [aux_z_max, aux_z_max, hd_center], [hd_center, aux_column_width, hd_center], - [v_one_half, aux_column_width, separator_distance], + [v_one_half, aux_column_width, sep_distance], [aux_column_width, hd_center, hd_center], [hd_center, hd_center, hd_center], - [v_one_half, separator_distance, separator_distance], - [aux_column_width, v_one_half, separator_distance], - [separator_distance, v_one_half, separator_distance], - [v_one_half, v_one_half, separator_distance], + [v_one_half, sep_distance, sep_distance], + [aux_column_width, v_one_half, sep_distance], + [sep_distance, v_one_half, sep_distance], + [v_one_half, v_one_half, sep_distance], [z_max_r, z_max_r, v_one_half], - [separator_distance, aux_column_width, v_one_half], + [sep_distance, aux_column_width, v_one_half], [v_one_half, aux_column_width, v_one_half], - [aux_column_width, separator_distance, v_one_half], - [separator_distance, separator_distance, v_one_half], - [v_one_half, separator_distance, v_one_half], + [aux_column_width, sep_distance, v_one_half], + [sep_distance, sep_distance, v_one_half], + [v_one_half, sep_distance, v_one_half], [aux_column_width, v_one_half, v_one_half], - [separator_distance, v_one_half, v_one_half], + [sep_distance, v_one_half, v_one_half], [v_one_half, v_one_half, v_one_half], ] ) @@ -1671,5 +1824,4 @@ def create_tile( splines = spline_list.copy() else: derivatives.append(spline_list) - - return splines, derivatives + return (splines, derivatives) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index edaf0b477..339efd219 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -189,11 +189,7 @@ def test_tile_derivatives(np_rng, heps=1e-8, n_test_points=4): Number of testing points in the parametric domain """ # TODO: right now EllipsVoid, CubeVoid and InverseCross show wrong derivatives - skip_classes = [ - ms.tiles.EllipsVoid, - ms.tiles.CubeVoid, - ms.tiles.InverseCross3D, - ] + skip_classes = [ms.tiles.EllipsVoid, ms.tiles.CubeVoid] for tile_class in all_tile_classes: # TODO: right now skip classes with faultily implemented derivatives @@ -273,7 +269,7 @@ def test_tile_derivatives(np_rng, heps=1e-8, n_test_points=4): ): assert np.allclose(deriv_orig, deriv_fd), ( "Implemented derivative calculation for tile class" - + f"{tile_class}, parameter " + + f"{tile_class}, with closure {closure}, parameter " + f"{i_parameter+1}/{n_info_per_eval_point} at patch " + f"{i_patch+1}/{n_patches} does not match the derivative " + "obtained using Finite Differences" From 61b384652d5f17cb6095824b7319c88431f8c86d Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 9 Oct 2024 16:53:32 +0200 Subject: [PATCH 18/52] Fix CubeVoid derivatives --- splinepy/microstructure/tiles/cube_void.py | 2 +- tests/test_microstructure.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/splinepy/microstructure/tiles/cube_void.py b/splinepy/microstructure/tiles/cube_void.py index c435b6a88..9eeb3a33b 100644 --- a/splinepy/microstructure/tiles/cube_void.py +++ b/splinepy/microstructure/tiles/cube_void.py @@ -64,7 +64,7 @@ def _rotation_matrix_y(self, angle): def _rotation_matrix_y_deriv(self, angle): cc, ss = _np.cos(angle), _np.sin(angle) - return _np.array([[-ss, 0, -cc], [0, 1, 0], [cc, 0, -ss]]) + return _np.array([[-ss, 0, -cc], [0, 0, 0], [cc, 0, -ss]]) def create_tile( self, diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 339efd219..009cbabf4 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -176,7 +176,7 @@ def test_tile_closure(): check_control_points(tile_patches) -def test_tile_derivatives(np_rng, heps=1e-8, n_test_points=4): +def test_tile_derivatives(np_rng, heps=1e-7, n_test_points=10): """Testing the correctness of the tile derivatives using Finite Differences. This includes every closure and no closure, every parameter and every patch by evaluating at random points and for random parameters. @@ -188,8 +188,8 @@ def test_tile_derivatives(np_rng, heps=1e-8, n_test_points=4): n_test_points: int Number of testing points in the parametric domain """ - # TODO: right now EllipsVoid, CubeVoid and InverseCross show wrong derivatives - skip_classes = [ms.tiles.EllipsVoid, ms.tiles.CubeVoid] + # TODO: right now EllipsVoid shows wrong derivatives + skip_classes = [ms.tiles.EllipsVoid] for tile_class in all_tile_classes: # TODO: right now skip classes with faultily implemented derivatives From e41898968cdb390c4bef47b19b3b1aa6ba171921 Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 9 Oct 2024 17:22:06 +0200 Subject: [PATCH 19/52] Fix Ellipsvoid derivatives --- splinepy/microstructure/tiles/ellips_v_oid.py | 2 +- tests/test_microstructure.py | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/splinepy/microstructure/tiles/ellips_v_oid.py b/splinepy/microstructure/tiles/ellips_v_oid.py index 84025d8bf..67f31b6fd 100644 --- a/splinepy/microstructure/tiles/ellips_v_oid.py +++ b/splinepy/microstructure/tiles/ellips_v_oid.py @@ -91,7 +91,7 @@ def _rotation_matrix_y(self, angle): def _rotation_matrix_y_deriv(self, angle): cc, ss = _np.cos(angle), _np.sin(angle) - return _np.array([[-ss, 0, -cc], [0, 1, 0], [cc, 0, -ss]]) + return _np.array([[-ss, 0, -cc], [0, 0, 0], [cc, 0, -ss]]) def create_tile( self, diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 009cbabf4..260ee2fa2 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -188,14 +188,8 @@ def test_tile_derivatives(np_rng, heps=1e-7, n_test_points=10): n_test_points: int Number of testing points in the parametric domain """ - # TODO: right now EllipsVoid shows wrong derivatives - skip_classes = [ms.tiles.EllipsVoid] for tile_class in all_tile_classes: - # TODO: right now skip classes with faultily implemented derivatives - if tile_class in skip_classes: - continue - tile_creator = tile_class() # Skip test if tile class has no implemented sensitivities if not tile_creator._sensitivities_implemented: From 9baa5f12474003e9fb230372a808f51cec36ad80 Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 10 Oct 2024 09:23:36 +0200 Subject: [PATCH 20/52] Change to more appropriate name test_microtiles --- tests/{test_microstructure.py => test_microtiles.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test_microstructure.py => test_microtiles.py} (100%) diff --git a/tests/test_microstructure.py b/tests/test_microtiles.py similarity index 100% rename from tests/test_microstructure.py rename to tests/test_microtiles.py From cf13b7eb6c182adb213ce7ca7916df7e56f68ced Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 10 Oct 2024 11:40:47 +0200 Subject: [PATCH 21/52] Add microstructure closure test --- tests/test_microstructure.py | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 tests/test_microstructure.py diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py new file mode 100644 index 000000000..65cbc9c9f --- /dev/null +++ b/tests/test_microstructure.py @@ -0,0 +1,81 @@ +import splinepy.microstructure as ms +from splinepy.helpme.create import box +from splinepy.helpme.integrate import volume + +all_tile_classes = list(ms.tiles.everything().values()) + +TILING = [2, 2, 2] +BOX_DIMENSIONS = [1, 1, 1] +EPS = 1e-7 + +# TODO: the following tiles fail the closure test +CLOSURE_FAILS = [ms.tiles.HollowOctagonExtrude, ms.tiles.InverseCross3D] + + +def test_closing_face(): + def check_if_closed(multipatch, closure_direction): + """Helper function to see if multipatch has a closing surface + + Parameters + ---------- + multipatch: splinepy Multipatch + Microstructure multipatch + closure_direction: str + Direction in which the closure has been applied + """ + direction_index_dict = {"x": 0, "y": 1, "z": 2} + direction_index = direction_index_dict[closure_direction] + + def min_identifier(points): + return points[:, direction_index] < EPS + + def max_identifier(points): + return ( + points[:, direction_index] + > BOX_DIMENSIONS[direction_index] - EPS + ) + + multipatch.boundary_from_function(min_identifier, boundary_id=2) + multipatch.boundary_from_function(max_identifier, boundary_id=3) + + min_patches = multipatch.boundary_multipatch(2) + max_patches = multipatch.boundary_multipatch(3) + + # Check if the closing surface has a surface area of 1 + face_min_area = sum([volume(patch) for patch in min_patches.patches]) + face_max_area = sum([volume(patch) for patch in max_patches.patches]) + + assert ( + face_min_area > 1.0 - EPS + ), f"The closure of the {closure_direction}_min surface is not complete" + assert ( + face_max_area > 1.0 - EPS + ), f"The closure of the {closure_direction}_max surface is not complete" + + for tile_class in all_tile_classes: + # Skip tile if it doesn't support closure + if "_closure_directions" not in dir(tile_class): + continue + + # TODO: right now skip tiles which have faulty closures + if tile_class in CLOSURE_FAILS: + continue + + tile_creator = tile_class() + generator = ms.microstructure.Microstructure( + deformation_function=box(*BOX_DIMENSIONS[: tile_creator._dim]), + microtile=tile_creator, + tiling=TILING[: tile_creator._para_dim], + ) + # Go through all implemented closure direction + closure_directions = { + directionname[0] + for directionname in tile_creator._closure_directions + } + for closure_direction in closure_directions: + multipatch = generator.create(closing_face=closure_direction) + check_if_closed(multipatch, closure_direction) + + +def test_macro_sensitivities(): + pass From 2a316ed6781b77279be472134a3a09f7a22405d0 Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 11 Oct 2024 15:46:35 +0200 Subject: [PATCH 22/52] Add test for microstructure macro sensitivities --- splinepy/microstructure/microstructure.py | 17 ++--- tests/test_microstructure.py | 76 ++++++++++++++++++++++- tests/test_microtiles.py | 6 +- 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/splinepy/microstructure/microstructure.py b/splinepy/microstructure/microstructure.py index bb34246c6..298df64be 100644 --- a/splinepy/microstructure/microstructure.py +++ b/splinepy/microstructure/microstructure.py @@ -427,8 +427,8 @@ def _compute_tiling_prerequisites( def create( self, closing_face=None, - knot_span_wise=None, - macro_sensitivities=None, + knot_span_wise=True, + macro_sensitivities=False, **kwargs, ): """Create a Microstructure. @@ -455,11 +455,12 @@ def create( if not self._sanity_check(): raise ValueError("Not enough information provided, abort") - # Set default values - if knot_span_wise is None: - knot_span_wise = True - if macro_sensitivities is None: - macro_sensitivities = False + assert isinstance( + knot_span_wise, bool + ), "knot_span_wise must be a bool" + assert isinstance( + macro_sensitivities, bool + ), "macro_senstivities must be a bool" # check if user wants closed structure if closing_face is not None: @@ -533,7 +534,7 @@ def create( if macro_sensitivities or parameter_sensitivities: spline_list_derivs = [ [] - for i in range( + for _ in range( n_parameter_sensitivities + n_macro_sensitivities ) ] diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 65cbc9c9f..b0b9ed916 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -1,3 +1,5 @@ +import numpy as np + import splinepy.microstructure as ms from splinepy.helpme.create import box from splinepy.helpme.integrate import volume @@ -13,6 +15,8 @@ def test_closing_face(): + """Check if closing face is working""" + def check_if_closed(multipatch, closure_direction): """Helper function to see if multipatch has a closing surface @@ -65,7 +69,7 @@ def max_identifier(points): generator = ms.microstructure.Microstructure( deformation_function=box(*BOX_DIMENSIONS[: tile_creator._dim]), microtile=tile_creator, - tiling=TILING[: tile_creator._para_dim], + tiling=TILING[: tile_creator._dim], ) # Go through all implemented closure direction closure_directions = { @@ -77,5 +81,71 @@ def max_identifier(points): check_if_closed(multipatch, closure_direction) -def test_macro_sensitivities(): - pass +def test_macro_sensitivities(np_rng, heps=1e-7, n_test_points=10): + """Testing the correctness of the derivatives of the whole microstructure w.r.t. + the deformation function's control points. It is tested by evaluating the derivative + obtained via finite differences. The values are evaluated at random points. + + Parameters + ---------- + heps: float + Perturbation size for finite difference evaluation + n_test_points: int + Number of testing points int the parametric domain""" + + for tile_class in all_tile_classes: + tile_creator = tile_class() + deformation_function_orig = box(*BOX_DIMENSIONS[: tile_creator._dim]) + generator = ms.microstructure.Microstructure( + deformation_function=deformation_function_orig, + microtile=tile_creator, + tiling=TILING[: tile_creator._dim], + ) + multipatch = generator.create(macro_sensitivities=True) + dim = multipatch.dim + n_cps = deformation_function_orig.cps.shape[0] + + # Set evaluation points as random spots in the parametric space + eval_points = np_rng.random((n_test_points, tile_creator._para_dim)) + microstructure_orig_evaluations = [ + patch.evaluate(eval_points) for patch in multipatch.patches + ] + n_patches = len(multipatch.patches) + + # Go through derivatives of every deformation function's control point + for ii_ctps in range(n_cps): + # Gradient through finite differences + deformation_function_perturbed = deformation_function_orig.copy() + deformation_function_perturbed.cps[ii_ctps, :] += heps + generator.deformation_function = deformation_function_perturbed + multipatch_perturbed = generator.create() + microstructure_perturbed_evaluations = [ + patch.evaluate(eval_points) + for patch in multipatch_perturbed.patches + ] + # Evaluate finite difference gradient + fd_sensitivity = [ + (patch_perturbed - patch_orig) / heps + for patch_perturbed, patch_orig in zip( + microstructure_orig_evaluations, + microstructure_perturbed_evaluations, + ) + ] + + # Go through each direction + for jj_dim in range(dim): + deriv_orig = multipatch.fields[ii_ctps * dim + jj_dim] + deriv_evaluations = [ + patch.evaluate(eval_points) for patch in deriv_orig.patches + ] + for k_patch, patch_deriv_implemented, patch_deriv_fd in zip( + range(n_patches), deriv_evaluations, fd_sensitivity + ): + assert np.allclose( + -patch_deriv_implemented[:, jj_dim], + patch_deriv_fd[:, jj_dim], + ), ( + "Implemented derivative calculation for tile class" + + f"{tile_class}, at patch {k_patch+1}/{n_patches} does not " + + "match the derivative obtained using Finite Differences" + ) diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 260ee2fa2..87e306e39 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -76,7 +76,7 @@ def test_tile_class(): required_param in create_parameters ), f"create_tile() must have '{required_param}' as an input parameter" - # Ensure closure can be correctly handled + # Ensure closure can be handled correctly if "closure" in create_parameters: assert "_closure_directions" in members, ( "Tile class has closure ability. The available closure directions " @@ -130,7 +130,7 @@ def test_tile_bounds(): def test_tile_closure(): - """Check if closing tiles also lie in unit cube. TODO: also check derivatives.""" + """Check if closing tiles also lie in unit cube.""" for tile_class in all_tile_classes: # Skip tile if if does not support closure @@ -218,7 +218,7 @@ def test_tile_derivatives(np_rng, heps=1e-7, n_test_points=10): splines_orig, _ = tile_creator.create_tile( parameters=parameters, closure=closure ) - # Set evaluation points as 4 random spots in the parametric space + # Set evaluation points as random spots in the parametric space eval_points = np_rng.random( (n_test_points, splines_orig[0].para_dim) ) From 8501ad87ac77bb18ee2e22d4e8e8f6839b125e3c Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 11 Oct 2024 17:33:02 +0200 Subject: [PATCH 23/52] Add working closure to HollowOctagonExtrude --- .../tiles/hollow_octagon_extrude.py | 1254 +++++++++++++---- 1 file changed, 961 insertions(+), 293 deletions(-) diff --git a/splinepy/microstructure/tiles/hollow_octagon_extrude.py b/splinepy/microstructure/tiles/hollow_octagon_extrude.py index 16359ef49..1ad07f70f 100644 --- a/splinepy/microstructure/tiles/hollow_octagon_extrude.py +++ b/splinepy/microstructure/tiles/hollow_octagon_extrude.py @@ -29,6 +29,7 @@ def create_tile( parameters=None, parameter_sensitivities=None, contact_length=0.2, + closure=None, **kwargs, # noqa ARG002 ): """Create a microtile based on the parameters that describe the wall @@ -77,6 +78,15 @@ def create_tile( n_derivatives = 0 derivatives = None + if closure is not None: + return self._closing_tile( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + closure=closure, + contact_length=contact_length, + **kwargs, + ) + self.check_params(parameters) self.check_param_derivatives(parameter_sensitivities) @@ -108,9 +118,9 @@ def create_tile( right = _np.array( [ [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_zero], - [v_one, -v_outer_c_h + v_one_half, 0.0], - [v_h_void + v_one_half, v_inner_c_h + v_one_half, 0.0], - [v_one, v_outer_c_h + v_one_half, 0.0], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_zero], + [v_one, v_outer_c_h + v_one_half, v_zero], [v_h_void + v_one_half, -v_inner_c_h + v_one_half, v_one], [v_one, -v_outer_c_h + v_one_half, v_one], [v_h_void + v_one_half, v_inner_c_h + v_one_half, v_one], @@ -298,334 +308,992 @@ def _closing_tile( self.check_params(parameters) if parameter_sensitivities is not None: - raise NotImplementedError( - "Derivatives are not implemented for this tile yet" - ) + self.check_param_derivatives(parameter_sensitivities) + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None + # Check whether parameter is within bounds v_h_void = parameters[0, 0] - if not ((v_h_void > 0.01) and (v_h_void < 0.5)): + para_bound_lower, para_bound_upper = self._parameter_bounds[0] + if not ( + (v_h_void > para_bound_lower) and (v_h_void < para_bound_upper) + ): raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" + f"The thickness of the wall must be in ({para_bound_lower} and " + + f"{para_bound_upper})" ) - spline_list = [] - v_zero = 0.0 - v_one_half = 0.5 - v_one = 1.0 - v_outer_c_h = contact_length * 0.5 - v_inner_c_h = contact_length * parameters[0, 0] - - if closure == "x_min": - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - ] - ) - - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - ] - ) - - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - ] - ) - - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - ] - ) - - left = _np.array( - [ - [v_zero, v_zero], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_one], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + splines = [] + for i_derivative in range(n_derivatives + 1): + if i_derivative == 0: + v_zero = 0.0 + v_one_half = 0.5 + v_one = 1.0 + v_outer_c_h = contact_length * 0.5 + v_inner_c_h = contact_length * parameters[0, 0] + else: + v_h_void = parameter_sensitivities[0, 0, i_derivative - 1] + v_zero, v_one_half, v_one = [0.0, 0.0, 0.0] + v_outer_c_h = 0.0 + v_inner_c_h = contact_length * v_h_void - top_left = _np.array( - [ - [v_zero, v_one], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + spline_list = [] - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + if closure == "x_min": + # set points: + right = _np.array( + [ + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_outer_c_h + v_one_half, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, -v_outer_c_h + v_one_half, v_one], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_outer_c_h + v_one_half, v_one], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - ] - ) + right_top = _np.array( + [ + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_outer_c_h + v_one_half, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_one, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_outer_c_h + v_one_half, v_one], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - elif closure == "x_max": - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, v_zero], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_one], - ] - ) + top = _np.array( + [ + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_one], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - ] - ) + bottom_left = _np.array( + [ + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_zero, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, v_zero, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_zero, v_one], + ] + ) - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - ] - ) + left = _np.array( + [ + [v_zero, v_zero, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_one, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_zero, v_one], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, v_one, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + ] + ) - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, -v_outer_c_h + v_one_half], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - ] - ) + top_left = _np.array( + [ + [v_zero, v_one, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_zero, v_one, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + ] + ) - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_zero, v_one], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_zero, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + ] + ) - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + bottom_right = _np.array( + [ + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_zero, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_zero, v_one], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, -v_outer_c_h + v_one_half, v_one], + ] + ) - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + elif closure == "x_max": + right = _np.array( + [ + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_zero, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_one, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_zero, v_one], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_one, v_one], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, v_zero], - ] - ) + right_top = _np.array( + [ + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_one, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_one, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_one, v_one], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - elif closure == "y_min": - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - ] - ) + top = _np.array( + [ + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - ] - ) + bottom_left = _np.array( + [ + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_zero, v_one], + ] + ) - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - ] - ) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + ] + ) - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, -v_outer_c_h + v_one_half], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_zero, v_zero], - ] - ) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_zero, v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + ] + ) - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_zero, v_one], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_zero, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + ] + ) - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [-v_outer_c_h + v_one_half, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + bottom_right = _np.array( + [ + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_zero, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_zero, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_zero, v_one], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_zero, v_one], + ] + ) - bottom = _np.array( - [ - [v_one, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_zero, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + elif closure == "y_min": + # set points: + right = _np.array( + [ + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_outer_c_h + v_one_half, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, -v_outer_c_h + v_one_half, v_one], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_outer_c_h + v_one_half, v_one], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_one, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - ] - ) + right_top = _np.array( + [ + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_outer_c_h + v_one_half, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_one, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_outer_c_h + v_one_half, v_one], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - elif closure == "y_max": - # set points: - right = _np.array( - [ - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - ] - ) + top = _np.array( + [ + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_one, v_one], + ] + ) - right_top = _np.array( - [ - [v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_one, v_outer_c_h + v_one_half], - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_one, v_one], - ] - ) + bottom_left = _np.array( + [ + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_zero, v_zero, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [v_zero, v_zero, v_one], + ] + ) - top = _np.array( - [ - [v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_one, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - [v_zero, v_one], - ] - ) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + ] + ) - bottom_left = _np.array( - [ - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, -v_outer_c_h + v_one_half], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - ] - ) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_zero, v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + ] + ) - left = _np.array( - [ - [v_zero, -v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - ] - ) + bottom = _np.array( + [ + [v_one, v_zero, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_zero, v_zero, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_one, v_zero, v_one], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [v_zero, v_zero, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + ] + ) - top_left = _np.array( - [ - [v_zero, v_outer_c_h + v_one_half], - [-v_h_void + v_one_half, v_inner_c_h + v_one_half], - [v_zero, v_one], - [-v_inner_c_h + v_one_half, v_h_void + v_one_half], - ] - ) + bottom_right = _np.array( + [ + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_one, v_zero, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [v_one, v_zero, v_one], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, -v_outer_c_h + v_one_half, v_one], + ] + ) - bottom = _np.array( - [ - [v_outer_c_h + v_one_half, v_zero], - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [-v_outer_c_h + v_one_half, v_zero], - [-v_inner_c_h + v_one_half, -v_h_void + v_one_half], - ] - ) + elif closure == "y_max": + # set points: + right = _np.array( + [ + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_outer_c_h + v_one_half, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, -v_outer_c_h + v_one_half, v_one], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_outer_c_h + v_one_half, v_one], + ] + ) - bottom_right = _np.array( - [ - [v_inner_c_h + v_one_half, -v_h_void + v_one_half], - [v_outer_c_h + v_one_half, v_zero], - [v_h_void + v_one_half, -v_inner_c_h + v_one_half], - [v_one, -v_outer_c_h + v_one_half], - ] - ) + right_top = _np.array( + [ + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, v_outer_c_h + v_one_half, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_one, v_one, v_zero], + [ + v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_one, v_outer_c_h + v_one_half, v_one], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_one, v_one, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=right)) + top = _np.array( + [ + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_one, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_zero, v_one, v_zero], + [ + v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_one, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + [v_zero, v_one, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=right_top)) + bottom_left = _np.array( + [ + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_zero, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom)) + left = _np.array( + [ + [v_zero, -v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, -v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=bottom_left)) + top_left = _np.array( + [ + [v_zero, v_outer_c_h + v_one_half, v_zero], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_zero, + ], + [v_zero, v_one, v_zero], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_zero, + ], + [v_zero, v_outer_c_h + v_one_half, v_one], + [ + -v_h_void + v_one_half, + v_inner_c_h + v_one_half, + v_one, + ], + [v_zero, v_one, v_one], + [ + -v_inner_c_h + v_one_half, + v_h_void + v_one_half, + v_one, + ], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=left)) + bottom = _np.array( + [ + [v_outer_c_h + v_one_half, v_zero, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [-v_outer_c_h + v_one_half, v_zero, v_zero], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_zero, v_one], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [-v_outer_c_h + v_one_half, v_zero, v_one], + [ + -v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=top_left)) + bottom_right = _np.array( + [ + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_zero, + ], + [v_outer_c_h + v_one_half, v_zero, v_zero], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_zero, + ], + [v_one, -v_outer_c_h + v_one_half, v_zero], + [ + v_inner_c_h + v_one_half, + -v_h_void + v_one_half, + v_one, + ], + [v_outer_c_h + v_one_half, v_zero, v_one], + [ + v_h_void + v_one_half, + -v_inner_c_h + v_one_half, + v_one, + ], + [v_one, -v_outer_c_h + v_one_half, v_one], + ] + ) - spline_list.append(_Bezier(degrees=[1, 1], control_points=top)) + for control_points in [ + right, + right_top, + bottom, + bottom_left, + left, + top_left, + top, + bottom_right, + ]: + spline_list.append( + _Bezier(degrees=[1, 1, 1], control_points=control_points) + ) - spline_list.append( - _Bezier(degrees=[1, 1], control_points=bottom_right) - ) + if i_derivative == 0: + splines = spline_list.copy() + else: + derivatives.append(spline_list) - return (spline_list, None) + return (splines, derivatives) From ee0860028e679760b567151a68f0d0e10dd3d292 Mon Sep 17 00:00:00 2001 From: markriegler Date: Tue, 14 Jan 2025 10:46:10 +0100 Subject: [PATCH 24/52] Add pytest parametrization of all the microtiles --- tests/test_microstructure.py | 161 ++++++++-------- tests/test_microtiles.py | 357 +++++++++++++++++------------------ 2 files changed, 258 insertions(+), 260 deletions(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index b0b9ed916..10c158bee 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -1,4 +1,5 @@ import numpy as np +from pytest import mark import splinepy.microstructure as ms from splinepy.helpme.create import box @@ -14,7 +15,8 @@ CLOSURE_FAILS = [ms.tiles.HollowOctagonExtrude, ms.tiles.InverseCross3D] -def test_closing_face(): +@mark.parametrize("tile_class", all_tile_classes) +def test_closing_face(tile_class): """Check if closing face is working""" def check_if_closed(multipatch, closure_direction): @@ -39,6 +41,7 @@ def max_identifier(points): > BOX_DIMENSIONS[direction_index] - EPS ) + # create min- and max-boundaries of the multipatch using the identifiers multipatch.boundary_from_function(min_identifier, boundary_id=2) multipatch.boundary_from_function(max_identifier, boundary_id=3) @@ -56,32 +59,31 @@ def max_identifier(points): face_max_area > 1.0 - EPS ), f"The closure of the {closure_direction}_max surface is not complete" - for tile_class in all_tile_classes: - # Skip tile if it doesn't support closure - if "_closure_directions" not in dir(tile_class): - continue - - # TODO: right now skip tiles which have faulty closures - if tile_class in CLOSURE_FAILS: - continue - - tile_creator = tile_class() - generator = ms.microstructure.Microstructure( - deformation_function=box(*BOX_DIMENSIONS[: tile_creator._dim]), - microtile=tile_creator, - tiling=TILING[: tile_creator._dim], - ) - # Go through all implemented closure direction - closure_directions = { - directionname[0] - for directionname in tile_creator._closure_directions - } - for closure_direction in closure_directions: - multipatch = generator.create(closing_face=closure_direction) - check_if_closed(multipatch, closure_direction) - - -def test_macro_sensitivities(np_rng, heps=1e-7, n_test_points=10): + # Skip tile if it doesn't support closure + if "_closure_directions" not in dir(tile_class): + return + + # TODO: right now skip tiles which have faulty closures + if tile_class in CLOSURE_FAILS: + return + + tile_creator = tile_class() + generator = ms.microstructure.Microstructure( + deformation_function=box(*BOX_DIMENSIONS[: tile_creator._dim]), + microtile=tile_creator, + tiling=TILING[: tile_creator._dim], + ) + # Go through all implemented closure direction + closure_directions = { + directionname[0] for directionname in tile_creator._closure_directions + } + for closure_direction in closure_directions: + multipatch = generator.create(closing_face=closure_direction) + check_if_closed(multipatch, closure_direction) + + +@mark.parametrize("tile_class", all_tile_classes) +def test_macro_sensitivities(tile_class, np_rng, heps=1e-7, n_test_points=10): """Testing the correctness of the derivatives of the whole microstructure w.r.t. the deformation function's control points. It is tested by evaluating the derivative obtained via finite differences. The values are evaluated at random points. @@ -93,59 +95,58 @@ def test_macro_sensitivities(np_rng, heps=1e-7, n_test_points=10): n_test_points: int Number of testing points int the parametric domain""" - for tile_class in all_tile_classes: - tile_creator = tile_class() - deformation_function_orig = box(*BOX_DIMENSIONS[: tile_creator._dim]) - generator = ms.microstructure.Microstructure( - deformation_function=deformation_function_orig, - microtile=tile_creator, - tiling=TILING[: tile_creator._dim], - ) - multipatch = generator.create(macro_sensitivities=True) - dim = multipatch.dim - n_cps = deformation_function_orig.cps.shape[0] - - # Set evaluation points as random spots in the parametric space - eval_points = np_rng.random((n_test_points, tile_creator._para_dim)) - microstructure_orig_evaluations = [ - patch.evaluate(eval_points) for patch in multipatch.patches + tile_creator = tile_class() + deformation_function_orig = box(*BOX_DIMENSIONS[: tile_creator._dim]) + generator = ms.microstructure.Microstructure( + deformation_function=deformation_function_orig, + microtile=tile_creator, + tiling=TILING[: tile_creator._dim], + ) + multipatch = generator.create(macro_sensitivities=True) + dim = multipatch.dim + n_cps = deformation_function_orig.cps.shape[0] + + # Set evaluation points as random spots in the parametric space + eval_points = np_rng.random((n_test_points, tile_creator._para_dim)) + microstructure_orig_evaluations = [ + patch.evaluate(eval_points) for patch in multipatch.patches + ] + n_patches = len(multipatch.patches) + + # Go through derivatives of every deformation function's control point + for ii_ctps in range(n_cps): + # Gradient through finite differences + deformation_function_perturbed = deformation_function_orig.copy() + deformation_function_perturbed.cps[ii_ctps, :] += heps + generator.deformation_function = deformation_function_perturbed + multipatch_perturbed = generator.create() + microstructure_perturbed_evaluations = [ + patch.evaluate(eval_points) + for patch in multipatch_perturbed.patches ] - n_patches = len(multipatch.patches) - - # Go through derivatives of every deformation function's control point - for ii_ctps in range(n_cps): - # Gradient through finite differences - deformation_function_perturbed = deformation_function_orig.copy() - deformation_function_perturbed.cps[ii_ctps, :] += heps - generator.deformation_function = deformation_function_perturbed - multipatch_perturbed = generator.create() - microstructure_perturbed_evaluations = [ - patch.evaluate(eval_points) - for patch in multipatch_perturbed.patches + # Evaluate finite difference gradient + fd_sensitivity = [ + (patch_perturbed - patch_orig) / heps + for patch_perturbed, patch_orig in zip( + microstructure_orig_evaluations, + microstructure_perturbed_evaluations, + ) + ] + + # Go through each direction + for jj_dim in range(dim): + deriv_orig = multipatch.fields[ii_ctps * dim + jj_dim] + deriv_evaluations = [ + patch.evaluate(eval_points) for patch in deriv_orig.patches ] - # Evaluate finite difference gradient - fd_sensitivity = [ - (patch_perturbed - patch_orig) / heps - for patch_perturbed, patch_orig in zip( - microstructure_orig_evaluations, - microstructure_perturbed_evaluations, + for k_patch, patch_deriv_implemented, patch_deriv_fd in zip( + range(n_patches), deriv_evaluations, fd_sensitivity + ): + assert np.allclose( + -patch_deriv_implemented[:, jj_dim], + patch_deriv_fd[:, jj_dim], + ), ( + "Implemented derivative calculation for tile class" + + f"{tile_class}, at patch {k_patch+1}/{n_patches} does not " + + "match the derivative obtained using Finite Differences" ) - ] - - # Go through each direction - for jj_dim in range(dim): - deriv_orig = multipatch.fields[ii_ctps * dim + jj_dim] - deriv_evaluations = [ - patch.evaluate(eval_points) for patch in deriv_orig.patches - ] - for k_patch, patch_deriv_implemented, patch_deriv_fd in zip( - range(n_patches), deriv_evaluations, fd_sensitivity - ): - assert np.allclose( - -patch_deriv_implemented[:, jj_dim], - patch_deriv_fd[:, jj_dim], - ), ( - "Implemented derivative calculation for tile class" - + f"{tile_class}, at patch {k_patch+1}/{n_patches} does not " - + "match the derivative obtained using Finite Differences" - ) diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 87e306e39..92544484f 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -1,6 +1,7 @@ from inspect import getfullargspec import numpy as np +from pytest import mark import splinepy.microstructure as ms from splinepy.utils.data import cartesian_product as _cartesian_product @@ -17,7 +18,8 @@ def check_control_points(tile_patches): - """Check if all of tile's control points all lie within unit square/cube""" + """Helper function. Check if all of tile's control points all lie within unit + square/cube""" # Go through all patches for tile_patch in tile_patches: cps = tile_patch.control_points @@ -27,8 +29,8 @@ def check_control_points(tile_patches): def make_bounds_feasible(bounds): - """Bounds are given are understood as open set of min. and max. values. Therefore, - convert bounds to open set of these values. + """Helper function. Bounds are understood as open set of min. and max. values. + Therefore, convert bounds to open set of these values. Parameters ------------ @@ -46,7 +48,8 @@ def make_bounds_feasible(bounds): return np.array(feasible_bounds) -def test_tile_class(): +@mark.parametrize("tile_class", all_tile_classes) +def test_tile_class(tile_class): """Checks if all tile classes have the appropriate members and functions.""" required_class_variables = { "_para_dim": int, @@ -58,125 +61,122 @@ def test_tile_class(): "_parameters_shape": tuple, } - # Go through all available tiles - for tile_class in all_tile_classes: - # Get tile class' objects - members = [ - attr for attr in dir(tile_class) if not attr.startswith("__") - ] - - # Class must have function create_tile() + # Get tile class' objects + members = [attr for attr in dir(tile_class) if not attr.startswith("__")] + + # Class must have function create_tile() + assert hasattr( + tile_class, "create_tile" + ), "Tile class must have create_tile()" + # Tile must be able to take parameters and sensitivities as input + create_parameters = getfullargspec(tile_class.create_tile).args + for required_param in ["parameters", "parameter_sensitivities"]: + assert ( + required_param in create_parameters + ), f"create_tile() must have '{required_param}' as an input parameter" + + # Ensure closure can be handled correctly + if "closure" in create_parameters: + assert "_closure_directions" in members, ( + "Tile class has closure ability. The available closure directions " + + "are missing" + ) assert hasattr( - tile_class, "create_tile" - ), "Tile class must have create_tile()" - # Tile must be able to take parameters and sensitivities as input - create_parameters = getfullargspec(tile_class.create_tile).args - for required_param in ["parameters", "parameter_sensitivities"]: - assert ( - required_param in create_parameters - ), f"create_tile() must have '{required_param}' as an input parameter" - - # Ensure closure can be handled correctly - if "closure" in create_parameters: - assert "_closure_directions" in members, ( - "Tile class has closure ability. The available closure directions " - + "are missing" - ) - assert hasattr( - tile_class, "_closing_tile" - ), "Tile class has closure ability but no _closing_tile() function!" + tile_class, "_closing_tile" + ), "Tile class has closure ability but no _closing_tile() function!" - # Check if tile class has all required variables and they are the correct type - for required_variable, var_type in required_class_variables.items(): - assert ( - required_variable in members - ), f"Tile class needs to have member variable '{required_variable}'" - assert isinstance( - eval(f"tile_class.{required_variable}"), var_type - ), f"Variable {required_variable} needs to be of type {var_type}" + # Check if tile class has all required variables and they are the correct type + for required_variable, var_type in required_class_variables.items(): + assert ( + required_variable in members + ), f"Tile class needs to have member variable '{required_variable}'" + assert isinstance( + eval(f"tile_class.{required_variable}"), var_type + ), f"Variable {required_variable} needs to be of type {var_type}" -def test_tile_bounds(): +@mark.parametrize("tile_class", all_tile_classes) +def test_tile_bounds(tile_class): """Test if tile is still in unit cube at the bounds. Checks default and also non-default parameter values.""" - for tile_class in all_tile_classes: - tile_creator = tile_class() - # Create tile with default parameters - tile_patches, _ = tile_creator.create_tile() + tile_creator = tile_class() + # Create tile with default parameters + tile_patches, _ = tile_creator.create_tile() + check_control_points(tile_patches) + + # Skip certain classes for testing + skip_tile_class = False + for skip_tile in skip_tiles: + if tile_class is skip_tile: + skip_tile_class = True + break + if skip_tile_class: + return + + # Go through all extremes of parameters and ensure that also they create + # tiles within unit square/cube + feasible_parameter_bounds = make_bounds_feasible( + tile_creator._parameter_bounds + ) + all_parameter_bounds = _cartesian_product(feasible_parameter_bounds) + for parameter_extremes in all_parameter_bounds: + tile_patches, _ = tile_creator.create_tile( + parameters=parameter_extremes.reshape( + tile_creator._parameters_shape + ) + ) check_control_points(tile_patches) - # Skip certain classes for testing - skip_tile_class = False - for skip_tile in skip_tiles: - if tile_class is skip_tile: - skip_tile_class = True - break - if skip_tile_class: - continue - - # Go through all extremes of parameters and ensure that also they create - # tiles within unit square/cube - feasible_parameter_bounds = make_bounds_feasible( - tile_creator._parameter_bounds + +@mark.parametrize("tile_class", all_tile_classes) +def test_tile_closure(tile_class): + """Check if closing tiles also lie in unit cube.""" + + # Skip tile if if does not support closure + if "_closure_directions" not in dir(tile_class): + return + tile_creator = tile_class() + # Go through all implemented closure directions + for closure_direction in tile_creator._closure_directions: + tile_patches, sensitivities = tile_creator.create_tile( + closure=closure_direction ) - all_parameter_bounds = _cartesian_product(feasible_parameter_bounds) + assert ( + sensitivities is None + ), "Ensure sensitivities for closure are None if no sensitivities are asked" + + check_control_points(tile_patches) + + # Also check non-default parameters + # Skip certain classes for testing + skip_tile_class = False + for skip_tile in skip_tiles: + if tile_class is skip_tile: + skip_tile_class = True + break + if skip_tile_class: + return + + # Go through all extremes of parameters and ensure that also they create + # tiles within unit square/cube + feasible_parameter_bounds = make_bounds_feasible( + tile_creator._parameter_bounds + ) + all_parameter_bounds = _cartesian_product(feasible_parameter_bounds) + # Go through all implemented closure directions + for closure_direction in tile_creator._closure_directions: for parameter_extremes in all_parameter_bounds: tile_patches, _ = tile_creator.create_tile( parameters=parameter_extremes.reshape( tile_creator._parameters_shape - ) + ), + closure=closure_direction, ) check_control_points(tile_patches) -def test_tile_closure(): - """Check if closing tiles also lie in unit cube.""" - - for tile_class in all_tile_classes: - # Skip tile if if does not support closure - if "_closure_directions" not in dir(tile_class): - continue - tile_creator = tile_class() - # Go through all implemented closure directions - for closure_direction in tile_creator._closure_directions: - tile_patches, sensitivities = tile_creator.create_tile( - closure=closure_direction - ) - assert ( - sensitivities is None - ), "Ensure sensitivities for closure are None if no sensitivities are asked" - - check_control_points(tile_patches) - - # Also check non-default parameters - # Skip certain classes for testing - skip_tile_class = False - for skip_tile in skip_tiles: - if tile_class is skip_tile: - skip_tile_class = True - break - if skip_tile_class: - continue - - # Go through all extremes of parameters and ensure that also they create - # tiles within unit square/cube - feasible_parameter_bounds = make_bounds_feasible( - tile_creator._parameter_bounds - ) - all_parameter_bounds = _cartesian_product(feasible_parameter_bounds) - # Go through all implemented closure directions - for closure_direction in tile_creator._closure_directions: - for parameter_extremes in all_parameter_bounds: - tile_patches, _ = tile_creator.create_tile( - parameters=parameter_extremes.reshape( - tile_creator._parameters_shape - ), - closure=closure_direction, - ) - check_control_points(tile_patches) - - -def test_tile_derivatives(np_rng, heps=1e-7, n_test_points=10): +@mark.parametrize("tile_class", all_tile_classes) +def test_tile_derivatives(tile_class, np_rng, heps=1e-7, n_test_points=10): """Testing the correctness of the tile derivatives using Finite Differences. This includes every closure and no closure, every parameter and every patch by evaluating at random points and for random parameters. @@ -189,82 +189,79 @@ def test_tile_derivatives(np_rng, heps=1e-7, n_test_points=10): Number of testing points in the parametric domain """ - for tile_class in all_tile_classes: - tile_creator = tile_class() - # Skip test if tile class has no implemented sensitivities - if not tile_creator._sensitivities_implemented: - continue - - # Choose random parameter(s) within bounds - parameter_bounds = np.array(tile_creator._parameter_bounds) - parameters = parameter_bounds[:, 0] + np_rng.random( - len(parameter_bounds) - ) * np.ptp(parameter_bounds, axis=1) - parameters = parameters.reshape(tile_creator._parameters_shape) - - # Test no closure as well as ... - closure_directions = [None] - # ... every closure implemented - if "_closure_directions" in dir(tile_creator): - closure_directions += tile_creator._closure_directions - - # Retrieve shape values of parameters - n_eval_points = tile_creator._evaluation_points.shape[0] - n_info_per_eval_point = tile_creator._n_info_per_eval_point - - # Test each closure direction - for closure in closure_directions: - # Evaluate tile with given parameter and closure configuration - splines_orig, _ = tile_creator.create_tile( - parameters=parameters, closure=closure + tile_creator = tile_class() + # Skip test if tile class has no implemented sensitivities + if not tile_creator._sensitivities_implemented: + return + + # Choose random parameter(s) within bounds + parameter_bounds = np.array(tile_creator._parameter_bounds) + parameters = parameter_bounds[:, 0] + np_rng.random( + len(parameter_bounds) + ) * np.ptp(parameter_bounds, axis=1) + parameters = parameters.reshape(tile_creator._parameters_shape) + + # Test no closure as well as ... + closure_directions = [None] + # ... every closure implemented + if "_closure_directions" in dir(tile_creator): + closure_directions += tile_creator._closure_directions + + # Retrieve shape values of parameters + n_eval_points = tile_creator._evaluation_points.shape[0] + n_info_per_eval_point = tile_creator._n_info_per_eval_point + + # Test each closure direction + for closure in closure_directions: + # Evaluate tile with given parameter and closure configuration + splines_orig, _ = tile_creator.create_tile( + parameters=parameters, closure=closure + ) + # Set evaluation points as random spots in the parametric space + eval_points = np_rng.random((n_test_points, splines_orig[0].para_dim)) + splines_orig_evaluations = [ + spl.evaluate(eval_points) for spl in splines_orig + ] + # Go through all the parameters individually + for i_parameter in range(n_info_per_eval_point): + # Get derivatives w.r.t. one parameter + parameter_sensitivities = np.zeros( + (n_eval_points, n_info_per_eval_point, 1) ) - # Set evaluation points as random spots in the parametric space - eval_points = np_rng.random( - (n_test_points, splines_orig[0].para_dim) + parameter_sensitivities[:, i_parameter, :] = 1 + _, derivatives = tile_creator.create_tile( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + closure=closure, ) - splines_orig_evaluations = [ - spl.evaluate(eval_points) for spl in splines_orig + deriv_evaluations = [ + deriv.evaluate(eval_points) for deriv in derivatives[0] ] - # Go through all the parameters individually - for i_parameter in range(n_info_per_eval_point): - # Get derivatives w.r.t. one parameter - parameter_sensitivities = np.zeros( - (n_eval_points, n_info_per_eval_point, 1) - ) - parameter_sensitivities[:, i_parameter, :] = 1 - _, derivatives = tile_creator.create_tile( - parameters=parameters, - parameter_sensitivities=parameter_sensitivities, - closure=closure, + # Perform finite difference evaluation + parameters_perturbed = parameters.copy() + parameters_perturbed[:, i_parameter] += heps + splines_perturbed, _ = tile_creator.create_tile( + parameters=parameters_perturbed, closure=closure + ) + spline_perturbed_evaluations = [ + spl.evaluate(eval_points) for spl in splines_perturbed + ] + # Evaluate finite difference gradient + fd_sensitivities = [ + (spl_pert - spl_orig) / heps + for spl_pert, spl_orig in zip( + spline_perturbed_evaluations, splines_orig_evaluations ) - deriv_evaluations = [ - deriv.evaluate(eval_points) for deriv in derivatives[0] - ] - # Perform finite difference evaluation - parameters_perturbed = parameters.copy() - parameters_perturbed[:, i_parameter] += heps - splines_perturbed, _ = tile_creator.create_tile( - parameters=parameters_perturbed, closure=closure + ] + # Check every patch + n_patches = len(fd_sensitivities) + for i_patch, deriv_orig, deriv_fd in zip( + range(n_patches), deriv_evaluations, fd_sensitivities + ): + assert np.allclose(deriv_orig, deriv_fd), ( + "Implemented derivative calculation for tile class" + + f"{tile_class}, with closure {closure}, parameter " + + f"{i_parameter+1}/{n_info_per_eval_point} at patch " + + f"{i_patch+1}/{n_patches} does not match the derivative " + + "obtained using Finite Differences" ) - spline_perturbed_evaluations = [ - spl.evaluate(eval_points) for spl in splines_perturbed - ] - # Evaluate finite difference gradient - fd_sensitivities = [ - (spl_pert - spl_orig) / heps - for spl_pert, spl_orig in zip( - spline_perturbed_evaluations, splines_orig_evaluations - ) - ] - # Check every patch - n_patches = len(fd_sensitivities) - for i_patch, deriv_orig, deriv_fd in zip( - range(n_patches), deriv_evaluations, fd_sensitivities - ): - assert np.allclose(deriv_orig, deriv_fd), ( - "Implemented derivative calculation for tile class" - + f"{tile_class}, with closure {closure}, parameter " - + f"{i_parameter+1}/{n_info_per_eval_point} at patch " - + f"{i_patch+1}/{n_patches} does not match the derivative " - + "obtained using Finite Differences" - ) From eff65395ad8f91b6eb587ff8ac5bf52b23101a2c Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 15 Jan 2025 10:03:02 +0100 Subject: [PATCH 25/52] Add to description that tiles are not tested --- splinepy/microstructure/tiles/ellips_v_oid.py | 3 +++ splinepy/microstructure/tiles/snappy.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/splinepy/microstructure/tiles/ellips_v_oid.py b/splinepy/microstructure/tiles/ellips_v_oid.py index 67f31b6fd..878adcc2b 100644 --- a/splinepy/microstructure/tiles/ellips_v_oid.py +++ b/splinepy/microstructure/tiles/ellips_v_oid.py @@ -7,6 +7,9 @@ class EllipsVoid(_TileBase): """Void in form of an ellipsoid set into a unit cell. + TODO: Currently this tile is skipped for testing, since the control points easily + lie outside of the unit cube, even though the tile itself lies within it + The Ellips(v)oid :D Parametrization acts on the elipsoid's orientation as well as on its diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index 84eba670d..ab521f7b7 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -8,6 +8,9 @@ class Snappy(_TileBase): """Snap-through tile consisting of a thin truss and a thick truss that collide into each other. + # TODO: currently the tile parameters are not implemented as the parameters variable + therefore, no parameter sensitivities are calculated + .. raw:: html

Fullscreen.

From d07f06f624480ccb53abcf10191b9b6866e9e5ee Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 15 Jan 2025 10:03:55 +0100 Subject: [PATCH 26/52] Simplify code which skips tile classes --- tests/test_microtiles.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 92544484f..87a725dc3 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -105,12 +105,7 @@ def test_tile_bounds(tile_class): check_control_points(tile_patches) # Skip certain classes for testing - skip_tile_class = False - for skip_tile in skip_tiles: - if tile_class is skip_tile: - skip_tile_class = True - break - if skip_tile_class: + if tile_class in skip_tiles: return # Go through all extremes of parameters and ensure that also they create @@ -149,12 +144,7 @@ def test_tile_closure(tile_class): # Also check non-default parameters # Skip certain classes for testing - skip_tile_class = False - for skip_tile in skip_tiles: - if tile_class is skip_tile: - skip_tile_class = True - break - if skip_tile_class: + if tile_class in skip_tiles: return # Go through all extremes of parameters and ensure that also they create From d05fa5fff06b9b5b36600153cc8ef22080f86661 Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 15 Jan 2025 10:08:56 +0100 Subject: [PATCH 27/52] Failed sensitivity calculation now outputs evaluation points --- tests/test_microstructure.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 10c158bee..54096da1d 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -148,5 +148,7 @@ def test_macro_sensitivities(tile_class, np_rng, heps=1e-7, n_test_points=10): ), ( "Implemented derivative calculation for tile class" + f"{tile_class}, at patch {k_patch+1}/{n_patches} does not " - + "match the derivative obtained using Finite Differences" + + "match the derivative obtained using Finite Differences at " + + "the following evaluation points:\n" + + str(eval_points) ) From d8ba2e92be177186e93435ebae8566e95d6ad01a Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 15 Jan 2025 13:29:04 +0100 Subject: [PATCH 28/52] Fixing RNG seed, sensitivity step size and number of random test points --- tests/conftest.py | 19 +++++++++++++++++- tests/test_microstructure.py | 19 ++++++++++++++---- tests/test_microtiles.py | 39 ++++++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5043ef971..74981090a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,7 +15,7 @@ def error_log(*args): @pytest.fixture def np_rng(): - return np.random.default_rng() + return np.random.default_rng(seed=0) # query points @@ -41,6 +41,23 @@ def queries_3D(): ] +# hard-coded values to keep the same for derivative/sensitivity calculations +@pytest.fixture +def heps(): + """ + Perturbation/step size for finite difference evaluation of derivative/sensitivity + """ + return 1e-7 + + +@pytest.fixture +def n_test_points(): + """ + Number of random testing points (in parametric domain) + """ + return 10 + + # initializing a spline should be a test itself, so provide `dict_spline` # this is "iga-book"'s fig 2.15. @pytest.fixture diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 54096da1d..8e28ac08a 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -17,7 +17,13 @@ @mark.parametrize("tile_class", all_tile_classes) def test_closing_face(tile_class): - """Check if closing face is working""" + """Check if closing face is working + + Parameters + --------- + tile_class: tile class in splinepy.microstructure.tiles + Microtile + """ def check_if_closed(multipatch, closure_direction): """Helper function to see if multipatch has a closing surface @@ -83,17 +89,22 @@ def max_identifier(points): @mark.parametrize("tile_class", all_tile_classes) -def test_macro_sensitivities(tile_class, np_rng, heps=1e-7, n_test_points=10): +def test_macro_sensitivities(tile_class, np_rng, heps, n_test_points): """Testing the correctness of the derivatives of the whole microstructure w.r.t. the deformation function's control points. It is tested by evaluating the derivative obtained via finite differences. The values are evaluated at random points. Parameters ---------- + tile_class: tile class in splinepy.microstructure.tiles + Microtile + np_rng: numpy.random._generator.Generator + Default random number generator heps: float - Perturbation size for finite difference evaluation + Perturbation size for finite difference evaluation. Defined in conftest.py n_test_points: int - Number of testing points int the parametric domain""" + Number of testing points int the parametric domain. Defined in conftest.py + """ tile_creator = tile_class() deformation_function_orig = box(*BOX_DIMENSIONS[: tile_creator._dim]) diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 87a725dc3..3f1c8c75f 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -50,7 +50,13 @@ def make_bounds_feasible(bounds): @mark.parametrize("tile_class", all_tile_classes) def test_tile_class(tile_class): - """Checks if all tile classes have the appropriate members and functions.""" + """Checks if all tile classes have the appropriate members and functions. + + Parameters + --------- + tile_class: tile class in splinepy.microstructure.tiles + Microtile + """ required_class_variables = { "_para_dim": int, "_dim": int, @@ -98,7 +104,13 @@ def test_tile_class(tile_class): @mark.parametrize("tile_class", all_tile_classes) def test_tile_bounds(tile_class): """Test if tile is still in unit cube at the bounds. Checks default and also - non-default parameter values.""" + non-default parameter values. + + Parameters + --------- + tile_class: tile class in splinepy.microstructure.tiles + Microtile + """ tile_creator = tile_class() # Create tile with default parameters tile_patches, _ = tile_creator.create_tile() @@ -125,7 +137,13 @@ def test_tile_bounds(tile_class): @mark.parametrize("tile_class", all_tile_classes) def test_tile_closure(tile_class): - """Check if closing tiles also lie in unit cube.""" + """Check if closing tiles also lie in unit cube. + + Parameters + --------- + tile_class: tile class in splinepy.microstructure.tiles + Microtile + """ # Skip tile if if does not support closure if "_closure_directions" not in dir(tile_class): @@ -166,19 +184,22 @@ def test_tile_closure(tile_class): @mark.parametrize("tile_class", all_tile_classes) -def test_tile_derivatives(tile_class, np_rng, heps=1e-7, n_test_points=10): +def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): """Testing the correctness of the tile derivatives using Finite Differences. This includes every closure and no closure, every parameter and every patch by evaluating at random points and for random parameters. Parameters --------- + tile_class: tile class in splinepy.microstructure.tiles + Microtile + np_rng: numpy.random._generator.Generator + Default random number generator heps: float - Perturbation size for finite difference evaluation + Perturbation size for finite difference evaluation. Defined in conftest.py n_test_points: int - Number of testing points in the parametric domain + Number of testing points in the parametric domain. Defined in conftest.py """ - tile_creator = tile_class() # Skip test if tile class has no implemented sensitivities if not tile_creator._sensitivities_implemented: @@ -253,5 +274,7 @@ def test_tile_derivatives(tile_class, np_rng, heps=1e-7, n_test_points=10): + f"{tile_class}, with closure {closure}, parameter " + f"{i_parameter+1}/{n_info_per_eval_point} at patch " + f"{i_patch+1}/{n_patches} does not match the derivative " - + "obtained using Finite Differences" + + "obtained using Finite Differences at the following evaluation " + + "points:\n" + + str(eval_points) ) From 42ade4e3b762ad0a46f1175517f19c340e0d641f Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 15 Jan 2025 13:42:28 +0100 Subject: [PATCH 29/52] Fix failing knot vector test --- tests/test_knot_vectors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_knot_vectors.py b/tests/test_knot_vectors.py index 329d165b5..c7ddb41f2 100644 --- a/tests/test_knot_vectors.py +++ b/tests/test_knot_vectors.py @@ -29,4 +29,4 @@ def test_knot_vectors(splinetype, request): spline.knot_multiplicities, spline.knot_vectors, ): - assert np.allclose(np.array(spl_kv), np.repeat(u_kv, kn_m)) + assert np.allclose(spl_kv.numpy(), np.repeat(u_kv, kn_m)) From da02b45130dd60cf2c596562b2843d12ce7bb957 Mon Sep 17 00:00:00 2001 From: markriegler Date: Wed, 15 Jan 2025 15:17:06 +0100 Subject: [PATCH 30/52] Remove @classmethod when there is also @property, due to issues in Python 3.8 --- splinepy/microstructure/tiles/tile_base.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index 5c1fe89e9..1e90a037d 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -30,7 +30,6 @@ def _raise_if_not_set_else_return(cls, attr_name): ) return attr - @classmethod @property def evaluation_points(cls): """Positions in the parametrization function to be evaluated when tile @@ -46,7 +45,6 @@ def evaluation_points(cls): """ return cls._raise_if_not_set_else_return("_evaluation_points") - @classmethod @property def dim(cls): """Returns dimensionality in physical space of the Microtile. @@ -61,7 +59,6 @@ def dim(cls): """ return cls._raise_if_not_set_else_return("_dim") - @classmethod @property def para_dim(cls): """Returns dimensionality in parametric space of the Microtile. From df680e544887bc683a42af68b643898e1590c69b Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 16 Jan 2025 15:22:39 +0100 Subject: [PATCH 31/52] Refactor, add common code to TileBase --- splinepy/microstructure/tiles/tile_base.py | 187 ++++++++++++++++++++- tests/test_microstructure.py | 2 +- tests/test_microtiles.py | 4 +- 3 files changed, 183 insertions(+), 10 deletions(-) diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index 1e90a037d..77306dac3 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -12,6 +12,11 @@ class TileBase(_SplinepyBase): _para_dim = None _evaluation_points = None _n_info_per_eval_point = None + _sensitivities_implemented = None + _closure_directions = None + _parameter_bounds = None + _parameters_shape = None + _default_parameter_value = None def __init__(self): if type(self) is TileBase: @@ -45,6 +50,20 @@ def evaluation_points(cls): """ return cls._raise_if_not_set_else_return("_evaluation_points") + @property + def n_info_per_eval_point(cls): + """Number of parameters per evaluation point + + Parameters + ---------- + None + + Returns + ------- + n_info : int + """ + return cls._raise_if_not_set_else_return("_n_info_per_eval_point") + @property def dim(cls): """Returns dimensionality in physical space of the Microtile. @@ -73,8 +92,79 @@ def para_dim(cls): """ return cls._raise_if_not_set_else_return("_para_dim") - def check_params(self, params): - """Checks if the parameters have the correct format and shape + @property + def sensitivites_implemented(cls): + """Returns whether sensitivities are implemented for the microtile + + Parameters + ---------- + None + + Returns + ------- + is_implemented: bool + """ + return cls._raise_if_not_set_else_return("_sensitivities_implemented") + + @property + def closure_directions(self): + """Returns the available closure directions of the microtile + + Parameters + ---------- + None + + Returns + ------- + directions: None/list + """ + return self._closure_directions + + @property + def parameter_bounds(cls): + """Returns the bounds for the microtiles' parameters + + Parameters + ---------- + None + + Returns + ------- + bounds: list> + """ + return cls._raise_if_not_set_else_return("_parameter_bounds") + + @property + def parameters_shape(cls): + """Returns the shape of the microtile's parameters array + + Parameters + ---------- + None + + Returns + ------- + shape: tuple + """ + return cls._raise_if_not_set_else_return("_parameters_shape") + + @property + def default_parameter_value(cls): + """Returns the default value of the microtile's parameters + + Parameters + ---------- + None + + Returns + ------- + default_value: float/None + """ + return cls._default_parameter_value + + def check_params(self, parameters): + """Checks if the parameters have the correct format and shape and are within + defined bounds Parameters ---------- @@ -85,14 +175,14 @@ def check_params(self, params): ------- True: Boolean """ - # check if tuple - - if not (isinstance(params, _np.ndarray) and params.ndim == 2): + # Check correct format + if not (isinstance(parameters, _np.ndarray) and parameters.ndim == 2): raise TypeError("parameters must be two-dimensional np array") + # Check correct shape if not ( - (self._evaluation_points.shape[0] == params.shape[0]) - and (self._n_info_per_eval_point == params.shape[1]) + (self._evaluation_points.shape[0] == parameters.shape[0]) + and (self._n_info_per_eval_point == parameters.shape[1]) ): raise TypeError( f"Mismatch in parameter size, expected " @@ -100,6 +190,20 @@ def check_params(self, params): f"{self._n_info_per_eval_point}" ) + # Check if all parameters are within bounds + if self._parameter_bounds is not None: + bounds = _np.array(self._parameter_bounds) + lower_bounds = bounds[:, 0] + upper_bounds = bounds[:, 1] + within_bounds = (parameters.ravel() > lower_bounds) & ( + parameters.ravel() < upper_bounds + ) + if not _np.all(within_bounds): + raise ValueError( + f"The parameters {parameters} must be within the following bounds: " + + f"lower: {lower_bounds} and upper: {upper_bounds}" + ) + return True def check_param_derivatives(self, derivatives): @@ -153,3 +257,72 @@ def create_tile(self, **kwargs): raise NotImplementedError( f"create_tile() not implemented for {type(self)}" ) + + def _process_input(self, parameters, parameter_sensitivities): + """Processing input for create_tile and _closing_tile + + Parameters + ------------- + parameters: np.ndarray + Tile parameters + parameter_sensitivities: np.ndarray + Tile parameter sensitivities to be calculated + + Returns + --------- + parameters: np.ndarray + Tile parameters + n_derivatives: np.ndarray + Number of different derivatives to compute + derivatives: list/None + Initialized list of derivatives + """ + # Set parameters to default values if not user-given + if parameters is None: + default_value = self.default_parameter_value + self._logd( + f"Setting parameters to default values ({default_value})" + ) + if isinstance(default_value, float): + parameters = _np.full( + (len(self.evaluation_points), self.n_info_per_eval_point), + default_value, + ) + elif isinstance(default_value, _np.ndarray): + parameters = default_value + + # Initialize list of derivatives + if parameter_sensitivities is not None: + n_derivatives = parameter_sensitivities.shape[2] + derivatives = [] + else: + n_derivatives = 0 + derivatives = None + + # Validity check of parameters and their sensitivities + self.check_params(parameters) + self.check_param_derivatives(parameter_sensitivities) + + return parameters, n_derivatives, derivatives + + def _check_custom_parameter(self, value, param_name, min_bound, max_bound): + """Check if a custom tile parameter (e.g. contact length) is within bounds + + Parameters + ------------------ + value: float + Value of the custom parameter + param_name: str + Name of custom parameter + min_bound: float + Lower bound for parameter + max_bound: float + Upper bound for parameter + """ + if not isinstance(value, float): + raise ValueError(f"Invalid type for {param_name}") + + if not ((value > min_bound) and (value < max_bound)): + raise ValueError( + f"{param_name} must be in ({min_bound}, {max_bound})" + ) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 8e28ac08a..10f6be9ce 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -66,7 +66,7 @@ def max_identifier(points): ), f"The closure of the {closure_direction}_max surface is not complete" # Skip tile if it doesn't support closure - if "_closure_directions" not in dir(tile_class): + if tile_class._closure_directions is None: return # TODO: right now skip tiles which have faulty closures diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 3f1c8c75f..e28bcc55e 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -146,7 +146,7 @@ def test_tile_closure(tile_class): """ # Skip tile if if does not support closure - if "_closure_directions" not in dir(tile_class): + if tile_class._closure_directions is None: return tile_creator = tile_class() # Go through all implemented closure directions @@ -215,7 +215,7 @@ def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): # Test no closure as well as ... closure_directions = [None] # ... every closure implemented - if "_closure_directions" in dir(tile_creator): + if tile_creator._closure_directions is not None: closure_directions += tile_creator._closure_directions # Retrieve shape values of parameters From c2bb90c1c4d954bd18149a135c3c57b7ab0170e0 Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 16 Jan 2025 15:25:01 +0100 Subject: [PATCH 32/52] Refactor all tile classes to make use of common functions --- splinepy/microstructure/tiles/armadillo.py | 71 ++++------------ splinepy/microstructure/tiles/chi.py | 32 ++------ splinepy/microstructure/tiles/cross_2d.py | 80 +++++-------------- splinepy/microstructure/tiles/cross_3d.py | 73 +++++------------ .../microstructure/tiles/cross_3d_linear.py | 73 +++++------------ splinepy/microstructure/tiles/cube_void.py | 18 ++--- .../microstructure/tiles/double_lattice.py | 35 +++----- splinepy/microstructure/tiles/ellips_v_oid.py | 15 ++-- splinepy/microstructure/tiles/hollow_cube.py | 25 ++---- .../microstructure/tiles/hollow_octagon.py | 70 +++------------- .../tiles/hollow_octagon_extrude.py | 79 ++++-------------- .../microstructure/tiles/inverse_cross_3d.py | 75 +++++------------ splinepy/microstructure/tiles/snappy.py | 5 +- 13 files changed, 153 insertions(+), 498 deletions(-) diff --git a/splinepy/microstructure/tiles/armadillo.py b/splinepy/microstructure/tiles/armadillo.py index e9fe2a50c..bbac762a9 100644 --- a/splinepy/microstructure/tiles/armadillo.py +++ b/splinepy/microstructure/tiles/armadillo.py @@ -31,6 +31,7 @@ class Armadillo(_TileBase): ] _parameter_bounds = [[0.0, 0.5]] _parameters_shape = (1, 1) + _default_parameter_value = 0.2 def _closing_tile( self, @@ -69,35 +70,14 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - if not isinstance(contact_length, float): - raise ValueError("Invalid Type for radius") + self._check_custom_parameter( + contact_length, "contact length", 0.0, 0.99 + ) - if not ((contact_length > 0) and (contact_length < 0.99)): - raise ValueError("The length of a side must be in (0.01, 0.99)") - - if parameters is None: - self._logd("Setting parameters to default values (0.2)") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - self.check_params(parameters) - self.check_param_derivatives(parameter_sensitivities) - - if parameter_sensitivities is not None: - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" - ) + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) splines = [] for i_derivative in range(n_derivatives + 1): @@ -5062,35 +5042,14 @@ def create_tile( derivative_list : list / None """ - if not isinstance(contact_length, float): - raise ValueError("Invalid Type for radius") + self._check_custom_parameter( + contact_length, "contact length", 0.0, 0.99 + ) - if not ((contact_length > 0) and (contact_length < 0.99)): - raise ValueError("The length of a side must be in (0.01, 0.99)") - - if parameters is None: - self._logd("Setting parameters to default values (0.2)") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - self.check_params(parameters) - self.check_param_derivatives(parameter_sensitivities) - - if parameter_sensitivities is not None: - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" - ) + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) if closure is not None: return self._closing_tile( diff --git a/splinepy/microstructure/tiles/chi.py b/splinepy/microstructure/tiles/chi.py index 0bcd215e9..4a48132dd 100644 --- a/splinepy/microstructure/tiles/chi.py +++ b/splinepy/microstructure/tiles/chi.py @@ -21,6 +21,7 @@ class Chi(_TileBase): _sensitivities_implemented = True _parameter_bounds = [[-_np.pi / 2, _np.pi / 2]] _parameters_shape = (1, 1) + _default_parameter_value = _np.pi / 8 def create_tile( self, @@ -44,33 +45,10 @@ def create_tile( microtile_list : list(splines) """ - # set to default if nothing is given - if parameters is None: - self._logd( - "Tile request is not parametrized, setting default Pi/8" - ) - parameters = _np.array([[_np.pi / 8]]) - else: - angle_bounds = self._parameter_bounds[0] - if not ( - _np.all(parameters >= angle_bounds[0]) - and _np.all(parameters < angle_bounds[1]) - ): - error_message = ( - f"The parameter must be in {angle_bounds[0]}" - + f"and {angle_bounds[1]}" - ) - raise ValueError(error_message) - pass - self.check_params(parameters) - - # Check if user requests derivative splines - if self.check_param_derivatives(parameter_sensitivities): - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) splines = [] for i_derivative in range(n_derivatives + 1): diff --git a/splinepy/microstructure/tiles/cross_2d.py b/splinepy/microstructure/tiles/cross_2d.py index 2fe51c2be..b919ff0ad 100644 --- a/splinepy/microstructure/tiles/cross_2d.py +++ b/splinepy/microstructure/tiles/cross_2d.py @@ -32,6 +32,7 @@ class Cross2D(_TileBase): [0.0, 0.5] ] * 4 # valid for default center_expansion=1.0 _parameters_shape = (4, 1) + _default_parameter_value = 0.2 def _closing_tile( self, @@ -72,36 +73,17 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - if parameters is None: - self._logd("Tile request is not parametrized, setting default 0.2") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - self.check_params(parameters) - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError("Thickness out of range (0, .5)") + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) - if not (0.0 < float(boundary_width) < 0.5): - raise ValueError("Boundary Width is out of range") - - if not (0.0 < float(filling_height) < 1.0): - raise ValueError("Filling must be in (0,1)") - - # Check if user requests derivative splines - if parameter_sensitivities is not None: - # Check format - self.check_param_derivatives(parameter_sensitivities) - - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None + self._check_custom_parameter( + boundary_width, "boundary width", 0.0, 0.5 + ) + self._check_custom_parameter( + filling_height, "filling height", 0.0, 1.0 + ) splines = [] for i_derivative in range(n_derivatives + 1): @@ -420,43 +402,19 @@ def create_tile( derivative_list : list / None """ - if not isinstance(center_expansion, float): - raise ValueError("Invalid Type") + self._check_custom_parameter( + center_expansion, "center expansion", 0.5, 1.5 + ) - if not ((center_expansion > 0.5) and (center_expansion < 1.5)): - error_message = "Center Expansion must be in (0.5, 1.5)" - raise ValueError(error_message) + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) max_radius = min(0.5, (0.5 / center_expansion)) - - # set to default if nothing is given - if parameters is None: - self._logd("Setting branch thickness to default 0.2") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - self.check_params(parameters) - - if not (_np.all(parameters > 0) and _np.all(parameters < max_radius)): + if not _np.all(parameters < max_radius): raise ValueError(f"Thickness out of range (0, {max_radius})") - self.check_param_derivatives(parameter_sensitivities) - - # Check if user requests derivative splines - if parameter_sensitivities is not None: - # Check format - self.check_param_derivatives(parameter_sensitivities) - - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - # Closure requested, pass to function if closure is not None: return self._closing_tile( diff --git a/splinepy/microstructure/tiles/cross_3d.py b/splinepy/microstructure/tiles/cross_3d.py index fba595111..5552d998e 100644 --- a/splinepy/microstructure/tiles/cross_3d.py +++ b/splinepy/microstructure/tiles/cross_3d.py @@ -34,6 +34,7 @@ class Cross3D(_TileBase): [0.0, 0.5] ] * 6 # valid for default center_expansion=1.0 _parameters_shape = (6, 1) + _default_parameter_value = 0.2 def _closing_tile( self, @@ -74,32 +75,17 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - if parameters is None: - self._logd("Tile request is not parametrized, setting default 0.2") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError("Thickness out of range (0, .5)") + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) - # Check if user requests derivative splines - if parameter_sensitivities is not None: - self.check_param_derivatives(parameter_sensitivities) - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - - if not (0.0 < float(boundary_width) < 0.5): - raise ValueError("Boundary Width is out of range") - - if not (0.0 < float(filling_height) < 1.0): - raise ValueError("Filling must be in (0,1)") + self._check_custom_parameter( + boundary_width, "boundary width", 0.0, 0.5 + ) + self._check_custom_parameter( + filling_height, "filling height", 0.0, 1.0 + ) splines = [] for i_derivative in range(n_derivatives + 1): @@ -524,44 +510,23 @@ def create_tile( derivative_list : list / None """ - if not isinstance(center_expansion, float): - raise ValueError("Invalid Type") + self._check_custom_parameter( + center_expansion, "center expansion", 0.5, 1.5 + ) - if not ((center_expansion > 0.5) and (center_expansion < 1.5)): - raise ValueError("Center Expansion must be in (.5,1.5)") + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) # Max radius, so there is no tanglement in the crosstile max_radius = min(0.5, (0.5 / center_expansion)) - - # set to default if nothing is given - if parameters is None: - self._logd("Setting branch thickness to default 0.2") - parameters = ( - _np.ones( - ( - self._evaluation_points.shape[0], - self._n_info_per_eval_point, - ) - ) - * 0.2 - ) - - # Check for type and consistency - self.check_params(parameters) - if _np.any(parameters <= 0) or _np.any(parameters > max_radius): + if _np.any(parameters > max_radius): raise ValueError( f"Radii must be in (0,{max_radius}) for " f"center_expansion {center_expansion}" ) - if parameter_sensitivities is not None: - self.check_param_derivatives(parameter_sensitivities) - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - if closure is not None: if closure not in self._closure_directions: raise NotImplementedError( diff --git a/splinepy/microstructure/tiles/cross_3d_linear.py b/splinepy/microstructure/tiles/cross_3d_linear.py index 22c0f7959..103fa6372 100644 --- a/splinepy/microstructure/tiles/cross_3d_linear.py +++ b/splinepy/microstructure/tiles/cross_3d_linear.py @@ -34,6 +34,7 @@ class Cross3DLinear(_TileBase): [0.0, 0.5] ] * 6 # valid for default center_expansion=1.0 _parameters_shape = (6, 1) + _default_parameter_value = 0.2 def _closing_tile( self, @@ -74,32 +75,17 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - if parameters is None: - self._logd("Tile request is not parametrized, setting default 0.2") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError("Thickness out of range (0, .5)") + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) - # Check if user requests derivative splines - if parameter_sensitivities is not None: - self.check_param_derivatives(parameter_sensitivities) - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - - if not (0.0 < float(boundary_width) < 0.5): - raise ValueError("Boundary Width is out of range") - - if not (0.0 < float(filling_height) < 1.0): - raise ValueError("Filling must be in (0,1)") + self._check_custom_parameter( + boundary_width, "boundary width", 0.0, 0.5 + ) + self._check_custom_parameter( + filling_height, "filling height", 0.0, 1.0 + ) splines = [] for i_derivative in range(n_derivatives + 1): @@ -480,44 +466,23 @@ def create_tile( derivative_list : list / None """ - if not isinstance(center_expansion, float): - raise ValueError("Invalid Type") + self._check_custom_parameter( + center_expansion, "center expansion", 0.5, 1.5 + ) - if not ((center_expansion > 0.5) and (center_expansion < 1.5)): - raise ValueError("Center Expansion must be in (.5,1.5)") + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) # Max radius, so there is no tanglement in the crosstile max_radius = min(0.5, (0.5 / center_expansion)) - - # set to default if nothing is given - if parameters is None: - self._logd("Setting branch thickness to default 0.2") - parameters = ( - _np.ones( - ( - self._evaluation_points.shape[0], - self._n_info_per_eval_point, - ) - ) - * 0.2 - ) - - # Check for type and consistency - self.check_params(parameters) - if _np.any(parameters <= 0) or _np.any(parameters > max_radius): + if _np.any(parameters > max_radius): raise ValueError( f"Radii must be in (0,{max_radius}) for " f"center_expansion {center_expansion}" ) - if parameter_sensitivities is not None: - self.check_param_derivatives(parameter_sensitivities) - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - if closure is not None: return self._closing_tile( parameters=parameters, diff --git a/splinepy/microstructure/tiles/cube_void.py b/splinepy/microstructure/tiles/cube_void.py index 9eeb3a33b..0ac29e965 100644 --- a/splinepy/microstructure/tiles/cube_void.py +++ b/splinepy/microstructure/tiles/cube_void.py @@ -35,6 +35,7 @@ class CubeVoid(_TileBase): [-_np.pi / 2, _np.pi / 2], ] _parameters_shape = (1, 4) + _default_parameter_value = _np.array([[0.5, 0.5, 0.0, 0.0]]) # Aux values _sphere_ctps = _np.array( @@ -100,23 +101,16 @@ def create_tile( microtile_list : list(splines) derivatives : list> / None """ # set to default if nothing is given - if parameters is None: - parameters = _np.array([0.5, 0.5, 0, 0]).reshape( - self._parameters_shape - ) + + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) # Create center ellipsoid # RotY * RotX * DIAG(r_x, r_yz) * T_base [r_x, r_yz, rot_x, rot_y] = parameters.flatten() - # Check if user requests derivative splines - if self.check_param_derivatives(parameter_sensitivities): - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - # Prepare auxiliary matrices and values diag = _np.diag([r_x, r_yz, r_yz]) rotMx = self._rotation_matrix_x(rot_x) diff --git a/splinepy/microstructure/tiles/double_lattice.py b/splinepy/microstructure/tiles/double_lattice.py index e040078f9..d1fb1438a 100644 --- a/splinepy/microstructure/tiles/double_lattice.py +++ b/splinepy/microstructure/tiles/double_lattice.py @@ -23,6 +23,7 @@ class DoubleLattice(_TileBase): _sensitivities_implemented = True _parameter_bounds = [[0.0, 1 / (2 * (1 + _np.sqrt(2)))]] * 2 _parameters_shape = (1, 2) + _default_parameter_value = 0.1 def create_tile( self, @@ -53,32 +54,14 @@ def create_tile( ------- microtile_list : list(splines) """ - if not isinstance(contact_length, float): - raise ValueError("Invalid Type") - if not ((contact_length > 0.0) and (contact_length < 1.0)): - raise ValueError("Contact length must be in (0.,1.)") - - # set to default if nothing is given - if parameters is None: - self._logd("Tile request is not parametrized, setting default 0.2") - parameters = _np.ones((1, 2)) * 0.1 - if not ( - _np.all(parameters > 0) - and _np.all(parameters < 0.5 / (1 + _np.sqrt(2))) - ): - raise ValueError( - "Parameters must be between 0.01 and 0.5/(1+sqrt(2))=0.207" - ) - - self.check_params(parameters) - - # Check if user requests derivative splines - if self.check_param_derivatives(parameter_sensitivities): - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None + self._check_custom_parameter( + contact_length, "contact length", 0.0, 1.0 + ) + + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) splines = [] for i_derivative in range(n_derivatives + 1): diff --git a/splinepy/microstructure/tiles/ellips_v_oid.py b/splinepy/microstructure/tiles/ellips_v_oid.py index 878adcc2b..37d12c669 100644 --- a/splinepy/microstructure/tiles/ellips_v_oid.py +++ b/splinepy/microstructure/tiles/ellips_v_oid.py @@ -41,6 +41,7 @@ class EllipsVoid(_TileBase): [-_np.pi / 2, _np.pi / 2], ] _parameters_shape = (1, 4) + _default_parameter_value = _np.array([[0.5, 0.5, 0, 0]]) # Aux values _c0 = 0.5 / 3**0.5 @@ -130,21 +131,15 @@ def create_tile( microtile_list : list(splines) derivatives: list> / None """ # set to default if nothing is given - if parameters is None: - parameters = _np.array([0.5, 0.5, 0, 0]).reshape(1, 1, 4) + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) # Create center ellipsoid # RotY * RotX * DIAG(r_x, r_yz) * T_base [r_x, r_yz, rot_x, rot_y] = parameters.flatten() - # Check if user requests derivative splines - if self.check_param_derivatives(parameter_sensitivities): - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - # Prepare auxiliary matrices and values diag = _np.diag([r_x, r_yz, r_yz]) rotMx = self._rotation_matrix_x(rot_x) diff --git a/splinepy/microstructure/tiles/hollow_cube.py b/splinepy/microstructure/tiles/hollow_cube.py index a93e3b457..58d2ba5f8 100644 --- a/splinepy/microstructure/tiles/hollow_cube.py +++ b/splinepy/microstructure/tiles/hollow_cube.py @@ -31,6 +31,7 @@ class HollowCube(_TileBase): _sensitivities_implemented = True _parameter_bounds = [[0.0, 0.5]] * 7 _parameters_shape = (7, 1) + _default_parameter_value = 0.2 def create_tile( self, @@ -57,26 +58,10 @@ def create_tile( microtile_list : list(splines) """ - if parameters is None: - self._logd("Setting parameters to default value (0.2)") - parameters = ( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ).reshape(-1, 1) - * 0.2 - ) - - self.check_params(parameters) - - if not _np.all((parameters > 0.0) & (parameters < 0.5)): - raise ValueError("The wall thickness must be in (0.0 and 0.5)") - - if self.check_param_derivatives(parameter_sensitivities): - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) splines = [] diff --git a/splinepy/microstructure/tiles/hollow_octagon.py b/splinepy/microstructure/tiles/hollow_octagon.py index 22ace6555..c1e3271ec 100644 --- a/splinepy/microstructure/tiles/hollow_octagon.py +++ b/splinepy/microstructure/tiles/hollow_octagon.py @@ -22,6 +22,7 @@ class HollowOctagon(_TileBase): _closure_directions = ["x_min", "x_max", "y_min", "y_max"] _parameter_bounds = [[0.0, 0.5]] _parameters_shape = (1, 1) + _default_parameter_value = 0.2 def _closing_tile( self, @@ -55,35 +56,12 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - if parameters is None: - self._log("Tile request is not parametrized, setting default 0.2") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" - ) - - self.check_params(parameters) - self.check_param_derivatives(parameter_sensitivities) - - if parameter_sensitivities is not None: - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) v_h_void = parameters[0, 0] - if not ((v_h_void > 0.0) and (v_h_void < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.0 and 0.5)" - ) splines = [] for i_derivative in range(n_derivatives + 1): @@ -454,36 +432,14 @@ def create_tile( microtile_list : list(splines) derivatives: list> / None """ - - if not isinstance(contact_length, float): - raise ValueError("Invalid Type for radius") - - if not ((contact_length > 0) and (contact_length < 0.99)): - raise ValueError("The length of a side must be in (0.01, 0.99)") - - if parameters is None: - self._logd("Setting parameters to default values (0.2)") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - if parameter_sensitivities is not None: - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - - self.check_params(parameters) - self.check_param_derivatives(parameter_sensitivities) - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" - ) + self._check_custom_parameter( + contact_length, "contact length", 0.0, 0.99 + ) + + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) if closure is not None: return self._closing_tile( diff --git a/splinepy/microstructure/tiles/hollow_octagon_extrude.py b/splinepy/microstructure/tiles/hollow_octagon_extrude.py index 1ad07f70f..6bcfd4313 100644 --- a/splinepy/microstructure/tiles/hollow_octagon_extrude.py +++ b/splinepy/microstructure/tiles/hollow_octagon_extrude.py @@ -19,10 +19,10 @@ class HollowOctagonExtrude(_TileBase): _evaluation_points = _np.array([[0.5, 0.5, 0.5]]) _n_info_per_eval_point = 1 _sensitivities_implemented = True - # TODO: closure in create_tile still missing _closure_directions = ["x_min", "x_max", "y_min", "y_max"] _parameter_bounds = [[0.0, 0.5]] _parameters_shape = (1, 1) + _default_parameter_value = 0.2 def create_tile( self, @@ -56,27 +56,16 @@ def create_tile( derivatives: list> / None """ - if not isinstance(contact_length, float): - raise ValueError("Invalid Type for radius") + self._check_custom_parameter( + contact_length, "contact length", 0.0, 0.99 + ) + # Process input + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) - if not ((contact_length > 0) and (contact_length < 0.99)): - raise ValueError("The length of a side must be in (0.01, 0.99)") - - if parameters is None: - self._logd("Setting parameters to default values (0.2)") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - if parameter_sensitivities is not None: - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None + v_h_void = parameters[0, 0] if closure is not None: return self._closing_tile( @@ -87,15 +76,6 @@ def create_tile( **kwargs, ) - self.check_params(parameters) - self.check_param_derivatives(parameter_sensitivities) - - v_h_void = parameters[0, 0] - if not ((v_h_void > 0.0) and (v_h_void < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.0 and 0.5)" - ) - splines = [] for i_derivative in range(n_derivatives + 1): if i_derivative == 0: @@ -259,7 +239,7 @@ def create_tile( def _closing_tile( self, parameters=None, - parameter_sensitivities=None, # TODO + parameter_sensitivities=None, contact_length=0.2, closure=None, ): @@ -291,40 +271,13 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - if parameters is None: - self._log("Tile request is not parametrized, setting default 0.2") - parameters = _np.array( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - if not (_np.all(parameters[0] > 0) and _np.all(parameters[0] < 0.5)): - raise ValueError( - "The thickness of the wall must be in (0.01 and 0.49)" - ) - - self.check_params(parameters) + # Process input + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) - if parameter_sensitivities is not None: - self.check_param_derivatives(parameter_sensitivities) - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - - # Check whether parameter is within bounds v_h_void = parameters[0, 0] - para_bound_lower, para_bound_upper = self._parameter_bounds[0] - if not ( - (v_h_void > para_bound_lower) and (v_h_void < para_bound_upper) - ): - raise ValueError( - f"The thickness of the wall must be in ({para_bound_lower} and " - + f"{para_bound_upper})" - ) splines = [] for i_derivative in range(n_derivatives + 1): diff --git a/splinepy/microstructure/tiles/inverse_cross_3d.py b/splinepy/microstructure/tiles/inverse_cross_3d.py index 4787cd3b2..5a366ee11 100644 --- a/splinepy/microstructure/tiles/inverse_cross_3d.py +++ b/splinepy/microstructure/tiles/inverse_cross_3d.py @@ -37,6 +37,7 @@ class InverseCross3D(_TileBase): _closure_directions = ["z_min", "z_max"] _parameter_bounds = [[0.2, 0.3]] * 6 # For default values _parameters_shape = (6, 1) + _default_parameter_value = 0.21 def _closing_tile( self, @@ -74,37 +75,17 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - if parameters is None: - self._logd("Tile request is not parametrized, setting default 0.2") - parameters = ( - _np.ones( - ( - self._evaluation_points.shape[0], - self._n_info_per_eval_point, - ) - ) - * 0.2 - ) - - self.check_params(parameters) - - if parameter_sensitivities is not None: - self.check_param_derivatives(parameter_sensitivities) - - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None - - if not (_np.all(parameters > 0) and _np.all(parameters < 0.5)): - raise ValueError("Thickness out of range (0, .5)") + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) - if not (0.0 < float(boundary_width) < 0.5): - raise ValueError("Boundary Width is out of range") - - if not (0.0 < float(filling_height) < 1.0): - raise ValueError("Filling must be in (0,1)") + self._check_custom_parameter( + boundary_width, "boundary width", 0.0, 0.5 + ) + self._check_custom_parameter( + filling_height, "filling height", 0.0, 1.0 + ) splines = [] @@ -1069,43 +1050,25 @@ def create_tile( microtile_list : list(splines) """ - if not isinstance(center_expansion, float): - raise ValueError("Invalid type for center_expansion") - - if not ((center_expansion > 0.5) and (center_expansion < 1.5)): - raise ValueError("Center Expansion must be in (.5, 1.5)") + self._check_custom_parameter( + center_expansion, "center expansion", 0.5, 1.5 + ) # Check if all radii are in allowed range max_radius = min(0.5, (0.5 / center_expansion)) max_radius = min(max_radius, separator_distance) min_radius = max(0.5 - separator_distance, 0) - # set to default if nothing is given - if parameters is None: - self._logd("Setting branch thickness to default 0.2") - parameters = ( - _np.ones( - (len(self._evaluation_points), self._n_info_per_eval_point) - ) - * 0.2 - ) - - self.check_params(parameters) - - if parameter_sensitivities is not None: - self.check_param_derivatives(parameter_sensitivities) - - n_derivatives = parameter_sensitivities.shape[2] - derivatives = [] - else: - n_derivatives = 0 - derivatives = None + parameters, n_derivatives, derivatives = self._process_input( + parameters=parameters, + parameter_sensitivities=parameter_sensitivities, + ) if _np.any(parameters < min_radius) or _np.any( parameters > max_radius ): raise ValueError( - f"Radii must be in (0,{max_radius}) for " + f"Radii must be in ({min_radius},{max_radius}) for " f"center_expansion {center_expansion}" ) diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index ab521f7b7..d3202aa63 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -353,8 +353,9 @@ def create_tile( if param < 0: raise ValueError("Invalid parameter, must be > 0.") - if not ((contact_length > 0) and (contact_length < 0.49)): - raise ValueError("The length of a side must be in (0.01, 0.49)") + self._check_custom_parameter( + contact_length, "contact length", 0.0, 0.49 + ) # Check horizontal parameters if not ((r + contact_length) < 0.5): From a042ca01c69fe060fca86e2b695e49896747bd39 Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 16 Jan 2025 18:01:58 +0100 Subject: [PATCH 33/52] Add comments according to coderabbitai --- tests/conftest.py | 9 ++++++++- tests/test_microstructure.py | 10 ++++++++++ tests/test_microtiles.py | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 74981090a..7223529fb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -45,7 +45,12 @@ def queries_3D(): @pytest.fixture def heps(): """ - Perturbation/step size for finite difference evaluation of derivative/sensitivity + Perturbation/step size for finite difference evaluation of derivative/sensitivity. + + The value 1e-7 is arbitrary, but is a a compromise between: + - Being small enough to ensure the finite difference calculation being accurate + enough + - Being large enough to avoid round-off error in floating-point arithmetic """ return 1e-7 @@ -54,6 +59,8 @@ def heps(): def n_test_points(): """ Number of random testing points (in parametric domain) + + The number 10 is arbitrary and should ensure to have good test coverage """ return 10 diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 10f6be9ce..e2fccc026 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -153,6 +153,12 @@ def test_macro_sensitivities(tile_class, np_rng, heps, n_test_points): for k_patch, patch_deriv_implemented, patch_deriv_fd in zip( range(n_patches), deriv_evaluations, fd_sensitivity ): + # Verify derivative shapes + assert patch_deriv_implemented.shape[1] == dim, ( + "The derivative at " + + f"patch {k_patch} has the wrong dimensions." + ) + # Assert correctness of sensitivity assert np.allclose( -patch_deriv_implemented[:, jj_dim], patch_deriv_fd[:, jj_dim], @@ -162,4 +168,8 @@ def test_macro_sensitivities(tile_class, np_rng, heps, n_test_points): + "match the derivative obtained using Finite Differences at " + "the following evaluation points:\n" + str(eval_points) + + "\nImplemented derivative:\n" + + str(patch_deriv_implemented[:, jj_dim]) + + "\nFinite difference derivative:\n" + + str(patch_deriv_fd[:, jj_dim]) ) diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index e28bcc55e..5e37fd40a 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -277,4 +277,8 @@ def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): + "obtained using Finite Differences at the following evaluation " + "points:\n" + str(eval_points) + + "\nImplemented derivative:\n" + + str(deriv_orig) + + "\nFinite difference derivative:\n" + + str(deriv_fd) ) From d519adf38b0919e3800d32fa2427d2521ccd90f1 Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 17 Jan 2025 18:02:20 +0100 Subject: [PATCH 34/52] Add check of default tile parameters --- tests/test_microtiles.py | 62 +++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 5e37fd40a..4355812d3 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -73,13 +73,14 @@ def test_tile_class(tile_class): # Class must have function create_tile() assert hasattr( tile_class, "create_tile" - ), "Tile class must have create_tile()" + ), f"Tile class {tile_class.__name__} must have create_tile() method" # Tile must be able to take parameters and sensitivities as input create_parameters = getfullargspec(tile_class.create_tile).args for required_param in ["parameters", "parameter_sensitivities"]: - assert ( - required_param in create_parameters - ), f"create_tile() must have '{required_param}' as an input parameter" + assert required_param in create_parameters, ( + f"{tile_class.__name__}.create_tile() must have '{required_param}' as an " + "input parameter" + ) # Ensure closure can be handled correctly if "closure" in create_parameters: @@ -100,6 +101,37 @@ def test_tile_class(tile_class): eval(f"tile_class.{required_variable}"), var_type ), f"Variable {required_variable} needs to be of type {var_type}" + # Check default parameter value if there is one + if tile_class._parameters_shape != (): + # Assert that there is a default value + assert hasattr(tile_class, "_default_parameter_value"), ( + f'{tile_class.__name__} must have "_default_parameter_value" as a class ' + " attribute." + ) + # Check the default value's type + default_value = tile_class._default_parameter_value + if isinstance(default_value, np.ndarray): + # Check the dimensions + assert default_value.shape == tile_class._parameters_shape, ( + f"Default parameter values for tile {tile_class.__name__} has the wrong" + " dimensions" + ) + # Check if default values are within bounds + default_value = default_value.ravel() + elif not isinstance(default_value, float): + raise ValueError( + f"Default parameter value for tile {tile_class.__name__} must either be" + "a float or a numpy array" + ) + + # Check if default values are within bounds + parameter_bounds = np.asarray(tile_class._parameter_bounds) + lower_bounds = parameter_bounds[:, 0] + upper_bounds = parameter_bounds[:, 1] + assert np.all( + (default_value > lower_bounds) & (default_value < upper_bounds) + ), f"Default parameter value of tile {tile_class.__name__} is not within bounds" + @mark.parametrize("tile_class", all_tile_classes) def test_tile_bounds(tile_class): @@ -154,9 +186,10 @@ def test_tile_closure(tile_class): tile_patches, sensitivities = tile_creator.create_tile( closure=closure_direction ) - assert ( - sensitivities is None - ), "Ensure sensitivities for closure are None if no sensitivities are asked" + assert sensitivities is None, ( + f"Expected sensitivities to be None for closure {closure_direction} " + + f"when no sensitivities are requested, got {sensitivities}" + ) check_control_points(tile_patches) @@ -205,12 +238,15 @@ def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): if not tile_creator._sensitivities_implemented: return - # Choose random parameter(s) within bounds - parameter_bounds = np.array(tile_creator._parameter_bounds) - parameters = parameter_bounds[:, 0] + np_rng.random( - len(parameter_bounds) - ) * np.ptp(parameter_bounds, axis=1) - parameters = parameters.reshape(tile_creator._parameters_shape) + def generate_random_parameters(tile_creator, np_rng): + """Generate random parameters within bounds""" + parameter_bounds = np.array(tile_creator._parameter_bounds) + parameters = parameter_bounds[:, 0] + np_rng.random( + len(parameter_bounds) + ) * np.ptp(parameter_bounds, axis=1) + return parameters.reshape(tile_creator._parameters_shape) + + parameters = generate_random_parameters(tile_creator, np_rng) # Test no closure as well as ... closure_directions = [None] From c430acaa921e0e48e1e7c67d56579abe0e733bfa Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 17 Jan 2025 18:03:32 +0100 Subject: [PATCH 35/52] Change input to custom parameter check --- splinepy/microstructure/tiles/tile_base.py | 38 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index 77306dac3..076a42983 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -6,6 +6,28 @@ class TileBase(_SplinepyBase): """ Base class for tile objects + + Attributes + --------------- + _dim: int + Dimension in physical space + _para_dim: int + Dimension in parametric space + _evaluation_points: np.ndarray (2D) + Points in parametric space where tile parameters are evaluated. Each parameter + is attributed one evaluation point. This is used for the parametrization spline. + _n_info_per_eval_point: int + Number of tile parameters per evaluation point + _sensitivities_implemented: bool + Whether sensitivities w.r.t. tile parameters are implemented + _closure_directions: list + List of directions in which the closure has been implemented + _parameter_bounds: list> + List of bounds for the tile parameters + _parameters_shape: tuple + Shape of parameters array + _default_parameter_value: float/np.ndarray + Default values for all tile parameters """ _dim = None @@ -93,7 +115,7 @@ def para_dim(cls): return cls._raise_if_not_set_else_return("_para_dim") @property - def sensitivites_implemented(cls): + def sensitivities_implemented(cls): """Returns whether sensitivities are implemented for the microtile Parameters @@ -305,7 +327,7 @@ def _process_input(self, parameters, parameter_sensitivities): return parameters, n_derivatives, derivatives - def _check_custom_parameter(self, value, param_name, min_bound, max_bound): + def _check_custom_parameter(self, value, param_name, bounds): """Check if a custom tile parameter (e.g. contact length) is within bounds Parameters @@ -314,11 +336,15 @@ def _check_custom_parameter(self, value, param_name, min_bound, max_bound): Value of the custom parameter param_name: str Name of custom parameter - min_bound: float - Lower bound for parameter - max_bound: float - Upper bound for parameter + bounds: list + List of min. and max. bound """ + assert isinstance(bounds, list), "Bounds has to be a list" + assert ( + len(bounds) == 2 + ), "Bounds must consist of a min. and a max. value" + min_bound, max_bound = bounds + if not isinstance(value, float): raise ValueError(f"Invalid type for {param_name}") From 26b4335b7cf8f7906d86227e55ce29774d566431 Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 17 Jan 2025 18:05:17 +0100 Subject: [PATCH 36/52] Add bounds for custom tile parameters to class attributes --- splinepy/microstructure/tiles/armadillo.py | 6 ++++-- splinepy/microstructure/tiles/cross_2d.py | 12 ++++++++---- splinepy/microstructure/tiles/cross_3d.py | 10 +++++++--- splinepy/microstructure/tiles/cross_3d_linear.py | 10 +++++++--- splinepy/microstructure/tiles/double_lattice.py | 4 +++- splinepy/microstructure/tiles/hollow_octagon.py | 4 +++- .../microstructure/tiles/hollow_octagon_extrude.py | 4 +++- splinepy/microstructure/tiles/inverse_cross_3d.py | 10 +++++++--- splinepy/microstructure/tiles/snappy.py | 6 +++--- 9 files changed, 45 insertions(+), 21 deletions(-) diff --git a/splinepy/microstructure/tiles/armadillo.py b/splinepy/microstructure/tiles/armadillo.py index bbac762a9..8e4712d99 100644 --- a/splinepy/microstructure/tiles/armadillo.py +++ b/splinepy/microstructure/tiles/armadillo.py @@ -33,6 +33,8 @@ class Armadillo(_TileBase): _parameters_shape = (1, 1) _default_parameter_value = 0.2 + _CONTACT_LENGTH_BOUNDS = [0.0, 0.99] + def _closing_tile( self, parameters=None, @@ -71,7 +73,7 @@ def _closing_tile( raise ValueError("No closing direction given") self._check_custom_parameter( - contact_length, "contact length", 0.0, 0.99 + contact_length, "contact length", self._CONTACT_LENGTH_BOUNDS ) parameters, n_derivatives, derivatives = self._process_input( @@ -5043,7 +5045,7 @@ def create_tile( """ self._check_custom_parameter( - contact_length, "contact length", 0.0, 0.99 + contact_length, "contact length", self._CONTACT_LENGTH_BOUNDS ) parameters, n_derivatives, derivatives = self._process_input( diff --git a/splinepy/microstructure/tiles/cross_2d.py b/splinepy/microstructure/tiles/cross_2d.py index b919ff0ad..3267ce9bc 100644 --- a/splinepy/microstructure/tiles/cross_2d.py +++ b/splinepy/microstructure/tiles/cross_2d.py @@ -34,6 +34,10 @@ class Cross2D(_TileBase): _parameters_shape = (4, 1) _default_parameter_value = 0.2 + _BOUNDARY_WIDTH_BOUNDS = [0.0, 0.5] + _FILLING_HEIGHT_BOUNDS = [0.0, 1.0] + _CENTER_EXPANSION_BOUNDS = [0.5, 1.5] + def _closing_tile( self, parameters=None, @@ -79,10 +83,10 @@ def _closing_tile( ) self._check_custom_parameter( - boundary_width, "boundary width", 0.0, 0.5 + boundary_width, "boundary width", self._BOUNDARY_WIDTH_BOUNDS ) self._check_custom_parameter( - filling_height, "filling height", 0.0, 1.0 + filling_height, "filling height", self._FILLING_HEIGHT_BOUNDS ) splines = [] @@ -403,7 +407,7 @@ def create_tile( """ self._check_custom_parameter( - center_expansion, "center expansion", 0.5, 1.5 + center_expansion, "center expansion", self._CENTER_EXPANSION_BOUNDS ) parameters, n_derivatives, derivatives = self._process_input( @@ -412,7 +416,7 @@ def create_tile( ) max_radius = min(0.5, (0.5 / center_expansion)) - if not _np.all(parameters < max_radius): + if not (_np.all(parameters > 0) and _np.all(parameters < max_radius)): raise ValueError(f"Thickness out of range (0, {max_radius})") # Closure requested, pass to function diff --git a/splinepy/microstructure/tiles/cross_3d.py b/splinepy/microstructure/tiles/cross_3d.py index 5552d998e..0b9955c52 100644 --- a/splinepy/microstructure/tiles/cross_3d.py +++ b/splinepy/microstructure/tiles/cross_3d.py @@ -36,6 +36,10 @@ class Cross3D(_TileBase): _parameters_shape = (6, 1) _default_parameter_value = 0.2 + _BOUNDARY_WIDTH_BOUNDS = [0.0, 0.5] + _FILLING_HEIGHT_BOUNDS = [0.0, 1.0] + _CENTER_EXPANSION_BOUNDS = [0.5, 1.5] + def _closing_tile( self, parameters=None, @@ -81,10 +85,10 @@ def _closing_tile( ) self._check_custom_parameter( - boundary_width, "boundary width", 0.0, 0.5 + boundary_width, "boundary width", self._BOUNDARY_WIDTH_BOUNDS ) self._check_custom_parameter( - filling_height, "filling height", 0.0, 1.0 + filling_height, "filling height", self._FILLING_HEIGHT_BOUNDS ) splines = [] @@ -511,7 +515,7 @@ def create_tile( """ self._check_custom_parameter( - center_expansion, "center expansion", 0.5, 1.5 + center_expansion, "center expansion", self._CENTER_EXPANSION_BOUNDS ) parameters, n_derivatives, derivatives = self._process_input( diff --git a/splinepy/microstructure/tiles/cross_3d_linear.py b/splinepy/microstructure/tiles/cross_3d_linear.py index 103fa6372..b0aa71bee 100644 --- a/splinepy/microstructure/tiles/cross_3d_linear.py +++ b/splinepy/microstructure/tiles/cross_3d_linear.py @@ -36,6 +36,10 @@ class Cross3DLinear(_TileBase): _parameters_shape = (6, 1) _default_parameter_value = 0.2 + _BOUNDARY_WIDTH_BOUNDS = [0.0, 0.5] + _FILLING_HEIGHT_BOUNDS = [0.0, 1.0] + _CENTER_EXPANSION_BOUNDS = [0.5, 1.5] + def _closing_tile( self, parameters=None, @@ -81,10 +85,10 @@ def _closing_tile( ) self._check_custom_parameter( - boundary_width, "boundary width", 0.0, 0.5 + boundary_width, "boundary width", self._BOUNDARY_WIDTH_BOUNDS ) self._check_custom_parameter( - filling_height, "filling height", 0.0, 1.0 + filling_height, "filling height", self._FILLING_HEIGHT_BOUNDS ) splines = [] @@ -467,7 +471,7 @@ def create_tile( """ self._check_custom_parameter( - center_expansion, "center expansion", 0.5, 1.5 + center_expansion, "center expansion", self._CENTER_EXPANSION_BOUNDS ) parameters, n_derivatives, derivatives = self._process_input( diff --git a/splinepy/microstructure/tiles/double_lattice.py b/splinepy/microstructure/tiles/double_lattice.py index d1fb1438a..eda6cd5d8 100644 --- a/splinepy/microstructure/tiles/double_lattice.py +++ b/splinepy/microstructure/tiles/double_lattice.py @@ -25,6 +25,8 @@ class DoubleLattice(_TileBase): _parameters_shape = (1, 2) _default_parameter_value = 0.1 + _CONTACT_LENGTH_BOUNDS = [0.0, 1.0] + def create_tile( self, parameters=None, @@ -55,7 +57,7 @@ def create_tile( microtile_list : list(splines) """ self._check_custom_parameter( - contact_length, "contact length", 0.0, 1.0 + contact_length, "contact length", self._CONTACT_LENGTH_BOUNDS ) parameters, n_derivatives, derivatives = self._process_input( diff --git a/splinepy/microstructure/tiles/hollow_octagon.py b/splinepy/microstructure/tiles/hollow_octagon.py index c1e3271ec..c099e65c0 100644 --- a/splinepy/microstructure/tiles/hollow_octagon.py +++ b/splinepy/microstructure/tiles/hollow_octagon.py @@ -24,6 +24,8 @@ class HollowOctagon(_TileBase): _parameters_shape = (1, 1) _default_parameter_value = 0.2 + _CONTACT_LENGTH_BOUNDS = [0.0, 0.99] + def _closing_tile( self, parameters=None, @@ -433,7 +435,7 @@ def create_tile( derivatives: list> / None """ self._check_custom_parameter( - contact_length, "contact length", 0.0, 0.99 + contact_length, "contact length", self._CONTACT_LENGTH_BOUNDS ) parameters, n_derivatives, derivatives = self._process_input( diff --git a/splinepy/microstructure/tiles/hollow_octagon_extrude.py b/splinepy/microstructure/tiles/hollow_octagon_extrude.py index 6bcfd4313..4d63972ac 100644 --- a/splinepy/microstructure/tiles/hollow_octagon_extrude.py +++ b/splinepy/microstructure/tiles/hollow_octagon_extrude.py @@ -24,6 +24,8 @@ class HollowOctagonExtrude(_TileBase): _parameters_shape = (1, 1) _default_parameter_value = 0.2 + _CONTACT_LENGTH_BOUNDS = [0.0, 0.99] + def create_tile( self, parameters=None, @@ -57,7 +59,7 @@ def create_tile( """ self._check_custom_parameter( - contact_length, "contact length", 0.0, 0.99 + contact_length, "contact length", self._CONTACT_LENGTH_BOUNDS ) # Process input parameters, n_derivatives, derivatives = self._process_input( diff --git a/splinepy/microstructure/tiles/inverse_cross_3d.py b/splinepy/microstructure/tiles/inverse_cross_3d.py index 5a366ee11..43e5ed632 100644 --- a/splinepy/microstructure/tiles/inverse_cross_3d.py +++ b/splinepy/microstructure/tiles/inverse_cross_3d.py @@ -39,6 +39,10 @@ class InverseCross3D(_TileBase): _parameters_shape = (6, 1) _default_parameter_value = 0.21 + _BOUNDARY_WIDTH_BOUNDS = [0.0, 0.5] + _FILLING_HEIGHT_BOUNDS = [0.0, 1.0] + _CENTER_EXPANSION_BOUNDS = [0.5, 1.5] + def _closing_tile( self, parameters=None, @@ -81,10 +85,10 @@ def _closing_tile( ) self._check_custom_parameter( - boundary_width, "boundary width", 0.0, 0.5 + boundary_width, "boundary width", self._BOUNDARY_WIDTH_BOUNDS ) self._check_custom_parameter( - filling_height, "filling height", 0.0, 1.0 + filling_height, "filling height", self._FILLING_HEIGHT_BOUNDS ) splines = [] @@ -1051,7 +1055,7 @@ def create_tile( """ self._check_custom_parameter( - center_expansion, "center expansion", 0.5, 1.5 + center_expansion, "center expansion", self._CENTER_EXPANSION_BOUNDS ) # Check if all radii are in allowed range diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index d3202aa63..85801926a 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -28,6 +28,8 @@ class Snappy(_TileBase): _parameter_bounds = [] _parameters_shape = () + _CONTACT_LENGTH_BOUNDS = [0.0, 0.49] + def _closing_tile( self, parameters=None, @@ -69,8 +71,6 @@ def _closing_tile( raise ValueError("No closing direction given") # TODO: parameters are not implemented, therefore do not check params - if parameters is not None: - self.check_params(parameters) if parameter_sensitivities is not None: raise NotImplementedError( @@ -354,7 +354,7 @@ def create_tile( raise ValueError("Invalid parameter, must be > 0.") self._check_custom_parameter( - contact_length, "contact length", 0.0, 0.49 + contact_length, "contact length", self._CONTACT_LENGTH_BOUNDS ) # Check horizontal parameters From 77fd9d98dfe1f0fcd04fbfcb9a3d78ce27720ada Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 17 Jan 2025 18:06:13 +0100 Subject: [PATCH 37/52] Add comments according to coderabbitai --- tests/test_microstructure.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index e2fccc026..b109ababa 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -12,6 +12,9 @@ EPS = 1e-7 # TODO: the following tiles fail the closure test +# HollowOctagonExtrude has no closure +# InverseCross3D's closure is special: it does not fill the whole unit cube and does not +# fully cover the closing face CLOSURE_FAILS = [ms.tiles.HollowOctagonExtrude, ms.tiles.InverseCross3D] @@ -58,12 +61,14 @@ def max_identifier(points): face_min_area = sum([volume(patch) for patch in min_patches.patches]) face_max_area = sum([volume(patch) for patch in max_patches.patches]) - assert ( - face_min_area > 1.0 - EPS - ), f"The closure of the {closure_direction}_min surface is not complete" - assert ( - face_max_area > 1.0 - EPS - ), f"The closure of the {closure_direction}_max surface is not complete" + assert face_min_area > 1.0 - EPS, ( + f"The closure of the {closure_direction}_min surface is not complete. " + f"Expected area of 1, got {face_min_area}" + ) + assert face_max_area > 1.0 - EPS, ( + f"The closure of the {closure_direction}_max surface is not complete. " + f"Expected area of 1, got{face_max_area}" + ) # Skip tile if it doesn't support closure if tile_class._closure_directions is None: From 2a8c0836dc39c15986450b7da8c4a0c0f082f89c Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 20 Jan 2025 10:39:48 +0100 Subject: [PATCH 38/52] Add dynamical update of parameter bounds --- splinepy/microstructure/tiles/cross_2d.py | 18 +++++++++------ splinepy/microstructure/tiles/cross_3d.py | 22 +++++++++---------- .../microstructure/tiles/cross_3d_linear.py | 22 +++++++++---------- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/splinepy/microstructure/tiles/cross_2d.py b/splinepy/microstructure/tiles/cross_2d.py index 3267ce9bc..990db61f2 100644 --- a/splinepy/microstructure/tiles/cross_2d.py +++ b/splinepy/microstructure/tiles/cross_2d.py @@ -28,12 +28,18 @@ class Cross2D(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = True _closure_directions = ["x_min", "x_max", "y_min", "y_max"] - _parameter_bounds = [ - [0.0, 0.5] - ] * 4 # valid for default center_expansion=1.0 _parameters_shape = (4, 1) _default_parameter_value = 0.2 + # Default value of center_expansion + _center_expansion = 1.0 + + # Dynamical computation of parameter bounds depending on center expansion + @property + def _parameter_bounds(self): + max_radius = min(0.5, (0.5 / self._center_expansion)) + return [[0.0, max_radius]] * 4 + _BOUNDARY_WIDTH_BOUNDS = [0.0, 0.5] _FILLING_HEIGHT_BOUNDS = [0.0, 1.0] _CENTER_EXPANSION_BOUNDS = [0.5, 1.5] @@ -410,15 +416,13 @@ def create_tile( center_expansion, "center expansion", self._CENTER_EXPANSION_BOUNDS ) + self._center_expansion = center_expansion + parameters, n_derivatives, derivatives = self._process_input( parameters=parameters, parameter_sensitivities=parameter_sensitivities, ) - max_radius = min(0.5, (0.5 / center_expansion)) - if not (_np.all(parameters > 0) and _np.all(parameters < max_radius)): - raise ValueError(f"Thickness out of range (0, {max_radius})") - # Closure requested, pass to function if closure is not None: return self._closing_tile( diff --git a/splinepy/microstructure/tiles/cross_3d.py b/splinepy/microstructure/tiles/cross_3d.py index 0b9955c52..c0edd34ee 100644 --- a/splinepy/microstructure/tiles/cross_3d.py +++ b/splinepy/microstructure/tiles/cross_3d.py @@ -30,12 +30,18 @@ class Cross3D(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = True _closure_directions = ["z_min", "z_max"] - _parameter_bounds = [ - [0.0, 0.5] - ] * 6 # valid for default center_expansion=1.0 _parameters_shape = (6, 1) _default_parameter_value = 0.2 + # Default value of center_expansion + _center_expansion = 1.0 + + # Dynamical computation of parameter bounds depending on center expansion + @property + def _parameter_bounds(self): + max_radius = min(0.5, (0.5 / self._center_expansion)) + return [[0.0, max_radius]] * 6 + _BOUNDARY_WIDTH_BOUNDS = [0.0, 0.5] _FILLING_HEIGHT_BOUNDS = [0.0, 1.0] _CENTER_EXPANSION_BOUNDS = [0.5, 1.5] @@ -518,19 +524,13 @@ def create_tile( center_expansion, "center expansion", self._CENTER_EXPANSION_BOUNDS ) + self._center_expansion = center_expansion + parameters, n_derivatives, derivatives = self._process_input( parameters=parameters, parameter_sensitivities=parameter_sensitivities, ) - # Max radius, so there is no tanglement in the crosstile - max_radius = min(0.5, (0.5 / center_expansion)) - if _np.any(parameters > max_radius): - raise ValueError( - f"Radii must be in (0,{max_radius}) for " - f"center_expansion {center_expansion}" - ) - if closure is not None: if closure not in self._closure_directions: raise NotImplementedError( diff --git a/splinepy/microstructure/tiles/cross_3d_linear.py b/splinepy/microstructure/tiles/cross_3d_linear.py index b0aa71bee..c41697857 100644 --- a/splinepy/microstructure/tiles/cross_3d_linear.py +++ b/splinepy/microstructure/tiles/cross_3d_linear.py @@ -30,12 +30,18 @@ class Cross3DLinear(_TileBase): _n_info_per_eval_point = 1 _sensitivities_implemented = True _closure_directions = ["z_min", "z_max"] - _parameter_bounds = [ - [0.0, 0.5] - ] * 6 # valid for default center_expansion=1.0 _parameters_shape = (6, 1) _default_parameter_value = 0.2 + # Default value of center_expansion + _center_expansion = 1.0 + + # Dynamical computation of parameter bounds depending on center expansion + @property + def _parameter_bounds(self): + max_radius = min(0.5, (0.5 / self._center_expansion)) + return [[0.0, max_radius]] * 6 + _BOUNDARY_WIDTH_BOUNDS = [0.0, 0.5] _FILLING_HEIGHT_BOUNDS = [0.0, 1.0] _CENTER_EXPANSION_BOUNDS = [0.5, 1.5] @@ -474,19 +480,13 @@ def create_tile( center_expansion, "center expansion", self._CENTER_EXPANSION_BOUNDS ) + self._center_expansion = center_expansion + parameters, n_derivatives, derivatives = self._process_input( parameters=parameters, parameter_sensitivities=parameter_sensitivities, ) - # Max radius, so there is no tanglement in the crosstile - max_radius = min(0.5, (0.5 / center_expansion)) - if _np.any(parameters > max_radius): - raise ValueError( - f"Radii must be in (0,{max_radius}) for " - f"center_expansion {center_expansion}" - ) - if closure is not None: return self._closing_tile( parameters=parameters, From a6bbbd65896b154d35fc906848b4769e1a86edd3 Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 20 Jan 2025 13:54:48 +0100 Subject: [PATCH 39/52] Test tile class now works with instances so that _parameter_bounds can be either class attribute or instance property --- tests/test_microtiles.py | 52 ++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 4355812d3..97ec2cc6f 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -57,6 +57,10 @@ def test_tile_class(tile_class): tile_class: tile class in splinepy.microstructure.tiles Microtile """ + # Create instance of class + tile_instance = tile_class() + tile_name = tile_class.__name__ + required_class_variables = { "_para_dim": int, "_dim": int, @@ -68,69 +72,75 @@ def test_tile_class(tile_class): } # Get tile class' objects - members = [attr for attr in dir(tile_class) if not attr.startswith("__")] + members = [ + attr for attr in dir(tile_instance) if not attr.startswith("__") + ] # Class must have function create_tile() assert hasattr( - tile_class, "create_tile" - ), f"Tile class {tile_class.__name__} must have create_tile() method" + tile_instance, "create_tile" + ), f"Tile class {tile_name} must have create_tile() method" + # Tile must be able to take parameters and sensitivities as input - create_parameters = getfullargspec(tile_class.create_tile).args + create_parameters = getfullargspec(tile_instance.create_tile).args for required_param in ["parameters", "parameter_sensitivities"]: assert required_param in create_parameters, ( - f"{tile_class.__name__}.create_tile() must have '{required_param}' as an " + f"{tile_name}.create_tile() must have '{required_param}' as an " "input parameter" ) # Ensure closure can be handled correctly if "closure" in create_parameters: assert "_closure_directions" in members, ( - "Tile class has closure ability. The available closure directions " - + "are missing" + f"Tile class {tile_name} has closure ability. The available closure " + + "directions are missing" ) assert hasattr( - tile_class, "_closing_tile" - ), "Tile class has closure ability but no _closing_tile() function!" + tile_instance, "_closing_tile" + ), f"Tile class {tile_name} has closure ability but no _closing_tile() function" # Check if tile class has all required variables and they are the correct type for required_variable, var_type in required_class_variables.items(): assert ( required_variable in members - ), f"Tile class needs to have member variable '{required_variable}'" + ), f"Tile class {tile_name} needs to have member variable '{required_variable}'" assert isinstance( - eval(f"tile_class.{required_variable}"), var_type - ), f"Variable {required_variable} needs to be of type {var_type}" + eval(f"tile_instance.{required_variable}"), var_type + ), ( + f"Variable {required_variable} needs to be of type {var_type} and not" + f"{required_variable}" + ) # Check default parameter value if there is one - if tile_class._parameters_shape != (): + if tile_instance._parameters_shape != (): # Assert that there is a default value - assert hasattr(tile_class, "_default_parameter_value"), ( - f'{tile_class.__name__} must have "_default_parameter_value" as a class ' + assert hasattr(tile_instance, "_default_parameter_value"), ( + f'{tile_name} must have "_default_parameter_value" as a class ' " attribute." ) # Check the default value's type - default_value = tile_class._default_parameter_value + default_value = tile_instance._default_parameter_value if isinstance(default_value, np.ndarray): # Check the dimensions - assert default_value.shape == tile_class._parameters_shape, ( - f"Default parameter values for tile {tile_class.__name__} has the wrong" + assert default_value.shape == tile_instance._parameters_shape, ( + f"Default parameter values for tile {tile_name} has the wrong" " dimensions" ) # Check if default values are within bounds default_value = default_value.ravel() elif not isinstance(default_value, float): raise ValueError( - f"Default parameter value for tile {tile_class.__name__} must either be" + f"Default parameter value for tile {tile_name} must either be" "a float or a numpy array" ) # Check if default values are within bounds - parameter_bounds = np.asarray(tile_class._parameter_bounds) + parameter_bounds = np.asarray(tile_instance._parameter_bounds) lower_bounds = parameter_bounds[:, 0] upper_bounds = parameter_bounds[:, 1] assert np.all( (default_value > lower_bounds) & (default_value < upper_bounds) - ), f"Default parameter value of tile {tile_class.__name__} is not within bounds" + ), f"Default parameter value of tile {tile_name} is not within bounds" @mark.parametrize("tile_class", all_tile_classes) From a34c182f16b58c4370c6f4fddd34e36cc37c988a Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 20 Jan 2025 14:11:23 +0100 Subject: [PATCH 40/52] Define class properties as class attribute or instance attribute --- splinepy/microstructure/tiles/tile_base.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index 076a42983..e1b5753bf 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -129,7 +129,7 @@ def sensitivities_implemented(cls): return cls._raise_if_not_set_else_return("_sensitivities_implemented") @property - def closure_directions(self): + def closure_directions(cls): """Returns the available closure directions of the microtile Parameters @@ -140,11 +140,14 @@ def closure_directions(self): ------- directions: None/list """ - return self._closure_directions + return cls._closure_directions @property - def parameter_bounds(cls): - """Returns the bounds for the microtiles' parameters + def parameter_bounds(self): + """Returns the bounds for the microtiles' parameters. + + Depending on the tile, parameter bounds can change (e.g. Cross2D). Therefore, it + is instance-dependent and self instead of cls is used. Parameters ---------- @@ -154,7 +157,7 @@ def parameter_bounds(cls): ------- bounds: list> """ - return cls._raise_if_not_set_else_return("_parameter_bounds") + return self._raise_if_not_set_else_return("_parameter_bounds") @property def parameters_shape(cls): From e29f3fb5b5fd6009654c2c05f00e66e2a163b231 Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 20 Jan 2025 15:01:46 +0100 Subject: [PATCH 41/52] Accept integers as tile parameters as well --- splinepy/microstructure/tiles/tile_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index e1b5753bf..262274cc6 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -348,7 +348,7 @@ def _check_custom_parameter(self, value, param_name, bounds): ), "Bounds must consist of a min. and a max. value" min_bound, max_bound = bounds - if not isinstance(value, float): + if not isinstance(value, (int, float)): raise ValueError(f"Invalid type for {param_name}") if not ((value > min_bound) and (value < max_bound)): From 40e08d8b35a0fbc97973f61a7139652a3d4785dd Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 20 Jan 2025 15:03:33 +0100 Subject: [PATCH 42/52] Add pytest skip for unfinished/hard-to-test tiles and some coderabbitai suggestions --- tests/test_microstructure.py | 35 ++++++++++++++-------- tests/test_microtiles.py | 58 +++++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index b109ababa..9a0a0f0a7 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -1,11 +1,17 @@ import numpy as np -from pytest import mark +from pytest import mark, skip import splinepy.microstructure as ms from splinepy.helpme.create import box from splinepy.helpme.integrate import volume all_tile_classes = list(ms.tiles.everything().values()) +# Tile classes where closure should be tested +tile_classes_with_closure = [ + tile_class + for tile_class in all_tile_classes + if tile_class._closure_directions is not None +] TILING = [2, 2, 2] BOX_DIMENSIONS = [1, 1, 1] @@ -18,7 +24,7 @@ CLOSURE_FAILS = [ms.tiles.HollowOctagonExtrude, ms.tiles.InverseCross3D] -@mark.parametrize("tile_class", all_tile_classes) +@mark.parametrize("tile_class", tile_classes_with_closure) def test_closing_face(tile_class): """Check if closing face is working @@ -28,6 +34,19 @@ def test_closing_face(tile_class): Microtile """ + # Skip tile if it doesn't support closure + if tile_class._closure_directions is None: + skip( + f"Tile {tile_class.__name__} does not have a closure implementation. Skip" + ) + + # TODO: right now skip tiles which have faulty closures + if tile_class in CLOSURE_FAILS: + skip( + f"Known issue: skip closure test for {tile_class.__name__}, which may have " + "closure implementation" + ) + def check_if_closed(multipatch, closure_direction): """Helper function to see if multipatch has a closing surface @@ -67,17 +86,9 @@ def max_identifier(points): ) assert face_max_area > 1.0 - EPS, ( f"The closure of the {closure_direction}_max surface is not complete. " - f"Expected area of 1, got{face_max_area}" + f"Expected area of 1, instead got {face_max_area}" ) - # Skip tile if it doesn't support closure - if tile_class._closure_directions is None: - return - - # TODO: right now skip tiles which have faulty closures - if tile_class in CLOSURE_FAILS: - return - tile_creator = tile_class() generator = ms.microstructure.Microstructure( deformation_function=box(*BOX_DIMENSIONS[: tile_creator._dim]), @@ -108,7 +119,7 @@ def test_macro_sensitivities(tile_class, np_rng, heps, n_test_points): heps: float Perturbation size for finite difference evaluation. Defined in conftest.py n_test_points: int - Number of testing points int the parametric domain. Defined in conftest.py + Number of testing points in the parametric domain. Defined in conftest.py """ tile_creator = tile_class() diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 97ec2cc6f..4423783e7 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -1,7 +1,7 @@ from inspect import getfullargspec import numpy as np -from pytest import mark +from pytest import mark, skip import splinepy.microstructure as ms from splinepy.utils.data import cartesian_product as _cartesian_product @@ -9,6 +9,18 @@ EPS = 1e-8 all_tile_classes = list(ms.tiles.everything().values()) +# Tile classes where closure should be tested +tile_classes_with_closure = [ + tile_class + for tile_class in all_tile_classes + if tile_class._closure_directions is not None +] +# Tile classes where sensitivities should be tested +tile_classes_with_sensitivities = [ + tile_class + for tile_class in all_tile_classes + if tile_class._sensitivities_implemented +] # Skip certain tile classes for parameters testing skip_tiles = [ @@ -105,7 +117,7 @@ def test_tile_class(tile_class): required_variable in members ), f"Tile class {tile_name} needs to have member variable '{required_variable}'" assert isinstance( - eval(f"tile_instance.{required_variable}"), var_type + getattr(tile_instance, required_variable), var_type ), ( f"Variable {required_variable} needs to be of type {var_type} and not" f"{required_variable}" @@ -130,7 +142,7 @@ def test_tile_class(tile_class): default_value = default_value.ravel() elif not isinstance(default_value, float): raise ValueError( - f"Default parameter value for tile {tile_name} must either be" + f"Default parameter value for tile {tile_name} must either be " "a float or a numpy array" ) @@ -160,7 +172,10 @@ def test_tile_bounds(tile_class): # Skip certain classes for testing if tile_class in skip_tiles: - return + skip( + "Known issue: skip bound test for non-default parameter values for tile " + f"{tile_class.__name__}" + ) # Go through all extremes of parameters and ensure that also they create # tiles within unit square/cube @@ -177,7 +192,7 @@ def test_tile_bounds(tile_class): check_control_points(tile_patches) -@mark.parametrize("tile_class", all_tile_classes) +@mark.parametrize("tile_class", tile_classes_with_closure) def test_tile_closure(tile_class): """Check if closing tiles also lie in unit cube. @@ -186,10 +201,11 @@ def test_tile_closure(tile_class): tile_class: tile class in splinepy.microstructure.tiles Microtile """ + tile_name = tile_class.__name__ # Skip tile if if does not support closure if tile_class._closure_directions is None: - return + skip(f"Tile {tile_name} does not have a closure implementation. Skip") tile_creator = tile_class() # Go through all implemented closure directions for closure_direction in tile_creator._closure_directions: @@ -206,7 +222,10 @@ def test_tile_closure(tile_class): # Also check non-default parameters # Skip certain classes for testing if tile_class in skip_tiles: - return + skip( + "Known issue: skip closure test for non-default parameter for tile " + f"{tile_name}" + ) # Go through all extremes of parameters and ensure that also they create # tiles within unit square/cube @@ -226,7 +245,7 @@ def test_tile_closure(tile_class): check_control_points(tile_patches) -@mark.parametrize("tile_class", all_tile_classes) +@mark.parametrize("tile_class", tile_classes_with_sensitivities) def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): """Testing the correctness of the tile derivatives using Finite Differences. This includes every closure and no closure, every parameter and every patch @@ -246,7 +265,7 @@ def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): tile_creator = tile_class() # Skip test if tile class has no implemented sensitivities if not tile_creator._sensitivities_implemented: - return + skip(f"Tile {tile_class.__name__} has no sensitivities implemented") def generate_random_parameters(tile_creator, np_rng): """Generate random parameters within bounds""" @@ -315,16 +334,13 @@ def generate_random_parameters(tile_creator, np_rng): for i_patch, deriv_orig, deriv_fd in zip( range(n_patches), deriv_evaluations, fd_sensitivities ): - assert np.allclose(deriv_orig, deriv_fd), ( - "Implemented derivative calculation for tile class" - + f"{tile_class}, with closure {closure}, parameter " - + f"{i_parameter+1}/{n_info_per_eval_point} at patch " - + f"{i_patch+1}/{n_patches} does not match the derivative " - + "obtained using Finite Differences at the following evaluation " - + "points:\n" - + str(eval_points) - + "\nImplemented derivative:\n" - + str(deriv_orig) - + "\nFinite difference derivative:\n" - + str(deriv_fd) + message = ( + f"Implemented derivative calculation for tile class {tile_class} " + f"with closure {closure}, parameter {i_parameter+1}/" + f"{n_info_per_eval_point} at patch {i_patch+1}/{n_patches} does not" + f" match the derivative obtained using Finite Differences at the " + f"following evaluation points:\n {eval_points}\nImplemented " + f"derivative:\n{deriv_orig}\nFinite Difference derivative:\n" + f"{deriv_fd}" ) + assert np.allclose(deriv_orig, deriv_fd), message From 3f3263d8301ef1beccc0386ae512a427492f4fcd Mon Sep 17 00:00:00 2001 From: markriegler Date: Mon, 20 Jan 2025 15:12:32 +0100 Subject: [PATCH 43/52] Ignore parameters (unused in function) for pre-commit --- splinepy/microstructure/tiles/snappy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index 85801926a..7ae03c671 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -32,7 +32,7 @@ class Snappy(_TileBase): def _closing_tile( self, - parameters=None, + parameters=None, # noqa: ARG002 parameter_sensitivities=None, # TODO closure=None, contact_length=0.1, From 8cfa0ba294b5546662910c7f981bb89ee9a202dd Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 6 Feb 2025 13:21:09 +0100 Subject: [PATCH 44/52] Enhance error message for unsupported closure directions --- splinepy/microstructure/tiles/cross_3d.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/splinepy/microstructure/tiles/cross_3d.py b/splinepy/microstructure/tiles/cross_3d.py index c0edd34ee..95fe347b0 100644 --- a/splinepy/microstructure/tiles/cross_3d.py +++ b/splinepy/microstructure/tiles/cross_3d.py @@ -534,7 +534,8 @@ def create_tile( if closure is not None: if closure not in self._closure_directions: raise NotImplementedError( - f"Closure '{closure}' not implemented" + f"Closure '{closure}' not implemented. Supported closures are: " + + f"{self._closure_directions}" ) return self._closing_tile( parameters=parameters, From 29310bcdada1d4fe4710e1d2b29dc28123c2a785 Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 6 Feb 2025 13:24:16 +0100 Subject: [PATCH 45/52] Replace assert statements with proper exception handling --- splinepy/microstructure/tiles/tile_base.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index 262274cc6..cd32c59ca 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -342,10 +342,11 @@ def _check_custom_parameter(self, value, param_name, bounds): bounds: list List of min. and max. bound """ - assert isinstance(bounds, list), "Bounds has to be a list" - assert ( - len(bounds) == 2 - ), "Bounds must consist of a min. and a max. value" + + if not isinstance(bounds, list): + raise TypeError("bounds has to be a list") + if len(bounds) != 2: + raise ValueError("Bounds must consist of a min. and a max. value") min_bound, max_bound = bounds if not isinstance(value, (int, float)): From 6fe00cb1bd91a4f957db6333f6630f2c08ce2c13 Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 6 Feb 2025 15:09:27 +0100 Subject: [PATCH 46/52] Add tests to check if error is validly thrown when parameters are wrong --- tests/conftest.py | 8 +++++ tests/test_microtiles.py | 70 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 7223529fb..070af6278 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -65,6 +65,14 @@ def n_test_points(): return 10 +@pytest.fixture +def big_perturbation(): + """Value for perturbation of parameters value + + The number 0.1 is small enough to fit the range of most tile parameters""" + return 0.1 + + # initializing a spline should be a test itself, so provide `dict_spline` # this is "iga-book"'s fig 2.15. @pytest.fixture diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 4423783e7..27de3cc18 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -1,7 +1,7 @@ from inspect import getfullargspec import numpy as np -from pytest import mark, skip +from pytest import mark, raises, skip import splinepy.microstructure as ms from splinepy.utils.data import cartesian_product as _cartesian_product @@ -344,3 +344,71 @@ def generate_random_parameters(tile_creator, np_rng): f"{deriv_fd}" ) assert np.allclose(deriv_orig, deriv_fd), message + + +@mark.parametrize("tile_class", all_tile_classes) +def test_invalid_parameter_values(tile_class, big_perturbation): + """Testing whether the tile class correctly raises an error if invalid parameters + are given. Current tests include too low or too high parameter values and wrong + shapes of the parameter array. + + Parameters + ---------- + tile_class: tile class in splinepy.microstructure.tiles + Microtile class + """ + tile_creator = tile_class() + # For certain tiles skip tests + if len(tile_creator._parameter_bounds) == 0: + skip( + f"Skip check for invalid parameters for tile {tile_class.__name__} " + "since there are no parameter bounds implemented for this tile" + ) + + parameter_bounds = np.asarray(tile_creator._parameter_bounds) + + # Check if tile class correctly raises an error if parameter values are too low + parameters_too_low = ( + parameter_bounds[:, 0].reshape(tile_creator._parameters_shape) + - big_perturbation + ) + with raises(ValueError) as exc_info_low: + tile_creator.create_tile(parameters=parameters_too_low) + # Check if the exception message calls TileBase.check_params() + assert "must be within the following bounds: lower: " in str( + exc_info_low.value + ), ( + f"Tile class {tile_class.__name__} must call TileBase.check_params() and raise", + " a ValueError if parameters values are too low", + ) + + # Check the same if parameter values are too high + parameters_too_high = ( + parameter_bounds[:, 1].reshape(tile_creator._parameters_shape) + + big_perturbation + ) + with raises(ValueError) as exc_info_high: + tile_creator.create_tile(parameters=parameters_too_high) + # Check if the exception message calls TileBase.check_params() + assert "must be within the following bounds: lower: " in str( + exc_info_high.value + ), ( + f"Tile class {tile_class.__name__} must call TileBase.check_params() and raise", + " a ValueError if parameters values are too high", + ) + + # Test if error is correctly thrown if the parameter shape is incompatible + # Take parameters in the middle of the bounds and double the array size + parameters_middle = np.mean(parameter_bounds, axis=1).reshape( + tile_creator._parameters_shape + ) + parameters_middle = np.tile(parameters_middle, [2, 1]) + # Check if the error is correctly raised + with raises(TypeError) as exc_info_size: + tile_creator.create_tile(parameters=parameters_middle) + assert "Mismatch in parameter size, expected" in str( + exc_info_size.value + ), ( + f"Tile class {tile_class.__name__} must call TileBase.check_params() and raise", + " a TypeError if the given parameters have the wrong shape", + ) From b600d6eae731881d2ddcf8f168b673f3ca730332 Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 6 Feb 2025 15:26:53 +0100 Subject: [PATCH 47/52] Enhance error message clarity --- tests/test_microstructure.py | 17 ++++++++++------- tests/test_microtiles.py | 20 +++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/test_microstructure.py b/tests/test_microstructure.py index 9a0a0f0a7..4c3e62942 100644 --- a/tests/test_microstructure.py +++ b/tests/test_microstructure.py @@ -13,15 +13,17 @@ if tile_class._closure_directions is not None ] +# Fixed auxiliary variables specific to microstructure testing TILING = [2, 2, 2] BOX_DIMENSIONS = [1, 1, 1] EPS = 1e-7 -# TODO: the following tiles fail the closure test -# HollowOctagonExtrude has no closure -# InverseCross3D's closure is special: it does not fill the whole unit cube and does not -# fully cover the closing face -CLOSURE_FAILS = [ms.tiles.HollowOctagonExtrude, ms.tiles.InverseCross3D] +# TODO(#458): the following tiles fail the closure test +CLOSURE_FAILS = { + ms.tiles.HollowOctagonExtrude: "has no closure implemented", + ms.tiles.InverseCross3D: "closure is special: it does not fill the whole unit " + + "cube and does not fully cover the closing face", +} @mark.parametrize("tile_class", tile_classes_with_closure) @@ -42,9 +44,10 @@ def test_closing_face(tile_class): # TODO: right now skip tiles which have faulty closures if tile_class in CLOSURE_FAILS: + reason = CLOSURE_FAILS[tile_class] skip( - f"Known issue: skip closure test for {tile_class.__name__}, which may have " - "closure implementation" + f"Known issue: skip closure test for {tile_class.__name__}, " + f"reason: {reason}" ) def check_if_closed(multipatch, closure_direction): diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 27de3cc18..a27476abf 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -23,10 +23,10 @@ ] # Skip certain tile classes for parameters testing -skip_tiles = [ - ms.tiles.EllipsVoid, # Control points easily lie outside unitcube - ms.tiles.Snappy, # Has no "parameters" -] +skip_tiles = { + ms.tiles.EllipsVoid: "control points easily lie outside unitcube", + ms.tiles.Snappy: "has no 'parameters' implemented", +} def check_control_points(tile_patches): @@ -35,9 +35,11 @@ def check_control_points(tile_patches): # Go through all patches for tile_patch in tile_patches: cps = tile_patch.control_points - assert np.all( - (cps >= 0.0 - EPS) & (cps <= 1.0 + EPS) - ), "Control points of tile must lie inside the unit square/cube" + assert np.all((cps >= 0.0 - EPS) & (cps <= 1.0 + EPS)), ( + "Control points of tile must lie inside the unit square/cube. " + + "Found points outside bounds: " + f"{cps[~((cps >= 0.0 - EPS) & (cps <= 1.0 + EPS))]}" + ) def make_bounds_feasible(bounds): @@ -174,7 +176,7 @@ def test_tile_bounds(tile_class): if tile_class in skip_tiles: skip( "Known issue: skip bound test for non-default parameter values for tile " - f"{tile_class.__name__}" + f"{tile_class.__name__}. Reason: {skip_tiles[tile_class]}" ) # Go through all extremes of parameters and ensure that also they create @@ -224,7 +226,7 @@ def test_tile_closure(tile_class): if tile_class in skip_tiles: skip( "Known issue: skip closure test for non-default parameter for tile " - f"{tile_name}" + f"{tile_name}. Reason: {skip_tiles[tile_class]}" ) # Go through all extremes of parameters and ensure that also they create From 7ed7a5af5dd3e0130946b8ccce908ece248e989e Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 6 Feb 2025 16:19:37 +0100 Subject: [PATCH 48/52] Add fourth order accurate Finite Difference calculation of parameter sensitvities --- tests/conftest.py | 16 +++++++- tests/test_microtiles.py | 83 ++++++++++++++++++++++++++++++---------- 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 070af6278..94535072c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,12 +47,12 @@ def heps(): """ Perturbation/step size for finite difference evaluation of derivative/sensitivity. - The value 1e-7 is arbitrary, but is a a compromise between: + The value 1e-4 is arbitrary, but is a a compromise between: - Being small enough to ensure the finite difference calculation being accurate enough - Being large enough to avoid round-off error in floating-point arithmetic """ - return 1e-7 + return 1e-5 @pytest.fixture @@ -73,6 +73,18 @@ def big_perturbation(): return 0.1 +@pytest.fixture +def fd_derivative_stepsizes_and_weights(): + """Stepsizes and weights for the calculation of the derivative using finite + differences. Using fourth-order accurate centered scheme. + + Returns + ------- + stepsizes_and_weights, denominator: dict + """ + return {-2: 1 / 12, -1: -8 / 12, 1: 8 / 12, 2: -1 / 12} + + # initializing a spline should be a test itself, so provide `dict_spline` # this is "iga-book"'s fig 2.15. @pytest.fixture diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index a27476abf..14f839fcf 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -248,7 +248,13 @@ def test_tile_closure(tile_class): @mark.parametrize("tile_class", tile_classes_with_sensitivities) -def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): +def test_tile_derivatives( + tile_class, + np_rng, + heps, + n_test_points, + fd_derivative_stepsizes_and_weights, +): """Testing the correctness of the tile derivatives using Finite Differences. This includes every closure and no closure, every parameter and every patch by evaluating at random points and for random parameters. @@ -263,6 +269,8 @@ def test_tile_derivatives(tile_class, np_rng, heps, n_test_points): Perturbation size for finite difference evaluation. Defined in conftest.py n_test_points: int Number of testing points in the parametric domain. Defined in conftest.py + fd_derivative_stepsizes_and_weights: dict + Stepsizes and weights for finite difference scheme. Defined in conftest.py """ tile_creator = tile_class() # Skip test if tile class has no implemented sensitivities @@ -289,20 +297,63 @@ def generate_random_parameters(tile_creator, np_rng): n_eval_points = tile_creator._evaluation_points.shape[0] n_info_per_eval_point = tile_creator._n_info_per_eval_point + def derivative_finite_difference_evaluation( + tile_creator, parameters, i_parameter, closure, eval_points, n_patches + ): + """Compute the derivative using fourth-order accurate centered finite + differences + + Parameters + ------------ + tile_creator: instance of microtile + Microtile class + parameters: np.ndarray + Tile parameter values + i_parameter: int + Index of parameter, on which the FD derivative calculation should be + performed on + closure: None/str + Closure direction of tile + eval_points: np.ndarray + Evaluation points on where to evaluate the derivative on + n_patches: int + Number of patches of tile + """ + # Initialize array for FD evaluation + fd_sensitivities = np.zeros( + (n_patches, len(eval_points), tile_creator.dim) + ) + + # Go through the + for stepsize, weighting in fd_derivative_stepsizes_and_weights.items(): + # Perturb parameter with respective stepsize + parameters_perturbed = parameters.copy() + parameters_perturbed[:, i_parameter] += stepsize * heps + # Create patches with perturbed parameter value + splines_perturbed, _ = tile_creator.create_tile( + parameters=parameters_perturbed, closure=closure + ) + fd_sensitivities += np.array( + [ + weighting / heps * spl.evaluate(eval_points) + for spl in splines_perturbed + ] + ) + + return fd_sensitivities + # Test each closure direction for closure in closure_directions: # Evaluate tile with given parameter and closure configuration splines_orig, _ = tile_creator.create_tile( parameters=parameters, closure=closure ) + n_patches = len(splines_orig) # Set evaluation points as random spots in the parametric space eval_points = np_rng.random((n_test_points, splines_orig[0].para_dim)) - splines_orig_evaluations = [ - spl.evaluate(eval_points) for spl in splines_orig - ] # Go through all the parameters individually for i_parameter in range(n_info_per_eval_point): - # Get derivatives w.r.t. one parameter + # Get implemented derivatives w.r.t. one parameter parameter_sensitivities = np.zeros( (n_eval_points, n_info_per_eval_point, 1) ) @@ -316,23 +367,15 @@ def generate_random_parameters(tile_creator, np_rng): deriv.evaluate(eval_points) for deriv in derivatives[0] ] # Perform finite difference evaluation - parameters_perturbed = parameters.copy() - parameters_perturbed[:, i_parameter] += heps - splines_perturbed, _ = tile_creator.create_tile( - parameters=parameters_perturbed, closure=closure + fd_sensitivities = derivative_finite_difference_evaluation( + tile_creator, + parameters, + i_parameter, + closure, + eval_points, + n_patches, ) - spline_perturbed_evaluations = [ - spl.evaluate(eval_points) for spl in splines_perturbed - ] - # Evaluate finite difference gradient - fd_sensitivities = [ - (spl_pert - spl_orig) / heps - for spl_pert, spl_orig in zip( - spline_perturbed_evaluations, splines_orig_evaluations - ) - ] # Check every patch - n_patches = len(fd_sensitivities) for i_patch, deriv_orig, deriv_fd in zip( range(n_patches), deriv_evaluations, fd_sensitivities ): From 18b85898a9760681e85ae1c4cefd49db9d3cb2c9 Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 6 Feb 2025 16:44:06 +0100 Subject: [PATCH 49/52] Change some error types --- splinepy/microstructure/tiles/snappy.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index 7ae03c671..d46cd4da8 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -28,7 +28,7 @@ class Snappy(_TileBase): _parameter_bounds = [] _parameters_shape = () - _CONTACT_LENGTH_BOUNDS = [0.0, 0.49] + _CONTACT_LENGTH_BOUNDS = [0.0, 0.5] def _closing_tile( self, @@ -70,8 +70,6 @@ def _closing_tile( if closure is None: raise ValueError("No closing direction given") - # TODO: parameters are not implemented, therefore do not check params - if parameter_sensitivities is not None: raise NotImplementedError( "Derivatives are not implemented for this tile yet" @@ -295,7 +293,7 @@ def _closing_tile( _Bezier(degrees=[3, 1], control_points=spline_5) ) else: - raise ValueError( + raise NotImplementedError( "Closing tile is only implemented for y-enclosure" ) @@ -349,7 +347,7 @@ def create_tile( for param in [a, b, c, r, contact_length]: if not isinstance(param, float): - raise ValueError(f"Invalid Type, {param} is not float") + raise TypeError(f"Invalid Type, {param} is not float") if param < 0: raise ValueError("Invalid parameter, must be > 0.") From 5ecb75dc0132f1ce5cd0c3ad1d425ba11633ee3e Mon Sep 17 00:00:00 2001 From: markriegler Date: Thu, 6 Feb 2025 17:14:14 +0100 Subject: [PATCH 50/52] Add clarification of parameter bounds --- splinepy/microstructure/tiles/tile_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index cd32c59ca..c831b97d9 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -146,8 +146,8 @@ def closure_directions(cls): def parameter_bounds(self): """Returns the bounds for the microtiles' parameters. - Depending on the tile, parameter bounds can change (e.g. Cross2D). Therefore, it - is instance-dependent and self instead of cls is used. + Depending on the tile, parameter bounds can dynamically change (e.g. Cross2D). + Therefore, it is instance-dependent and self instead of cls is used. Parameters ---------- From 087d8d1bcc29088b4d206f81af8e665b8d97e803 Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 7 Feb 2025 12:21:33 +0100 Subject: [PATCH 51/52] Add some suggestions from coderabbit --- splinepy/microstructure/tiles/snappy.py | 6 ++++-- splinepy/microstructure/tiles/tile_base.py | 7 +++++-- tests/conftest.py | 3 +-- tests/test_microtiles.py | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/splinepy/microstructure/tiles/snappy.py b/splinepy/microstructure/tiles/snappy.py index d46cd4da8..24a910e0d 100644 --- a/splinepy/microstructure/tiles/snappy.py +++ b/splinepy/microstructure/tiles/snappy.py @@ -346,8 +346,10 @@ def create_tile( """ for param in [a, b, c, r, contact_length]: - if not isinstance(param, float): - raise TypeError(f"Invalid Type, {param} is not float") + if not isinstance(param, (int, float)): + raise TypeError( + f"Invalid Type, {param} is neither int nor float" + ) if param < 0: raise ValueError("Invalid parameter, must be > 0.") diff --git a/splinepy/microstructure/tiles/tile_base.py b/splinepy/microstructure/tiles/tile_base.py index c831b97d9..9678bdf30 100644 --- a/splinepy/microstructure/tiles/tile_base.py +++ b/splinepy/microstructure/tiles/tile_base.py @@ -224,9 +224,12 @@ def check_params(self, parameters): parameters.ravel() < upper_bounds ) if not _np.all(within_bounds): + out_of_bounds = parameters[ + ~within_bounds.reshape(parameters.shape) + ] raise ValueError( - f"The parameters {parameters} must be within the following bounds: " - + f"lower: {lower_bounds} and upper: {upper_bounds}" + f"The following parameters are out of bounds: {out_of_bounds}. ", + f"Expected bounds: lower: {lower_bounds} and upper: {upper_bounds}", ) return True diff --git a/tests/conftest.py b/tests/conftest.py index 94535072c..2d3c46e45 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,9 +47,8 @@ def heps(): """ Perturbation/step size for finite difference evaluation of derivative/sensitivity. - The value 1e-4 is arbitrary, but is a a compromise between: + The value 1e-5 is arbitrary, but is a a compromise between: - Being small enough to ensure the finite difference calculation being accurate - enough - Being large enough to avoid round-off error in floating-point arithmetic """ return 1e-5 diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 14f839fcf..126f58ecf 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -420,7 +420,7 @@ def test_invalid_parameter_values(tile_class, big_perturbation): with raises(ValueError) as exc_info_low: tile_creator.create_tile(parameters=parameters_too_low) # Check if the exception message calls TileBase.check_params() - assert "must be within the following bounds: lower: " in str( + assert "The following parameters are out of bounds: " in str( exc_info_low.value ), ( f"Tile class {tile_class.__name__} must call TileBase.check_params() and raise", @@ -435,7 +435,7 @@ def test_invalid_parameter_values(tile_class, big_perturbation): with raises(ValueError) as exc_info_high: tile_creator.create_tile(parameters=parameters_too_high) # Check if the exception message calls TileBase.check_params() - assert "must be within the following bounds: lower: " in str( + assert "The following parameters are out of bounds: " in str( exc_info_high.value ), ( f"Tile class {tile_class.__name__} must call TileBase.check_params() and raise", From 66f3b8a846876b478f2e0bdda378b753896d404c Mon Sep 17 00:00:00 2001 From: markriegler Date: Fri, 7 Feb 2025 13:55:07 +0100 Subject: [PATCH 52/52] Add more suggestions from coderabbit --- tests/conftest.py | 9 ++++++--- tests/test_microtiles.py | 13 +++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 2d3c46e45..3bb99cd62 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,7 +47,7 @@ def heps(): """ Perturbation/step size for finite difference evaluation of derivative/sensitivity. - The value 1e-5 is arbitrary, but is a a compromise between: + The value 1e-5 is arbitrary, but is a compromise between: - Being small enough to ensure the finite difference calculation being accurate - Being large enough to avoid round-off error in floating-point arithmetic """ @@ -59,7 +59,8 @@ def n_test_points(): """ Number of random testing points (in parametric domain) - The number 10 is arbitrary and should ensure to have good test coverage + The number 10 is arbitrary and should ensure to have good test coverage. Increasing + this number could yield more thorough tests at the cost of longer runtime. """ return 10 @@ -68,7 +69,9 @@ def n_test_points(): def big_perturbation(): """Value for perturbation of parameters value - The number 0.1 is small enough to fit the range of most tile parameters""" + The number 0.1 is chosen arbitrarily. This value is for testing out of bounds + parameter values. It is designed to add to the maximum or subtract from the + minimum bound to delibarately make the values out of the bounds.""" return 0.1 diff --git a/tests/test_microtiles.py b/tests/test_microtiles.py index 126f58ecf..48ae1e508 100644 --- a/tests/test_microtiles.py +++ b/tests/test_microtiles.py @@ -6,6 +6,7 @@ import splinepy.microstructure as ms from splinepy.utils.data import cartesian_product as _cartesian_product +# Tolerance value for checking control points EPS = 1e-8 all_tile_classes = list(ms.tiles.everything().values()) @@ -31,14 +32,14 @@ def check_control_points(tile_patches): """Helper function. Check if all of tile's control points all lie within unit - square/cube""" + square/cube. The tolerance is defined by EPS""" # Go through all patches for tile_patch in tile_patches: cps = tile_patch.control_points - assert np.all((cps >= 0.0 - EPS) & (cps <= 1.0 + EPS)), ( + valid_cp_indices = (cps >= 0.0 - EPS) & (cps <= 1.0 + EPS) + assert np.all(valid_cp_indices), ( "Control points of tile must lie inside the unit square/cube. " - + "Found points outside bounds: " - f"{cps[~((cps >= 0.0 - EPS) & (cps <= 1.0 + EPS))]}" + + f"Found points outside bounds: {cps[~(valid_cp_indices)]}" ) @@ -121,8 +122,8 @@ def test_tile_class(tile_class): assert isinstance( getattr(tile_instance, required_variable), var_type ), ( - f"Variable {required_variable} needs to be of type {var_type} and not" - f"{required_variable}" + f"Variable {required_variable} must be of type {var_type}, but found type " + f"{type(getattr(tile_instance, required_variable))}" ) # Check default parameter value if there is one