Coverage for src/beamme/four_c/element_beam.py: 100%

59 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-30 18:48 +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.""" 

23 

24import warnings as _warnings 

25 

26import numpy as _np 

27 

28from beamme.core.conf import mpy as _mpy 

29from beamme.core.element_beam import Beam as _Beam 

30from beamme.four_c.material import MaterialEulerBernoulli as _MaterialEulerBernoulli 

31from beamme.four_c.material import MaterialKirchhoff as _MaterialKirchhoff 

32from beamme.four_c.material import MaterialReissner as _MaterialReissner 

33from beamme.four_c.material import ( 

34 MaterialReissnerElastoplastic as _MaterialReissnerElastoplastic, 

35) 

36 

37 

38class Beam3rHerm2Line3(_Beam): 

39 """Represents a Simo-Reissner beam element with third order Hermitian 

40 interpolation of the centerline and second order Lagrangian interpolation 

41 of the rotations.""" 

42 

43 nodes_create = [-1, 0, 1] 

44 beam_type = _mpy.beam.reissner 

45 valid_material = [_MaterialReissner, _MaterialReissnerElastoplastic] 

46 

47 coupling_fix_dict = {"NUMDOF": 9, "ONOFF": [1, 1, 1, 1, 1, 1, 0, 0, 0]} 

48 coupling_joint_dict = {"NUMDOF": 9, "ONOFF": [1, 1, 1, 0, 0, 0, 0, 0, 0]} 

49 

50 def dump_to_list(self): 

51 """Return a list with the (single) item representing this element.""" 

52 

53 # Check the material. 

54 self._check_material() 

55 

56 return { 

57 "id": self.i_global, 

58 "cell": { 

59 "type": "LINE3", 

60 "connectivity": [self.nodes[i] for i in [0, 2, 1]], 

61 }, 

62 "data": { 

63 "type": "BEAM3R", 

64 "MAT": self.material, 

65 "TRIADS": [ 

66 item 

67 for i in [0, 2, 1] 

68 for item in self.nodes[i].rotation.get_rotation_vector() 

69 ], 

70 "HERMITE_CENTERLINE": True, 

71 }, 

72 } 

73 

74 

75class Beam3rLine2Line2(_Beam): 

76 """Represents a Reissner beam with linear shapefunctions in the rotations 

77 as well as the displacements.""" 

78 

79 nodes_create = [-1, 1] 

80 beam_type = _mpy.beam.reissner 

81 valid_material = [_MaterialReissner] 

82 

83 coupling_fix_dict = {"NUMDOF": 6, "ONOFF": [1, 1, 1, 1, 1, 1]} 

84 coupling_joint_dict = {"NUMDOF": 6, "ONOFF": [1, 1, 1, 0, 0, 0]} 

85 

86 def dump_to_list(self): 

87 """Return a list with the (single) item representing this element.""" 

88 

89 # Check the material. 

90 self._check_material() 

91 

92 return { 

93 "id": self.i_global, 

94 "cell": { 

95 "type": "LINE2", 

96 "connectivity": self.nodes, 

97 }, 

98 "data": { 

99 "type": "BEAM3R", 

100 "MAT": self.material, 

101 "TRIADS": [ 

102 item 

103 for i in [0, 1] 

104 for item in self.nodes[i].rotation.get_rotation_vector() 

105 ], 

106 }, 

107 } 

108 

109 

110class Beam3kClass(_Beam): 

111 """Represents a Kirchhoff beam element.""" 

112 

113 nodes_create = [-1, 0, 1] 

114 beam_type = _mpy.beam.kirchhoff 

115 valid_material = [_MaterialKirchhoff] 

116 

117 coupling_fix_dict = {"NUMDOF": 7, "ONOFF": [1, 1, 1, 1, 1, 1, 0]} 

118 coupling_joint_dict = {"NUMDOF": 7, "ONOFF": [1, 1, 1, 0, 0, 0, 0]} 

119 

120 def __init__(self, *, weak=True, rotvec=True, is_fad=True, **kwargs): 

121 _Beam.__init__(self, **kwargs) 

122 

123 # Set the parameters for this beam. 

124 self.weak = weak 

125 self.rotvec = rotvec 

126 self.is_fad = is_fad 

127 

128 # Show warning when not using rotvec. 

129 if not rotvec: 

130 _warnings.warn( 

131 "Use rotvec=False with caution, especially when applying the boundary conditions " 

132 "and couplings." 

133 ) 

134 

135 def dump_to_list(self): 

136 """Return a list with the (single) item representing this element.""" 

137 

138 # Check the material. 

139 self._check_material() 

140 

141 return { 

142 "id": self.i_global, 

143 "cell": { 

144 "type": "LINE3", 

145 "connectivity": [self.nodes[i] for i in [0, 2, 1]], 

146 }, 

147 "data": { 

148 "type": "BEAM3K", 

149 "WK": 1 if self.weak else 0, 

150 "ROTVEC": 1 if self.rotvec else 0, 

151 "MAT": self.material, 

152 "TRIADS": [ 

153 item 

154 for i in [0, 2, 1] 

155 for item in self.nodes[i].rotation.get_rotation_vector() 

156 ], 

157 **({"USE_FAD": True} if self.is_fad else {}), 

158 }, 

159 } 

160 

161 

162def Beam3k(**kwargs_class): 

163 """This factory returns a function that creates a new Beam3kClass object 

164 with certain attributes defined. 

165 

166 The returned function behaves like a call to the object. 

167 """ 

168 

169 def create_class(**kwargs): 

170 """The function that will be returned. 

171 

172 This function should behave like the call to the __init__ 

173 function of the class. 

174 """ 

175 return Beam3kClass(**kwargs_class, **kwargs) 

176 

177 return create_class 

178 

179 

180class Beam3eb(_Beam): 

181 """Represents a Euler Bernoulli beam element.""" 

182 

183 nodes_create = [-1, 1] 

184 beam_type = _mpy.beam.euler_bernoulli 

185 valid_material = [_MaterialEulerBernoulli] 

186 

187 def dump_to_list(self): 

188 """Return a list with the (single) item representing this element.""" 

189 

190 # Check the material. 

191 self._check_material() 

192 

193 # The two rotations must be the same and the x1 vector must point from 

194 # the start point to the end point. 

195 if not self.nodes[0].rotation == self.nodes[1].rotation: 

196 raise ValueError( 

197 "The two nodal rotations in Euler Bernoulli beams must be the same, i.e. the beam " 

198 "has to be straight!" 

199 ) 

200 direction = self.nodes[1].coordinates - self.nodes[0].coordinates 

201 t1 = self.nodes[0].rotation * [1, 0, 0] 

202 if _np.linalg.norm(direction / _np.linalg.norm(direction) - t1) >= _mpy.eps_pos: 

203 raise ValueError( 

204 "The rotations do not match the direction of the Euler Bernoulli beam!" 

205 ) 

206 

207 return { 

208 "id": self.i_global, 

209 "cell": { 

210 "type": "LINE2", 

211 "connectivity": self.nodes, 

212 }, 

213 "data": { 

214 "type": "BEAM3EB", 

215 "MAT": self.material, 

216 }, 

217 }