beamme.mesh_creation_functions.beam_helix
Functions to create beam meshes along helical paths.
1# The MIT License (MIT) 2# 3# Copyright (c) 2018-2025 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 49 predefined axis (defined by axis_vector and axis_point). The helical 50 segment is defined by a start_point and exactly two of the basic helical 51 quantities [helix_angle, 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 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
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 50 predefined axis (defined by axis_vector and axis_point). The helical 51 segment is defined by a start_point and exactly two of the basic helical 52 quantities [helix_angle, 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 97 if [helix_angle, height_helix, turns].count(None) != 1: 98 raise ValueError( 99 "Exactly two arguments of [helix_angle, height_helix, turns]" 100 " must be provided!" 101 ) 102 103 if helix_angle is not None and _np.isclose(_np.sin(helix_angle), 0.0): 104 raise ValueError( 105 "Helix angle of helix is 0 degrees! " 106 + "Change angle for feasible helix geometry!" 107 ) 108 109 if height_helix is not None and _np.isclose(height_helix, 0.0): 110 raise ValueError( 111 "Height of helix is 0! Change height for feasible helix geometry!" 112 ) 113 114 # determine radius of helix 115 axis_vector = _np.asarray(axis_vector) 116 axis_point = _np.asarray(axis_point) 117 start_point = _np.asarray(start_point) 118 119 axis_vector = axis_vector / _np.linalg.norm(axis_vector) 120 origin = axis_point + _np.dot( 121 _np.dot(start_point - axis_point, axis_vector), axis_vector 122 ) 123 start_point_origin_vec = start_point - origin 124 radius = _np.linalg.norm(start_point_origin_vec) 125 126 # create temporary mesh to not alter original mesh 127 mesh_temp = _Mesh() 128 129 # return line if radius of helix is 0, helix angle is pi/2 or turns is 0 130 if ( 131 _np.isclose(radius, 0) 132 or (helix_angle is not None and _np.isclose(_np.cos(helix_angle), 0.0)) 133 or (turns is not None and _np.isclose(turns, 0.0)) 134 ): 135 if height_helix is None: 136 raise ValueError( 137 "Radius of helix is 0, helix angle is 90 degrees or turns is 0! " 138 + "Fallback to simple line geometry but height cannot be " 139 + "determined based on helix angle and turns! Either switch one " 140 + "helix parameter to height of helix or change radius!" 141 ) 142 143 if warning_straight_line: 144 _warnings.warn( 145 "Radius of helix is 0, helix angle is 90 degrees or turns is 0! " 146 + "Simple line geometry is returned!" 147 ) 148 149 if helix_angle is not None and height_helix is not None: 150 end_point = start_point + height_helix * axis_vector * _np.sign( 151 _np.sin(helix_angle) 152 ) 153 elif height_helix is not None and turns is not None: 154 end_point = start_point + height_helix * axis_vector 155 156 line_sets = _create_beam_mesh_line( 157 mesh_temp, 158 beam_class, 159 material, 160 start_point=start_point, 161 end_point=end_point, 162 **kwargs, 163 ) 164 165 # add line to mesh 166 mesh.add_mesh(mesh_temp) 167 168 return line_sets 169 170 # generate simple helix 171 if helix_angle and height_helix: 172 end_point = _np.array( 173 [ 174 radius, 175 _np.sign(_np.sin(helix_angle)) * height_helix / _np.tan(helix_angle), 176 _np.sign(_np.sin(helix_angle)) * height_helix, 177 ] 178 ) 179 elif helix_angle and turns: 180 end_point = _np.array( 181 [ 182 radius, 183 _np.sign(_np.cos(helix_angle)) * 2 * _np.pi * radius * turns, 184 _np.sign(_np.cos(helix_angle)) 185 * 2 186 * _np.pi 187 * radius 188 * _np.abs(turns) 189 * _np.tan(helix_angle), 190 ] 191 ) 192 elif height_helix and turns: 193 end_point = _np.array( 194 [ 195 radius, 196 2 * _np.pi * radius * turns, 197 height_helix, 198 ] 199 ) 200 201 helix_sets = _create_beam_mesh_line( 202 mesh_temp, 203 beam_class, 204 material, 205 start_point=[radius, 0, 0], 206 end_point=end_point, 207 **kwargs, 208 ) 209 210 mesh_temp.wrap_around_cylinder() 211 212 # rotate and translate simple helix to align with necessary axis and starting point 213 mesh_temp.rotate( 214 _Rotation.from_basis(start_point_origin_vec, axis_vector) 215 * _Rotation([1, 0, 0], -_np.pi * 0.5) 216 ) 217 mesh_temp.translate(-mesh_temp.nodes[0].coordinates + start_point) 218 219 # add helix to mesh 220 mesh.add_mesh(mesh_temp) 221 222 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.