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

59 statements  

« prev     ^ index     » next       coverage.py v7.9.0, created at 2025-06-13 04:26 +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.""" 

23 

24import warnings as _warnings 

25 

26import numpy as _np 

27 

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) 

36 

37 

38class Beam3rHerm2Line3(_Beam): 

39 """Represents a BEAM3R HERM2LINE3 element.""" 

40 

41 nodes_create = [-1, 0, 1] 

42 beam_type = _mpy.beam.reissner 

43 valid_material = [_MaterialReissner, _MaterialReissnerElastoplastic] 

44 

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

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

47 

48 def dump_to_list(self): 

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

50 

51 # Check the material. 

52 self._check_material() 

53 

54 return { 

55 "id": self.i_global, 

56 "cell": { 

57 "type": "HERM2LINE3", 

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

59 }, 

60 "data": { 

61 "type": "BEAM3R", 

62 "MAT": self.material.i_global, 

63 "TRIADS": [ 

64 item 

65 for i in [0, 2, 1] 

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

67 ], 

68 }, 

69 } 

70 

71 

72class Beam3rLine2Line2(_Beam): 

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

74 as well as the displacements.""" 

75 

76 nodes_create = [-1, 1] 

77 beam_type = _mpy.beam.reissner 

78 valid_material = [_MaterialReissner] 

79 

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

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

82 

83 def dump_to_list(self): 

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

85 

86 # Check the material. 

87 self._check_material() 

88 

89 return { 

90 "id": self.i_global, 

91 "cell": { 

92 "type": "LINE2", 

93 "connectivity": [self.nodes[i].i_global for i in [0, 1]], 

94 }, 

95 "data": { 

96 "type": "BEAM3R", 

97 "MAT": self.material.i_global, 

98 "TRIADS": [ 

99 item 

100 for i in [0, 1] 

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

102 ], 

103 }, 

104 } 

105 

106 

107class Beam3kClass(_Beam): 

108 """Represents a Kirchhoff beam element.""" 

109 

110 nodes_create = [-1, 0, 1] 

111 beam_type = _mpy.beam.kirchhoff 

112 valid_material = [_MaterialKirchhoff] 

113 

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

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

116 

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

118 _Beam.__init__(self, **kwargs) 

119 

120 # Set the parameters for this beam. 

121 self.weak = weak 

122 self.rotvec = rotvec 

123 self.is_fad = is_fad 

124 

125 # Show warning when not using rotvec. 

126 if not rotvec: 

127 _warnings.warn( 

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

129 "and couplings." 

130 ) 

131 

132 def dump_to_list(self): 

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

134 

135 # Check the material. 

136 self._check_material() 

137 

138 return { 

139 "id": self.i_global, 

140 "cell": { 

141 "type": "LINE3", 

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

143 }, 

144 "data": { 

145 "type": "BEAM3K", 

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

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

148 "MAT": self.material.i_global, 

149 "TRIADS": [ 

150 item 

151 for i in [0, 2, 1] 

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

153 ], 

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

155 }, 

156 } 

157 

158 

159def Beam3k(**kwargs_class): 

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

161 with certain attributes defined. 

162 

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

164 """ 

165 

166 def create_class(**kwargs): 

167 """The function that will be returned. 

168 

169 This function should behave like the call to the __init__ 

170 function of the class. 

171 """ 

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

173 

174 return create_class 

175 

176 

177class Beam3eb(_Beam): 

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

179 

180 nodes_create = [-1, 1] 

181 beam_type = _mpy.beam.euler_bernoulli 

182 valid_material = [_MaterialEulerBernoulli] 

183 

184 def dump_to_list(self): 

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

186 

187 # Check the material. 

188 self._check_material() 

189 

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

191 # the start point to the end point. 

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

193 raise ValueError( 

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

195 "has to be straight!" 

196 ) 

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

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

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

200 raise ValueError( 

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

202 ) 

203 

204 return { 

205 "id": self.i_global, 

206 "cell": { 

207 "type": "LINE2", 

208 "connectivity": [self.nodes[i].i_global for i in [0, 1]], 

209 }, 

210 "data": { 

211 "type": "BEAM3EB", 

212 "MAT": self.material.i_global, 

213 }, 

214 }