Coverage for src/meshpy/four_c/element_beam.py: 95%
76 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-28 04:21 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-28 04:21 +0000
1# The MIT License (MIT)
2#
3# Copyright (c) 2018-2025 MeshPy 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 meshpy.core.conf import mpy as _mpy
29from meshpy.core.element_beam import Beam as _Beam
30from meshpy.four_c.material import MaterialEulerBernoulli as _MaterialEulerBernoulli
31from meshpy.four_c.material import MaterialKirchhoff as _MaterialKirchhoff
32from meshpy.four_c.material import MaterialReissner as _MaterialReissner
33from meshpy.four_c.material import (
34 MaterialReissnerElastoplastic as _MaterialReissnerElastoplastic,
35)
36from meshpy.utils.environment import fourcipp_is_available as _fourcipp_is_available
39class Beam3rHerm2Line3(_Beam):
40 """Represents a BEAM3R HERM2LINE3 element."""
42 nodes_create = [-1, 0, 1]
43 beam_type = _mpy.beam.reissner
44 valid_material = [_MaterialReissner, _MaterialReissnerElastoplastic]
46 coupling_fix_dict = {"NUMDOF": 9, "ONOFF": [1, 1, 1, 1, 1, 1, 0, 0, 0]}
47 coupling_joint_dict = {"NUMDOF": 9, "ONOFF": [1, 1, 1, 0, 0, 0, 0, 0, 0]}
49 def dump_to_list(self):
50 """Return a list with the (single) item representing this element."""
52 if _fourcipp_is_available():
53 raise ValueError(
54 "Port this functionality to not use the legacy string any more"
55 )
57 string_nodes = " ".join(str(self.nodes[i].i_global) for i in [0, 2, 1])
58 string_triads = " ".join(
59 str(item)
60 for i in [0, 2, 1]
61 for item in self.nodes[i].rotation.get_rotation_vector()
62 )
64 # Check the material.
65 self._check_material()
67 return [
68 f"{self.i_global} BEAM3R HERM2LINE3 {string_nodes} MAT {self.material.i_global} "
69 f"TRIADS {string_triads}"
70 ]
73class Beam3rLine2Line2(_Beam):
74 """Represents a Reissner beam with linear shapefunctions in the rotations
75 as well as the displacements."""
77 nodes_create = [-1, 1]
78 beam_type = _mpy.beam.reissner
79 valid_material = [_MaterialReissner]
81 coupling_fix_dict = {"NUMDOF": 6, "ONOFF": [1, 1, 1, 1, 1, 1]}
82 coupling_joint_dict = {"NUMDOF": 6, "ONOFF": [1, 1, 1, 0, 0, 0]}
84 def dump_to_list(self):
85 """Return a list with the (single) item representing this element."""
87 if _fourcipp_is_available():
88 raise ValueError(
89 "Port this functionality to not use the legacy string any more"
90 )
92 string_nodes = " ".join(str(self.nodes[i].i_global) for i in [0, 1])
93 string_triads = " ".join(
94 str(item)
95 for i in [0, 1]
96 for item in self.nodes[i].rotation.get_rotation_vector()
97 )
99 # Check the material.
100 self._check_material()
102 return [
103 f"{self.i_global} BEAM3R LINE2 {string_nodes} MAT {self.material.i_global} "
104 f"TRIADS {string_triads}"
105 ]
108class Beam3kClass(_Beam):
109 """Represents a Kirchhoff beam element."""
111 nodes_create = [-1, 0, 1]
112 beam_type = _mpy.beam.kirchhoff
113 valid_material = [_MaterialKirchhoff]
115 coupling_fix_dict = {"NUMDOF": 7, "ONOFF": [1, 1, 1, 1, 1, 1, 0]}
116 coupling_joint_dict = {"NUMDOF": 7, "ONOFF": [1, 1, 1, 0, 0, 0, 0]}
118 def __init__(self, *, weak=True, rotvec=True, is_fad=True, **kwargs):
119 _Beam.__init__(self, **kwargs)
121 # Set the parameters for this beam.
122 self.weak = weak
123 self.rotvec = rotvec
124 self.is_fad = is_fad
126 # Show warning when not using rotvec.
127 if not rotvec:
128 _warnings.warn(
129 "Use rotvec=False with caution, especially when applying the boundary conditions "
130 "and couplings."
131 )
133 def dump_to_list(self):
134 """Return a list with the (single) item representing this element."""
136 if _fourcipp_is_available():
137 raise ValueError(
138 "Port this functionality to not use the legacy string any more"
139 )
141 string_nodes = " ".join(str(self.nodes[i].i_global) for i in [0, 2, 1])
142 string_triads = " ".join(
143 str(item)
144 for i in [0, 2, 1]
145 for item in self.nodes[i].rotation.get_rotation_vector()
146 )
148 # Check the material.
149 self._check_material()
151 string_dat = ("{} BEAM3K LINE3 {} WK {} ROTVEC {} MAT {} TRIADS {}{}").format(
152 self.i_global,
153 string_nodes,
154 "1" if self.weak else "0",
155 "1" if self.rotvec else "0",
156 self.material.i_global,
157 string_triads,
158 " FAD" if self.is_fad else "",
159 )
161 return [string_dat]
164def Beam3k(**kwargs_class):
165 """This factory returns a function that creates a new Beam3kClass object
166 with certain attributes defined.
168 The returned function behaves like a call to the object.
169 """
171 def create_class(**kwargs):
172 """The function that will be returned.
174 This function should behave like the call to the __init__
175 function of the class.
176 """
177 return Beam3kClass(**kwargs_class, **kwargs)
179 return create_class
182class Beam3eb(_Beam):
183 """Represents a Euler Bernoulli beam element."""
185 nodes_create = [-1, 1]
186 beam_type = _mpy.beam.euler_bernoulli
187 valid_material = [_MaterialEulerBernoulli]
189 def dump_to_list(self):
190 """Return a list with the (single) item representing this element."""
192 if _fourcipp_is_available():
193 raise ValueError(
194 "Port this functionality to not use the legacy string any more"
195 )
197 # The two rotations must be the same and the x1 vector must point from
198 # the start point to the end point.
199 if not self.nodes[0].rotation == self.nodes[1].rotation:
200 raise ValueError(
201 "The two nodal rotations in Euler Bernoulli beams must be the same, i.e. the beam "
202 "has to be straight!"
203 )
204 direction = self.nodes[1].coordinates - self.nodes[0].coordinates
205 t1 = self.nodes[0].rotation * [1, 0, 0]
206 if _np.linalg.norm(direction / _np.linalg.norm(direction) - t1) >= _mpy.eps_pos:
207 raise ValueError(
208 "The rotations do not match the direction of the Euler Bernoulli beam!"
209 )
211 string_nodes = " ".join(str(self.nodes[i].i_global) for i in [0, 1])
213 # Check the material.
214 self._check_material()
216 return [
217 f"{self.i_global} BEAM3EB LINE2 {string_nodes} MAT {self.material.i_global}"
218 ]