Skip to content

Commit faa6d35

Browse files
Merge pull request #299 from isteinbrecher/fix-bug-in-arc-length
Fix bug in create arc function
2 parents 4f2accc + 802b74c commit faa6d35

File tree

4 files changed

+111
-16
lines changed

4 files changed

+111
-16
lines changed

src/meshpy/mesh_creation_functions/beam_basic_geometry.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ def create_beam_mesh_arc_segment_via_axis(
179179
axis_point,
180180
start_point,
181181
angle,
182-
*,
183-
start_node=None,
184182
**kwargs,
185183
):
186184
"""Generate a circular segment of beam elements.
@@ -241,14 +239,13 @@ def create_beam_mesh_arc_segment_via_axis(
241239
center = start_point - distance
242240

243241
# Get the rotation at the start
244-
if start_node is None:
245-
tangent = _np.cross(axis, distance)
246-
tangent /= _np.linalg.norm(tangent)
247-
start_rotation = _Rotation.from_rotation_matrix(
248-
_np.transpose(_np.array([tangent, -distance / radius, axis]))
249-
)
250-
else:
251-
start_rotation = _get_single_node(start_node).rotation
242+
# No need to check the start node here, as eventual rotation offsets in
243+
# tangential direction will be covered by the create beam functionality.
244+
tangent = _np.cross(axis, distance)
245+
tangent /= _np.linalg.norm(tangent)
246+
start_rotation = _Rotation.from_rotation_matrix(
247+
_np.transpose(_np.array([tangent, -distance / radius, axis]))
248+
)
252249

253250
def get_beam_geometry(alpha, beta):
254251
"""Return a function for the position and rotation along the beam
@@ -273,7 +270,6 @@ def beam_function(xi):
273270
function_generator=get_beam_geometry,
274271
interval=[0.0, angle],
275272
interval_length=angle * radius,
276-
start_node=start_node,
277273
**kwargs,
278274
)
279275

src/meshpy/mesh_creation_functions/beam_generic.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ def check_given_node(node):
194194
if node not in mesh.nodes:
195195
raise ValueError("The given node is not in the current mesh")
196196

