beamme.mesh_creation_functions.beam_helix
Functions to create beam meshes along helical paths.
1# The MIT License (MIT) 2# 3# Copyright (c) 2018-2026 BeamMe Authors 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in 13# all copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21# THE SOFTWARE. 22"""Functions to create beam meshes along helical paths.""" 23 24import warnings as _warnings 25 26import numpy as _np 27 28from beamme.core.mesh import Mesh as _Mesh 29from beamme.core.rotation import Rotation as _Rotation 30 31from .beam_line import create_beam_mesh_line as _create_beam_mesh_line 32 33 34def create_beam_mesh_helix( 35 mesh, 36 beam_class, 37 material, 38 axis_vector, 39 axis_point, 40 start_point, 41 *, 42 helix_angle=None, 43 height_helix=None, 44 turns=None, 45 warning_straight_line=True, 46 **kwargs, 47): 48 """Generate a helical segment starting at a given start point around a predefined 49 axis (defined by axis_vector and axis_point). The helical segment is defined by a 50 start_point and exactly two of the basic helical quantities [helix_angle, 51 height_helix, turns]. 52 53 Args 54 ---- 55 mesh: Mesh 56 Mesh that the helical segment will be added to. 57 beam_class: Beam 58 Class of beam that will be used for this line. 59 material: Material 60 Material for this segment. 61 axis_vector: _np.array, list 62 Vector for the orientation of the helical center axis. 63 axis_point: _np.array, list 64 Point lying on the helical center axis. Does not need to align with 65 bottom plane of helix. 66 start_point: _np.array, list 67 Start point of the helix. Defines the radius. 68 helix_angle: float 69 Angle of the helix (synonyms in literature: twist angle or pitch 70 angle). 71 height_helix: float 72 Height of helix. 73 turns: float 74 Number of turns. 75 warning_straight_line: bool 76 Warn if radius of helix is zero or helix angle is 90 degrees and 77 simple line is returned. 78 79 **kwargs (for all of them look into create_beam_mesh_function) 80 ---- 81 n_el: int 82 Number of equally spaced beam elements along the line. Defaults to 1. 83 Mutually exclusive with l_el. 84 l_el: float 85 Desired length of beam elements. Mutually exclusive with n_el. 86 Be aware, that this length might not be achieved, if the elements are 87 warped after they are created. 88 89 Return 90 ---- 91 return_set: GeometryName 92 Set with the 'start' and 'end' node of the line. Also a 'line' set 93 with all nodes of the line. 94 """ 95 if [helix_angle, height_helix, turns].count(None) != 1: 96 raise ValueError( 97 "Exactly two arguments of [helix_angle, height_helix, turns]" 98 " must be provided!" 99 ) 100 101 if helix_angle is not None and _np.isclose(_np.sin(helix_angle), 0.0): 102 raise ValueError( 103 "Helix angle of helix is 0 degrees! " 104 + "Change angle for feasible helix geometry!" 105 ) 106 107 if height_helix is not None and _np.isclose(height_helix, 0.0): 108 raise ValueError( 109 "Height of helix is 0! Change height for feasible helix geometry!" 110 ) 111 112 # determine radius of helix 113 axis_vector = _np.asarray(axis_vector) 114 axis_point = _np.asarray(axis_point) 115 start_point = _np.asarray(start_point) 116 117 axis_vector = axis_vector / _np.linalg.norm(axis_vector) 118 origin = axis_point + _np.dot( 119 _np.dot(start_point - axis_point, axis_vector), axis_vector 120 ) 121 start_point_origin_vec = start_point - origin 122 radius = _np.linalg.norm(start_point_origin_vec) 123 124 # create temporary mesh to not alter original mesh 125 mesh_temp = _Mesh() 126 127 # return line if radius of helix is 0, helix angle is pi/2 or turns is 0 128 if ( 129 _np.isclose(radius, 0) 130 or (helix_angle is not None and _np.isclose(_np.cos(helix_angle), 0.0)) 131 or (turns is not None and _np.isclose(turns, 0.0)) 132 ): 133 if height_helix is None: 134 raise ValueError( 135 "Radius of helix is 0, helix angle is 90 degrees or turns is 0! " 136 + "Fallback to simple line geometry but height cannot be " 137 + "determined based on helix angle and turns! Either switch one " 138 + "helix parameter to height of helix or change radius!" 139 ) 140 141 if warning_straight_line: 142 _warnings.warn( 143 "Radius of helix is 0, helix angle is 90 degrees or turns is 0! " 144 + "Simple line geometry is returned!" 145 ) 146 147 if helix_angle is not None and height_helix is not None: 148 end_point = start_point + height_helix * axis_vector * _np.sign( 149 _np.sin(helix_angle) 150 ) 151 elif height_helix is not None and turns is not None: 152 end_point = start_point + height_helix * axis_vector 153 154 line_sets = _create_beam_mesh_line( 155 mesh_temp, 156 beam_class, 157 material, 158 start_point=start_point, 159 end_point=end_point, 160 **kwargs, 161 ) 162 163 # add line to mesh 164 mesh.add_mesh(mesh_temp) 165 166 return line_sets 167 168 # generate simple helix 169 if helix_angle and height_helix: 170 end_point = _np.array( 171 [ 172 radius, 173 _np.sign(_np.sin(helix_angle)) * height_helix / _np.tan(helix_angle), 174 _np.sign(_np.sin(helix_angle)) * height_helix, 175 ] 176 ) 177 elif helix_angle and turns: 178 end_point = _np.array( 179 [ 180 radius, 181 _np.sign(_np.cos(helix_angle)) * 2 * _np.pi * radius * turns, 182 _np.sign(_np.cos(helix_angle)) 183 * 2 184 * _np.pi 185 * radius 186 * _np.abs(turns) 187 * _np.tan(helix_angle), 188 ] 189 ) 190 elif height_helix and turns: 191 end_point = _np.array( 192 [ 193 radius, 194 2 * _np.pi * radius * turns, 195 height_helix, 196 ] 197 ) 198 199 helix_sets = _create_beam_mesh_line( 200 mesh_temp, 201 beam_class, 202 material, 203 start_point=[radius, 0, 0], 204 end_point=end_point, 205 **kwargs, 206 ) 207 208 mesh_temp.wrap_around_cylinder() 209 210 # rotate and translate simple helix to align with necessary axis and starting point 211 mesh_temp.rotate( 212 _Rotation.from_basis(start_point_origin_vec, axis_vector) 213 * _Rotation([1, 0, 0], -_np.pi * 0.5) 214 ) 215 mesh_temp.translate(-mesh_temp.nodes[0].coordinates + start_point) 216 217 # add helix to mesh 218 mesh.add_mesh(mesh_temp) 219 220 return helix_sets
35def create_beam_mesh_helix( 36 mesh, 37 beam_class, 38 material, 39 axis_vector, 40 axis_point, 41 start_point, 42 *, 43 helix_angle=None, 44 height_helix=None, 45 turns=None, 46 warning_straight_line=True, 47 **kwargs, 48): 49 """Generate a helical segment starting at a given start point around a predefined 50 axis (defined by axis_vector and axis_point). The helical segment is defined by a 51 start_point and exactly two of the basic helical quantities [helix_angle, 52 height_helix, turns]. 53 54 Args 55 ---- 56 mesh: Mesh 57 Mesh that the helical segment will be added to. 58 beam_class: Beam 59 Class of beam that will be used for this line. 60 material: Material 61 Material for this segment. 62 axis_vector: _np.array, list 63 Vector for the orientation of the helical center axis. 64 axis_point: _np.array, list 65 Point lying on the helical center axis. Does not need to align with 66 bottom plane of helix. 67 start_point: _np.array, list 68 Start point of the helix. Defines the radius. 69 helix_angle: float 70 Angle of the helix (synonyms in literature: twist angle or pitch 71 angle). 72 height_helix: float 73 Height of helix. 74 turns: float 75 Number of turns. 76 warning_straight_line: bool 77 Warn if radius of helix is zero or helix angle is 90 degrees and 78 simple line is returned. 79 80 **kwargs (for all of them look into create_beam_mesh_function) 81 ---- 82 n_el: int 83 Number of equally spaced beam elements along the line. Defaults to 1. 84 Mutually exclusive with l_el. 85 l_el: float 86 Desired length of beam elements. Mutually exclusive with n_el. 87 Be aware, that this length might not be achieved, if the elements are 88 warped after they are created. 89 90 Return 91 ---- 92 return_set: GeometryName 93 Set with the 'start' and 'end' node of the line. Also a 'line' set 94 with all nodes of the line. 95 """ 96 if [helix_angle, height_helix, turns].count(None) != 1: 97 raise ValueError( 98 "Exactly two arguments of [helix_angle, height_helix, turns]" 99 " must be provided!" 100 ) 101 102 if helix_angle is not None and _np.isclose(_np.sin(helix_angle), 0.0): 103 raise ValueError( 104 "Helix angle of helix is 0 degrees! " 105 + "Change angle for feasible helix geometry!" 106 ) 107 108 if height_helix is not None and _np.isclose(height_helix, 0.0): 109 raise ValueError( 110 "Height of helix is 0! Change height for feasible helix geometry!" 111 ) 112 113 # determine radius of helix 114 axis_vector = _np.asarray(axis_vector) 115 axis_point = _np.asarray(axis_point) 116 start_point = _np.asarray(start_point) 117 118 axis_vector = axis_vector / _np.linalg.norm(axis_vector) 119 origin = axis_point + _np.dot( 120 _np.dot(start_point - axis_point, axis_vector), axis_vector 121 ) 122 start_point_origin_vec = start_point - origin 123 radius = _np.linalg.norm(start_point_origin_vec) 124 125 # create temporary mesh to not alter original mesh 126 mesh_temp = _Mesh() 127 128 # return line if radius of helix is 0, helix angle is pi/2 or turns is 0 129 if ( 130 _np.isclose(radius, 0) 131 or (helix_angle is not None and _np.isclose(_np.cos(helix_angle), 0.0)) 132 or (turns is not None and _np.isclose(turns, 0.0)) 133 ): 134 if height_helix is None: 135 raise ValueError( 136 "Radius of helix is 0, helix angle is 90 degrees or turns is 0! " 137 + "Fallback to simple line geometry but height cannot be " 138 + "determined based on helix angle and turns! Either switch one " 139 + "helix parameter to height of helix or change radius!" 140 ) 141 142 if warning_straight_line: 143 _warnings.warn( 144 "Radius of helix is 0, helix angle is 90 degrees or turns is 0! " 145 + "Simple line geometry is returned!" 146 ) 147 148 if helix_angle is not None and height_helix is not None: 149 end_point = start_point + height_helix * axis_vector * _np.sign( 150 _np.sin(helix_angle) 151 ) 152 elif height_helix is not None and turns is not None: 153 end_point = start_point + height_helix * axis_vector 154 155 line_sets = _create_beam_mesh_line( 156 mesh_temp, 157 beam_class, 158 material, 159 start_point=start_point, 160 end_point=end_point, 161 **kwargs, 162 ) 163 164 # add line to mesh 165 mesh.add_mesh(mesh_temp) 166 167 return line_sets 168 169 # generate simple helix 170 if helix_angle and height_helix: 171 end_point = _np.array( 172 [ 173 radius, 174 _np.sign(_np.sin(helix_angle)) * height_helix / _np.tan(helix_angle), 175 _np.sign(_np.sin(helix_angle)) * height_helix, 176 ] 177 ) 178 elif helix_angle and turns: 179 end_point = _np.array( 180 [ 181 radius, 182 _np.sign(_np.cos(helix_angle)) * 2 * _np.pi * radius * turns, 183 _np.sign(_np.cos(helix_angle)) 184 * 2 185 * _np.pi 186 * radius 187 * _np.abs(turns) 188 * _np.tan(helix_angle), 189 ] 190 ) 191 elif height_helix and turns: 192 end_point = _np.array( 193 [ 194 radius, 195 2 * _np.pi * radius * turns, 196 height_helix, 197 ] 198 ) 199 200 helix_sets = _create_beam_mesh_line( 201 mesh_temp, 202 beam_class, 203 material, 204 start_point=[radius, 0, 0], 205 end_point=end_point, 206 **kwargs, 207 ) 208 209 mesh_temp.wrap_around_cylinder() 210 211 # rotate and translate simple helix to align with necessary axis and starting point 212 mesh_temp.rotate( 213 _Rotation.from_basis(start_point_origin_vec, axis_vector) 214 * _Rotation([1, 0, 0], -_np.pi * 0.5) 215 ) 216 mesh_temp.translate(-mesh_temp.nodes[0].coordinates + start_point) 217 218 # add helix to mesh 219 mesh.add_mesh(mesh_temp) 220 221 return helix_sets
Generate a helical segment starting at a given start point around a predefined axis (defined by axis_vector and axis_point). The helical segment is defined by a start_point and exactly two of the basic helical quantities [helix_angle, height_helix, turns].
Args
mesh: Mesh Mesh that the helical segment will be added to. beam_class: Beam Class of beam that will be used for this line. material: Material Material for this segment. axis_vector: _np.array, list Vector for the orientation of the helical center axis. axis_point: _np.array, list Point lying on the helical center axis. Does not need to align with bottom plane of helix. start_point: _np.array, list Start point of the helix. Defines the radius. helix_angle: float Angle of the helix (synonyms in literature: twist angle or pitch angle). height_helix: float Height of helix. turns: float Number of turns. warning_straight_line: bool Warn if radius of helix is zero or helix angle is 90 degrees and simple line is returned.
**kwargs (for all of them look into create_beam_mesh_function)
n_el: int Number of equally spaced beam elements along the line. Defaults to 1. Mutually exclusive with l_el. l_el: float Desired length of beam elements. Mutually exclusive with n_el. Be aware, that this length might not be achieved, if the elements are warped after they are created.
Return
return_set: GeometryName Set with the 'start' and 'end' node of the line. Also a 'line' set with all nodes of the line.