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
« 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."""
24import numpy as _np
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)
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.
38 The circular segment is defined via a rotation, specifying the "initial"
39 triad of the beam at the beginning of the arc.
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
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.
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.
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 """
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 )
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.
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.
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.
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.
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 """
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 )
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)
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
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 )
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)
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 )
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.
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.
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.
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 """
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!")
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])
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
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 )