197-
def get_relative_twist(rotation_node, rotation_function):
197+
def get_relative_twist(rotation_node, rotation_function, name):
198198
"""Check if the rotation at a node and the one returned by the function
199199
match.
200200
@@ -210,7 +210,7 @@ def get_relative_twist(rotation_node, rotation_function):
210210
elif not _mpy.allow_beam_rotation:
211211
# The settings do not allow for a rotation of the beam
212212
raise ValueError(
213-
"Given nodal rotation does not match with given rotation function!"
213+
f"Given rotation of the {name} node does not match with given rotation function!"
214214
)
215215
else:
216216
# Evaluate the relative rotation
@@ -221,7 +221,7 @@ def get_relative_twist(rotation_node, rotation_function):
221221
return rotation_function.inv() * rotation_node
222222
else:
223223
raise ValueError(
224-
"The tangent of the start node does not match with the given function!"
224+
f"The tangent of the {name} node does not match with the given function!"
225225
)
226226

227227
# Position and rotation at the start and end of the interval
@@ -235,14 +235,16 @@ def get_relative_twist(rotation_node, rotation_function):
235235
nodes = [start_node]
236236
check_given_node(start_node)
237237
_, start_rotation = function_over_whole_interval(-1.0)
238-
relative_twist_start = get_relative_twist(start_node.rotation, start_rotation)
238+
relative_twist_start = get_relative_twist(
239+
start_node.rotation, start_rotation, "start"
240+
)
239241

240242
# If an end node is given, check what behavior is wanted.
241243
if end_node is not None:
242244
end_node = _get_single_node(end_node)
243245
check_given_node(end_node)
244246
_, end_rotation = function_over_whole_interval(1.0)
245-
relative_twist_end = get_relative_twist(end_node.rotation, end_rotation)
247+
relative_twist_end = get_relative_twist(end_node.rotation, end_rotation, "end")
246248

247249
# Check if a relative twist has to be applied
248250
if relative_twist_start is not None and relative_twist_end is not None:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// -----------------------------------------------------------------------------
2+
// This input file was created with MeshPy.
3+
// Copyright (c) 2018-2025
4+
// Ivo Steinbrecher
5+
// Institute for Mathematics and Computer-Based Simulation
6+
// Universitaet der Bundeswehr Muenchen
7+
// https://www.unibw.de/imcs-en
8+
// -----------------------------------------------------------------------------
9+
-----------------------------------------------------------------------MATERIALS
10+
MAT 1 MAT_BeamReissnerElastHyper YOUNG -1.0 POISSONRATIO 0.0 DENS 0.0 CROSSAREA 3.141592653589793 SHEARCORR 1 MOMINPOL 1.5707963267948966 MOMIN2 0.7853981633974483 MOMIN3 0.7853981633974483
11+
---------------------------------------------------------------------NODE COORDS
12+
NODE 1 COORD 0 0 0
13+
NODE 2 COORD 1.68294196962 0.919395388264 0
14+
NODE 3 COORD 0.331792265387 0.0277135368741 0
15+
NODE 4 COORD 0.654389393592 0.110086107371 0
16+
NODE 5 COORD 0.958851077208 0.244834876219 0
17+
NODE 6 COORD 1.23673960614 0.428225478446 0
18+
NODE 7 COORD 1.48035370639 0.655175511834 0
19+
--------------------------------------------------------------STRUCTURE ELEMENTS
20+
1 BEAM3R HERM2LINE3 1 4 3 MAT 1 TRIADS 0 0 0 0 0 0.333333333333 0 0 0.166666666667
21+
2 BEAM3R HERM2LINE3 4 6 5 MAT 1 TRIADS 0 0 0.333333333333 0 0 0.666666666667 0 0 0.5
22+
3 BEAM3R HERM2LINE3 6 2 7 MAT 1 TRIADS 0 0 0.666666666667 0 0 1 0 0 0.833333333333

tests/test_mesh_creation_functions.py

+75
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,81 @@ def test_mesh_creation_functions_arc_segment_via_axis(
155155
assert_results_equal(get_corresponding_reference_file_path(), input_file)
156156

157157

158+
def test_mesh_creation_functions_arc_segment_start_end_node(
159+
assert_results_equal, get_corresponding_reference_file_path
160+
):
161+
"""Check that if start end nodes with non-matching positions or tangents
162+
are provided we get an error."""
163+
164+
angle = 1.0
165+
radius = 2.0
166+
start_node_pos = [0, 0, 0]
167+
start_node_rot = Rotation()
168+
end_node_pos = radius * np.array([np.sin(angle), 1.0 - np.cos(angle), 0])
169+
end_node_rot = Rotation([0, 0, 1], angle)
170+
171+
def create_beam(*, start_node=None, end_node=None):
172+
"""This is the base function we use to generate the beam in this test
173+
case."""
174+
input_file = InputFile()
175+
mat = MaterialReissner()
176+
if start_node is not None:
177+
input_file.add(start_node)
178+
if end_node is not None:
179+
input_file.add(end_node)
180+
create_beam_mesh_arc_segment_via_axis(
181+
input_file,
182+
Beam3rHerm2Line3,
183+
mat,
184+
[0, 0, 1],
185+
[0, radius, 0],
186+
[0, 0, 0],
187+
angle,
188+
n_el=3,
189+
start_node=start_node,
190+
end_node=end_node,
191+
)
192+
return input_file
193+
194+
# This should work as expected, as all the values match.
195+
start_node = NodeCosserat(start_node_pos, start_node_rot)
196+
end_node = NodeCosserat(end_node_pos, end_node_rot)
197+
input_file = create_beam(start_node=start_node, end_node=end_node)
198+
assert_results_equal(get_corresponding_reference_file_path(), input_file)
199+
200+
# Create with start node where the position does not match.
201+
with pytest.raises(
202+
ValueError,
203+
match="start_node position does not match with function!",
204+
):
205+
start_node = NodeCosserat([0, 1, 0], start_node_rot)
206+
create_beam(start_node=start_node)
207+
208+
# Create with start node where the rotation does not match.
209+
with pytest.raises(
210+
ValueError,
211+
match="The tangent of the start node does not match with the given function!",
212+
):
213+
start_node = NodeCosserat(start_node_pos, Rotation([1, 2, 3], np.pi / 3))
214+
create_beam(start_node=start_node)
215+
216+
# Create with end node where the position does not match.
217+
with pytest.raises(
218+
ValueError,
219+
match="end_node position does not match with function!",
220+
):
221+
end_node = NodeCosserat([0, 0, 0], end_node_rot)
222+
create_beam(end_node=end_node)
223+
224+
# Create with end node where the rotation does not match.
225+
with pytest.raises(
226+
ValueError,
227+
match="The tangent of the end node does not match with the given function!",
228+
):
229+
end_node = NodeCosserat(end_node_pos, Rotation([1, 2, 3], np.pi / 3))
230+
create_beam(end_node=end_node)
231+
232+
158233
def test_mesh_creation_functions_arc_segment_via_rotation(
159234
assert_results_equal, get_corresponding_reference_file_path
160235
):

0 commit comments

Comments
 (0)