Coverage for src / beamme / mesh_creation_functions / beam_arc.py: 95%

38 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-02-23 08:08 +0000

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 arcs.""" 

23 

24import numpy as _np 

25 

26from beamme.core.conf import bme as _bme 

27from beamme.core.rotation import Rotation as _Rotation 

28from beamme.mesh_creation_functions.beam_generic import ( 

29 create_beam_mesh_generic as _create_beam_mesh_generic, 

30) 

31 

32 

33def create_beam_mesh_arc_segment_via_rotation( 

34 mesh, beam_class, material, center, axis_rotation, radius, angle, **kwargs 

35): 

36 """Generate a circular segment of beam elements. 

37 

38 The circular segment is defined via a rotation, specifying the "initial" 

39 triad of the beam at the beginning of the arc. 

40 

41 This function exists for compatibility reasons with older BeamMe implementations. 

42 The user is encouraged to use the newer implementation create_beam_mesh_arc_segment_via_axis 

43 

44 Args 

45 ---- 

46 mesh: Mesh 

47 Mesh that the arc segment will be added to. 

48 beam_class: Beam 

49 Class of beam that will be used for this line. 

50 material: Material 

51 Material for this segment. 

52 center: _np.array, list 

53 Center of the arc. 

54 axis_rotation: Rotation 

55 This rotation defines the spatial orientation of the arc. 

56 The 3rd base vector of this rotation is the rotation axis of the arc 

57 segment. The segment starts in the direction of the 1st basis vector 

58 and the starting point is along the 2nd basis vector. 

59 radius: float 

60 The radius of the segment. 

61 angle: float 

62 The central angle of this segment in radians. 

63 

64 **kwargs (for all of them look into create_beam_mesh_function) 

65 ---- 

66 n_el: int 

67 Number of equally spaced beam elements along the line. Defaults to 1. 

68 Mutually exclusive with l_el. 

69 l_el: float 

70 Desired length of beam elements. Mutually exclusive with n_el. 

71 Be aware, that this length might not be achieved, if the elements are 

72 warped after they are created. 

73 

74 Return 

75 ---- 

76 return_set: GeometryName 

77 Set with the 'start' and 'end' node of the line. Also a 'line' set 

78 with all nodes of the line. 

79 """ 

80 

81 # Convert the input to the one for create_beam_mesh_arc_segment_via_axis 

82 axis = axis_rotation * [0, 0, 1] 

83 start_point = center + radius * (axis_rotation * [0, -1, 0]) 

84 return create_beam_mesh_arc_segment_via_axis( 

85 mesh, beam_class, material, axis, center, start_point, angle, **kwargs 

86 ) 

87 

88 

89def create_beam_mesh_arc_segment_via_axis( 

90 mesh, 

91 beam_class, 

92 material, 

93 axis, 

94 axis_point, 

95 start_point, 

96 angle, 

97 **kwargs, 

98): 

99 """Generate a circular segment of beam elements. 

100 

101 The arc is defined via a rotation axis, a point on the rotation axis a starting 

102 point, as well as the angle of the arc segment. 

103 

104 Args 

105 ---- 

106 mesh: Mesh 

107 Mesh that the arc segment will be added to. 

108 beam_class: Beam 

109 Class of beam that will be used for this line. 

110 material: Material 

111 Material for this segment. 

112 axis: _np.array, list 

113 Rotation axis of the arc. 

114 axis_point: _np.array, list 

115 Point lying on the rotation axis. Does not have to be the center of the arc. 

116 start_point: _np.array, list 

117 Start point of the arc. 

118 angle: float 

119 The central angle of this segment in radians. 

120 

121 **kwargs (for all of them look into create_beam_mesh_function) 

122 ---- 

123 n_el: int 

124 Number of equally spaced beam elements along the line. Defaults to 1. 

125 Mutually exclusive with l_el. 

126 l_el: float 

127 Desired length of beam elements. Mutually exclusive with n_el. 

128 Be aware, that this length might not be achieved, if the elements are 

129 warped after they are created. 

130 

131 Return 

132 ---- 

133 return_set: GeometryName 

134 Set with the 'start' and 'end' node of the line. Also a 'line' set 

135 with all nodes of the line. 

