Coverage for src/beamme/mesh_creation_functions/beam_arc.py: 95%
38 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-08-31 13:55 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-08-31 13:55 +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 """
80 # Convert the input to the one for create_beam_mesh_arc_segment_via_axis
81 axis = axis_rotation * [0, 0, 1]
82 start_point = center + radius * (axis_rotation * [0, -1, 0])
83 return create_beam_mesh_arc_segment_via_axis(
84 mesh, beam_class, material, axis, center, start_point, angle, **kwargs
85 )
88def create_beam_mesh_arc_segment_via_axis(
89 mesh,
90 beam_class,
91 material,
92 axis,
93 axis_point,
94 start_point,
95 angle,
96 **kwargs,
97):
98 """Generate a circular segment of beam elements.
100 The arc is defined via a rotation axis, a point on the rotation axis a starting
101 point, as well as the angle of the arc segment.
103 Args
104 ----
105 mesh: Mesh
106 Mesh that the arc segment will be added to.
107 beam_class: Beam
108 Class of beam that will be used for this line.
109 material: Material
110 Material for this segment.
111 axis: _np.array, list
112 Rotation axis of the arc.
113 axis_point: _np.array, list
114 Point lying on the rotation axis. Does not have to be the center of the arc.
115 start_point: _np.array, list
116 Start point of the arc.
117 angle: float
118 The central angle of this segment in radians.
120 **kwargs (for all of them look into create_beam_mesh_function)
121 ----
122 n_el: int
123 Number of equally spaced beam elements along the line. Defaults to 1.
124 Mutually exclusive with l_el.
125 l_el: float
126 Desired length of beam elements. Mutually exclusive with n_el.
127 Be aware, that this length might not be achieved, if the elements are
128 warped after they are created.
130 Return
131 ----
132 return_set: GeometryName
133 Set with the 'start' and 'end' node of the line. Also a 'line' set
134 with all nodes of the line.
135 """
136 # The angle can not be negative with the current implementation.
137 if angle <= 0.0:
138 raise ValueError(
139 "The angle for a beam arc segment has to be a positive number!"
140 )
142 # Shortest distance from the given point to the axis of rotation gives
143 # the "center" of the arc
144 axis = _np.asarray(axis)
145 axis_point = _np.asarray(axis_point)
146 start_point = _np.asarray(start_point)
148 axis = axis / _np.linalg.norm(axis)
149 diff = start_point - axis_point
150 distance = diff - _np.dot(_np.dot(diff, axis), axis)
151 radius = _np.linalg.norm(distance)
152 center = start_point - distance
154 # Get the rotation at the start
155 # No need to check the start node here, as eventual rotation offsets in
156 # tangential direction will be covered by the create beam functionality.
157 tangent = _np.cross(axis, distance)
158 tangent /= _np.linalg.norm(tangent)
159 start_rotation = _Rotation.from_rotation_matrix(
160 _np.transpose(_np.array([tangent, -distance / radius, axis]))
161 )
163 def beam_function(phi: float) -> tuple[_np.ndarray, _Rotation, float | None]:
164 """Return a point on the beams axis for a given interval coordinate."""
165 arc_rotation = _Rotation(axis, phi)
166 rot = arc_rotation * start_rotation
167 pos = center + arc_rotation * distance
168 return (pos, rot, phi * radius)
170 # Create the beam in the mesh
171 return _create_beam_mesh_generic(
172 mesh,
173 beam_class=beam_class,
174 material=material,
175 beam_function=beam_function,
176 interval=[0.0, angle],
177 interval_length=angle * radius,
178 **kwargs,
179 )
182def create_beam_mesh_arc_segment_2d(
183 mesh, beam_class, material, center, radius, phi_start, phi_end, **kwargs
184):
185 """Generate a circular segment of beam elements in the x-y plane.
187 Args
188 ----
189 mesh: Mesh
190 Mesh that the arc segment will be added to.
191 beam_class: Beam
192 Class of beam that will be used for this line.
193 material: Material
194 Material for this segment.
195 center: _np.array, list
196 Center of the arc. If the z component is not 0, an error will be
197 thrown.
198 radius: float
199 The radius of the segment.
200 phi_start, phi_end: float
201 The start and end angles of the arc w.r.t the x-axis. If the start
202 angle is larger than the end angle the beam faces in counter-clockwise
203 direction, and if the start angle is smaller than the end angle, the
204 beam faces in clockwise direction.
206 **kwargs (for all of them look into create_beam_mesh_function)
207 ----
208 n_el: int
209 Number of equally spaced beam elements along the line. Defaults to 1.
210 Mutually exclusive with l_el.
211 l_el: float
212 Desired length of beam elements. Mutually exclusive with n_el.
213 Be aware, that this length might not be achieved, if the elements are
214 warped after they are created.
216 Return
217 ----
218 return_set: GeometryName
219 Set with the 'start' and 'end' node of the line. Also a 'line' set
220 with all nodes of the line.
221 """
222 # The center point has to be on the x-y plane.
223 if _np.abs(center[2]) > _bme.eps_pos:
224 raise ValueError("The z-value of center has to be 0!")
226 # Check if the beam is in clockwise or counter clockwise direction.
227 angle = phi_end - phi_start
228 axis = _np.array([0, 0, 1])
229 start_point = center + radius * (_Rotation(axis, phi_start) * [1, 0, 0])
231 counter_clockwise = _np.sign(angle) == 1
232 if not counter_clockwise:
233 # If the beam is not in counter clockwise direction, we have to flip
234 # the rotation axis.
235 axis = -1.0 * axis
237 return create_beam_mesh_arc_segment_via_axis(
238 mesh,
239 beam_class,
240 material,
241 axis,
242 center,
243 start_point,
244 _np.abs(angle),
245 **kwargs,
246 )