Coverage for src / beamme / four_c / element_beam.py: 89%
73 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-21 12:57 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-21 12:57 +0000
1# The MIT License (MIT)
2#
3# Copyright (c) 2018-2025 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"""This file implements beam elements for 4C."""
24import warnings as _warnings
26import numpy as _np
28from beamme.core.conf import bme as _bme
29from beamme.core.element_beam import Beam as _Beam
30from beamme.core.element_beam import generate_beam_class as _generate_beam_class
31from beamme.four_c.four_c_types import (
32 BeamKirchhoffConstraintType as _BeamKirchhoffConstraintType,
33)
34from beamme.four_c.four_c_types import (
35 BeamKirchhoffParametrizationType as _BeamKirchhoffParametrizationType,
36)
37from beamme.four_c.four_c_types import BeamType as _BeamType
38from beamme.four_c.input_file_mappings import (
39 INPUT_FILE_MAPPINGS as _INPUT_FILE_MAPPINGS,
40)
41from beamme.four_c.material import MaterialEulerBernoulli as _MaterialEulerBernoulli
42from beamme.four_c.material import MaterialKirchhoff as _MaterialKirchhoff
43from beamme.four_c.material import MaterialReissner as _MaterialReissner
44from beamme.four_c.material import (
45 MaterialReissnerElastoplastic as _MaterialReissnerElastoplastic,
46)
49def dump_four_c_beam_to_list(self) -> dict:
50 """Return the dictionary representing this beam element in 4C.
52 Args:
53 self: The beam element to be dumped.
54 """
56 # Check the material.
57 self._check_material()
59 # Gather the element data for the input file.
60 element_data = type(self).four_c_element_data | self.data
61 element_data["MAT"] = self.material
62 if type(self).four_c_triads:
63 element_data["TRIADS"] = [
64 item
65 for i in _INPUT_FILE_MAPPINGS["n_nodes_to_node_ordering"][len(self.nodes)]
66 for item in self.nodes[i].rotation.get_rotation_vector()
67 ]
69 return {
70 "id": self.i_global + 1,
71 "cell": {
72 "type": _INPUT_FILE_MAPPINGS["n_nodes_to_cell_type"][len(self.nodes)],
73 "connectivity": [
74 self.nodes[i]
75 for i in _INPUT_FILE_MAPPINGS["n_nodes_to_node_ordering"][
76 len(self.nodes)
77 ]
78 ],
79 },
80 "data": element_data,
81 }
84def get_four_c_reissner_beam(n_nodes: int, is_hermite_centerline: bool) -> type[_Beam]:
85 """Return a Simo-Reissner beam for 4C."""
87 four_c_element_data = {
88 "type": _INPUT_FILE_MAPPINGS["beam_types"][_BeamType.reissner],
89 "HERMITE_CENTERLINE": is_hermite_centerline,
90 }
91 if is_hermite_centerline:
92 coupling_fix_dict = {"NUMDOF": 9, "ONOFF": [1, 1, 1, 1, 1, 1, 0, 0, 0]}
93 coupling_joint_dict = {"NUMDOF": 9, "ONOFF": [1, 1, 1, 0, 0, 0, 0, 0, 0]}
94 else:
95 coupling_fix_dict = {"NUMDOF": 6, "ONOFF": [1, 1, 1, 1, 1, 1]}
96 coupling_joint_dict = {"NUMDOF": 6, "ONOFF": [1, 1, 1, 0, 0, 0]}
98 return type(
99 "BeamFourCSimoReissner",
100 (_generate_beam_class(n_nodes),),
101 {
102 "four_c_beam_type": _BeamType.reissner,
103 "four_c_triads": True,
104 "four_c_element_data": four_c_element_data,
105 "valid_materials": [_MaterialReissner, _MaterialReissnerElastoplastic],
106 "coupling_fix_dict": coupling_fix_dict,
107 "coupling_joint_dict": coupling_joint_dict,
108 "dump_to_list": dump_four_c_beam_to_list,
109 },
110 )
113def get_four_c_kirchhoff_beam(
114 constraint: _BeamKirchhoffConstraintType = _BeamKirchhoffConstraintType.weak,
115 parametrization: _BeamKirchhoffParametrizationType = _BeamKirchhoffParametrizationType.rot,
116 is_fad: bool = True,
117) -> type[_Beam]:
118 """Return a Kirchhoff-Love beam for 4C."""
120 # Set the parameters for this beam.
121 four_c_element_data = {
122 "type": _INPUT_FILE_MAPPINGS["beam_types"][_BeamType.kirchhoff],
123 "CONSTRAINT": constraint.name,
124 "PARAMETRIZATION": parametrization.name,
125 "USE_FAD": is_fad,
126 }
128 # Show warning when not using rotvec.
129 if not parametrization == _BeamKirchhoffParametrizationType.rot:
130 _warnings.warn(
131 "Use tangent based parametrization with caution, especially when "
132 " applying the boundary conditions and couplings."
133 )
135 coupling_fix_dict = {"NUMDOF": 7, "ONOFF": [1, 1, 1, 1, 1, 1, 0]}
136 coupling_joint_dict = {"NUMDOF": 7, "ONOFF": [1, 1, 1, 0, 0, 0, 0]}
138 return type(
139 "BeamFourCKirchhoffLove",
140 (_generate_beam_class(3),),
141 {
142 "four_c_beam_type": _BeamType.kirchhoff,
143 "four_c_triads": True,
144 "four_c_element_data": four_c_element_data,
145 "valid_materials": [_MaterialKirchhoff],
146 "coupling_fix_dict": coupling_fix_dict,
147 "coupling_joint_dict": coupling_joint_dict,
148 "dump_to_list": dump_four_c_beam_to_list,
149 },
150 )
153class BeamFourCEulerBernoulli(_generate_beam_class(2)): # type: ignore[misc]
154 """Represents a Euler Bernoulli beam element."""
156 four_c_beam_type = _BeamType.euler_bernoulli
157 four_c_triads = False
158 four_c_element_data = {
159 "type": _INPUT_FILE_MAPPINGS["beam_types"][_BeamType.euler_bernoulli]
160 }
162 valid_materials = [_MaterialEulerBernoulli]
164 def dump_to_list(self):
165 """Return a list with the (single) item representing this element."""
167 # Check the material.
168 self._check_material()
170 # The two rotations must be the same and the x1 vector must point from
171 # the start point to the end point.
172 if not self.nodes[0].rotation == self.nodes[1].rotation:
173 raise ValueError(
174 "The two nodal rotations in Euler Bernoulli beams must be the same, i.e. the beam "
175 "has to be straight!"
176 )
177 direction = self.nodes[1].coordinates - self.nodes[0].coordinates
178 t1 = self.nodes[0].rotation * [1, 0, 0]
179 if _np.linalg.norm(direction / _np.linalg.norm(direction) - t1) >= _bme.eps_pos:
180 raise ValueError(
181 "The rotations do not match the direction of the Euler Bernoulli beam!"
182 )
184 return dump_four_c_beam_to_list(self)
187def get_four_c_beam(
188 beam_type: _BeamType,
189 *,
190 n_nodes: int | None = None,
191 is_hermite_centerline: bool | None = None,
192 **kwargs,
193) -> type[_Beam]:
194 """Return an object that can be used to create beams with 4C."""
196 def _check_arguments(name, value, expected):
197 """Check that if an argument is given, it has the expected value."""
198 if value is not None and not value == expected:
199 raise ValueError(
200 f"Parameter {name} with the value {value} does not match the expected value {expected}"
201 )
203 match beam_type:
204 case _BeamType.reissner:
205 # Set default values for centerline interpolation
206 if n_nodes is None:
207 n_nodes = 3
208 if is_hermite_centerline is None:
209 is_hermite_centerline = True
210 return get_four_c_reissner_beam(
211 n_nodes=n_nodes, is_hermite_centerline=is_hermite_centerline, **kwargs
212 )
213 case _BeamType.kirchhoff:
214 _check_arguments("n_nodes", n_nodes, 3)
215 _check_arguments("is_hermite_centerline", is_hermite_centerline, True)
216 return get_four_c_kirchhoff_beam(**kwargs)
217 case _BeamType.euler_bernoulli:
218 _check_arguments("n_nodes", n_nodes, 2)
219 _check_arguments("is_hermite_centerline", is_hermite_centerline, True)
220 return BeamFourCEulerBernoulli
221 case _:
222 raise ValueError("Got unexpected beam type.")
225# Provide shortcuts for backwards compatibility
226Beam3rHerm2Line3 = get_four_c_beam(
227 _BeamType.reissner, n_nodes=3, is_hermite_centerline=True
228)
229Beam3rLine2Line2 = get_four_c_beam(
230 _BeamType.reissner, n_nodes=2, is_hermite_centerline=False
231)
232Beam3eb = get_four_c_beam(_BeamType.euler_bernoulli)