136 """ 

137 

138 # The angle can not be negative with the current implementation. 

139 if angle <= 0.0: 

140 raise ValueError( 

141 "The angle for a beam arc segment has to be a positive number!" 

142 ) 

143 

144 # Shortest distance from the given point to the axis of rotation gives 

145 # the "center" of the arc 

146 axis = _np.asarray(axis) 

147 axis_point = _np.asarray(axis_point) 

148 start_point = _np.asarray(start_point) 

149 

150 axis = axis / _np.linalg.norm(axis) 

151 diff = start_point - axis_point 

152 distance = diff - _np.dot(_np.dot(diff, axis), axis) 

153 radius = _np.linalg.norm(distance) 

154 center = start_point - distance 

155 

156 # Get the rotation at the start 

157 # No need to check the start node here, as eventual rotation offsets in 

158 # tangential direction will be covered by the create beam functionality. 

159 tangent = _np.cross(axis, distance) 

160 tangent /= _np.linalg.norm(tangent) 

161 start_rotation = _Rotation.from_rotation_matrix( 

162 _np.transpose(_np.array([tangent, -distance / radius, axis])) 

163 ) 

164 

165 def beam_function(phi: float) -> tuple[_np.ndarray, _Rotation, float | None]: 

166 """Return a point on the beams axis for a given interval coordinate.""" 

167 arc_rotation = _Rotation(axis, phi) 

168 rot = arc_rotation * start_rotation 

169 pos = center + arc_rotation * distance 

170 return (pos, rot, phi * radius) 

171 

172 # Create the beam in the mesh 

173 return _create_beam_mesh_generic( 

174 mesh, 

175 beam_class=beam_class, 

176 material=material, 

177 beam_function=beam_function, 

178 interval=[0.0, angle], 

179 interval_length=angle * radius, 

180 **kwargs, 

181 ) 

182 

183 

184def create_beam_mesh_arc_segment_2d( 

185 mesh, beam_class, material, center, radius, phi_start, phi_end, **kwargs 

186): 

187 """Generate a circular segment of beam elements in the x-y plane. 

188 

189 Args 

190 ---- 

191 mesh: Mesh 

192 Mesh that the arc segment will be added to. 

193 beam_class: Beam 

194 Class of beam that will be used for this line. 

195 material: Material 

196 Material for this segment. 

197 center: _np.array, list 

198 Center of the arc. If the z component is not 0, an error will be 

199 thrown. 

200 radius: float 

201 The radius of the segment. 

202 phi_start, phi_end: float 

203 The start and end angles of the arc w.r.t the x-axis. If the start 

204 angle is larger than the end angle the beam faces in counter-clockwise 

205 direction, and if the start angle is smaller than the end angle, the 

206 beam faces in clockwise direction. 

207 

208 **kwargs (for all of them look into create_beam_mesh_function) 

209 ---- 

210 n_el: int 

211 Number of equally spaced beam elements along the line. Defaults to 1. 

212 Mutually exclusive with l_el. 

213 l_el: float 

214 Desired length of beam elements. Mutually exclusive with n_el. 

215 Be aware, that this length might not be achieved, if the elements are 

216 warped after they are created. 

217 

218 Return 

219 ---- 

220 return_set: GeometryName 

221 Set with the 'start' and 'end' node of the line. Also a 'line' set 

222 with all nodes of the line. 

223 """ 

224 

225 # The center point has to be on the x-y plane. 

226 if _np.abs(center[2]) > _bme.eps_pos: 

227 raise ValueError("The z-value of center has to be 0!") 

228 

229 # Check if the beam is in clockwise or counter clockwise direction. 

230 angle = phi_end - phi_start 

231 axis = _np.array([0, 0, 1]) 

232 start_point = center + radius * (_Rotation(axis, phi_start) * [1, 0, 0]) 

233 

234 counter_clockwise = _np.sign(angle) == 1 

235 if not counter_clockwise: 

236 # If the beam is not in counter clockwise direction, we have to flip 

237 # the rotation axis. 

238 axis = -1.0 * axis 

239 

240 return create_beam_mesh_arc_segment_via_axis( 

241 mesh, 

242 beam_class, 

243 material, 

244 axis, 

245 center, 

246 start_point, 

247 _np.abs(angle), 

248 **kwargs, 

249 )