@@ -51,10 +51,12 @@ def create_beam_mesh_function(
51
51
n_el : _Optional [int ] = None ,
52
52
l_el : _Optional [float ] = None ,
53
53
interval_length : _Optional [float ] = None ,
54
+ set_nodal_arc_length : bool = False ,
55
+ nodal_arc_length_offset : _Optional [float ] = None ,
54
56
node_positions_of_elements : _Optional [_List [float ]] = None ,
55
57
start_node : _Optional [_Union [_NodeCosserat , _GeometrySet ]] = None ,
56
58
end_node : _Optional [_Union [_NodeCosserat , _GeometrySet ]] = None ,
57
- close_beam : _Optional [ bool ] = False ,
59
+ close_beam : bool = False ,
58
60
vtk_cell_data : _Optional [_Dict [str , _Tuple ]] = None ,
59
61
) -> _GeometryName :
60
62
"""Generic beam creation function.
@@ -77,6 +79,10 @@ def create_beam_mesh_function(
77
79
point_b (both within the interval) and return a function(xi) that
78
80
calculates the position and rotation along the beam, where
79
81
point_a -> xi = -1 and point_b -> xi = 1.
82
+
83
+ Usually, the Jacobian of the returned position field should be a unit
84
+ vector. Otherwise, the nodes may be spaced in an undesired way. All
85
+ standard mesh creation functions in MeshPy fulfill this property.
80
86
interval:
81
87
Start and end values for interval that will be used to create the
82
88
beam.
@@ -90,6 +96,15 @@ def create_beam_mesh_function(
90
96
created.
91
97
interval_length:
92
98
Total length of the interval. Is required when the option l_el is given.
99
+ set_nodal_arc_length:
100
+ Flag if the arc length along the beam filament is set in the created
101
+ nodes. It is ensured that the arc length is consistent with possible
102
+ given start/end nodes.
103
+ nodal_arc_length_offset:
104
+ Offset of the stored nodal arc length w.r.t. to the one generated by
105
+ the function. Defaults to 0, the arc length set in the start node, or
106
+ the arc length in the end node minus total length (such that the arc
107
+ length at the end node matches).
93
108
node_positions_of_elements:
94
109
A list of normalized positions (within [0,1] and in ascending order)
95
110
that define the boundaries of beam elements along the created curve.
@@ -138,6 +153,17 @@ def create_beam_mesh_function(
138
153
'The arguments "close_beam" and "end_node" are mutually exclusive'
139
154
)
140
155
156
+ if set_nodal_arc_length :
157
+ if close_beam :
158
+ raise ValueError (
159
+ "The flags 'set_nodal_arc_length' and 'close_beam' are mutually exclusive."
160
+ )
161
+ elif nodal_arc_length_offset is not None :
162
+ raise ValueError (
163
+ 'Providing the argument "nodal_arc_length_offset" without setting '
164
+ '"set_nodal_arc_length" to True does not make sense.'
165
+ )
166
+
141
167
# Cases where we have equally spaced elements
142
168
if n_el is not None or l_el is not None :
143
169
if l_el is not None :
@@ -150,13 +176,10 @@ def create_beam_mesh_function(
150
176
elif n_el is None :
151
177
raise ValueError ("n_el should not be None at this point" )
152
178
153
- interval_node_positions_of_elements = [
154
- interval [0 ] + i_node * (interval [1 ] - interval [0 ]) / n_el
155
- for i_node in range (n_el + 1 )
156
- ]
179
+ node_positions_of_elements = [i_node / n_el for i_node in range (n_el + 1 )]
157
180
# A list for the element node positions was provided
158
181
elif node_positions_of_elements is not None :
159
- # Check that the given positions are in ascending order and start with 1 and end with 0
182
+ # Check that the given positions are in ascending order and start with 0 and end with 1
160
183
for index , value , name in zip ([0 , - 1 ], [0 , 1 ], ["First" , "Last" ]):
161
184
if not _np .isclose (
162
185
value ,
@@ -174,9 +197,11 @@ def create_beam_mesh_function(
174
197
raise ValueError (
175
198
f"The given node_positions_of_elements must be in ascending order. Got { node_positions_of_elements } "
176
199
)
177
- interval_node_positions_of_elements = interval [0 ] + (
178
- interval [1 ] - interval [0 ]
179
- ) * _np .asarray (node_positions_of_elements )
200
+
201
+ # Get the scale the node positions to the interval coordinates
202
+ interval_node_positions_of_elements = interval [0 ] + (
203
+ interval [1 ] - interval [0 ]
204
+ ) * _np .asarray (node_positions_of_elements )
180
205
181
206
# We need to make sure we have the number of elements for the case a given end node
182
207
n_el = len (interval_node_positions_of_elements ) - 1
@@ -234,7 +259,7 @@ def get_relative_twist(rotation_node, rotation_function, name):
234
259
start_node = _get_single_node (start_node )
235
260
nodes = [start_node ]
236
261
check_given_node (start_node )
237
- _ , start_rotation = function_over_whole_interval (- 1.0 )
262
+ _ , start_rotation , _ = function_over_whole_interval (- 1.0 )
238
263
relative_twist_start = get_relative_twist (
239
264
start_node .rotation , start_rotation , "start"
240
265
)
@@ -243,9 +268,24 @@ def get_relative_twist(rotation_node, rotation_function, name):
243
268
if end_node is not None :
244
269
end_node = _get_single_node (end_node )
245
270
check_given_node (end_node )
246
- _ , end_rotation = function_over_whole_interval (1.0 )
271
+ _ , end_rotation , _ = function_over_whole_interval (1.0 )
247
272
relative_twist_end = get_relative_twist (end_node .rotation , end_rotation , "end" )
248
273
274
+ # Get the start value for the arc length functionality
275
+ if set_nodal_arc_length :
276
+ if nodal_arc_length_offset is not None :
277
+ # Let's use the given value, if it does not match with possible given
278
+ # start or end nodes, the check in the create beam function will detect
279
+ # that.
280
+ pass
281
+ elif start_node is not None and start_node .arc_length is not None :
282
+ nodal_arc_length_offset = start_node .arc_length
283
+ elif end_node is not None and end_node .arc_length is not None :
284
+ nodal_arc_length_offset = end_node .arc_length - interval_length
285
+ else :
286
+ # Default value
287
+ nodal_arc_length_offset = 0.0
288
+
249
289
# Check if a relative twist has to be applied
250
290
if relative_twist_start is not None and relative_twist_end is not None :
251
291
if relative_twist_start == relative_twist_end :
@@ -262,7 +302,7 @@ def get_relative_twist(rotation_node, rotation_function, name):
262
302
relative_twist = None
263
303
264
304
# Create the beams.
265
- for i_el in range (len ( interval_node_positions_of_elements ) - 1 ):
305
+ for i_el in range (n_el ):
266
306
# If the beam is closed with itself, set the end node to be the
267
307
# first node of the beam. This is done when the second element is
268
308
# created, as the first node already exists here.
@@ -295,6 +335,8 @@ def get_relative_twist(rotation_node, rotation_function, name):
295
335
start_node = first_node ,
296
336
end_node = last_node ,
297
337
relative_twist = relative_twist ,
338
+ set_nodal_arc_length = set_nodal_arc_length ,
339
+ nodal_arc_length_offset = nodal_arc_length_offset ,
298
340
)
299
341
)
300
342
0 commit comments