Coverage for src / sdynpy / demo / beam_airplane.py: 100%

51 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-11 16:22 +0000

1# -*- coding: utf-8 -*- 

2""" 

3Demonstration system for a simple airplane made of beams 

4""" 

5""" 

6Copyright 2022 National Technology & Engineering Solutions of Sandia, 

7LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. 

8Government retains certain rights in this software. 

9 

10This program is free software: you can redistribute it and/or modify 

11it under the terms of the GNU General Public License as published by 

12the Free Software Foundation, either version 3 of the License, or 

13(at your option) any later version. 

14 

15This program is distributed in the hope that it will be useful, 

16but WITHOUT ANY WARRANTY; without even the implied warranty of 

17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

18GNU General Public License for more details. 

19 

20You should have received a copy of the GNU General Public License 

21along with this program. If not, see <https://www.gnu.org/licenses/>. 

22""" 

23 

24import numpy as _np 

25from ..fem.sdynpy_beam import beamkm as _beamkm 

26from ..core.sdynpy_geometry import (Geometry as _Geometry, 

27 node_array as _node_array, 

28 traceline_array as _traceline_array, 

29 coordinate_system_array as _coordinate_system_array) 

30from ..core.sdynpy_coordinate import (from_nodelist as _from_nodelist, 

31 coordinate_array as _coordinate_array) 

32from ..core.sdynpy_system import (System as _System, 

33 substructure_by_position as _substructure_by_position) 

34 

35 

36def create_models(): 

37 """ 

38 Creates models for the demonstration airplane. 

39 

40 Returns 

41 ------- 

42 full_system : System 

43 `System` containing all the airplane degrees of freedom 

44 full_geometry : Geometry 

45 `Geometry` containing the full airplane model 

46 transmission_system : System 

47 `System` containing a shorter wing that can be used as a transmission 

48 simulator 

49 transmission_geometry : Geometry 

50 `Geometry` containing a shorter wing that can be used as a transmission 

51 simulator 

52 all_systems : dict[System] 

53 A dictionary containing component `System` objects for use in 

54 substructuring 

55 all_geometries : dict[Geometry] 

56 A dictionary containing component `Geometry` objects for use in 

57 substructuring 

58 

59 """ 

60 # Fuselage coords 

61 fuselage_coords = _np.array([_np.linspace(0, 10, 21), 

62 _np.zeros(21), 

63 _np.zeros(21)]).T 

64 

65 # Wing coords 

66 wing_coords = _np.array([[x, y, 0] for x in [2, 3] for y in _np.linspace(-10, 10, 41)]) 

67 

68 # Transmission simulator 

69 transmission_simulator_coords = _np.array( 

70 [[x, y, 0] for x in [2, 3] for y in _np.linspace(-2.5, 2.5, 11)]) 

71 

72 # Tail Coords 

73 tail_coords = _np.array([[9, 2, 2], [9, 1, 1], [9, 0, 0], [9, -1, 1], 

74 [9, -2, 2], [10, 2, 2], [10, 1, 1], [10, 0, 0], [10, -1, 1], [10, -2, 2]]) 

75 

76 # Create element connectivity 

77 fuselage_connectivity = _np.array( 

78 [_np.arange(0, fuselage_coords.shape[0] - 1), _np.arange(1, fuselage_coords.shape[0])]).T 

79 wing_connectivity = _np.concatenate(( 

80 _np.array([_np.arange(0, wing_coords.shape[0] // 2 - 1), 

81 _np.arange(1, wing_coords.shape[0] // 2)]).T, # Front stringer 

82 _np.array([_np.arange(wing_coords.shape[0] // 2, wing_coords.shape[0] - 1), 

83 _np.arange(wing_coords.shape[0] // 2 + 1, wing_coords.shape[0])]).T, # Back stringer 

84 _np.array([_np.arange(0, wing_coords.shape[0] // 2), 

85 _np.arange(wing_coords.shape[0] // 2, wing_coords.shape[0])]).T # Spars 

86 ), axis=0) 

87 transmission_simulator_connectivity = _np.concatenate(( 

88 _np.array([_np.arange(0, transmission_simulator_coords.shape[0] // 2 - 1), 

89 _np.arange(1, transmission_simulator_coords.shape[0] // 2)]).T, # Front stringer 

90 _np.array([_np.arange(transmission_simulator_coords.shape[0] // 2, transmission_simulator_coords.shape[0] - 1), 

91 _np.arange(transmission_simulator_coords.shape[0] // 2 + 1, transmission_simulator_coords.shape[0])]).T, # Back stringer 

92 _np.array([_np.arange(0, transmission_simulator_coords.shape[0] // 2), 

93 _np.arange(transmission_simulator_coords.shape[0] // 2, transmission_simulator_coords.shape[0])]).T # Spars 

94 ), axis=0) 

95 tail_connectivity = _np.concatenate(( 

96 _np.array([_np.arange(0, tail_coords.shape[0] // 2 - 1), 

97 _np.arange(1, tail_coords.shape[0] // 2)]).T, # Front stringer 

98 _np.array([_np.arange(tail_coords.shape[0] // 2, tail_coords.shape[0] - 1), 

99 _np.arange(tail_coords.shape[0] // 2 + 1, tail_coords.shape[0])]).T, # Back stringer 

100 _np.array([_np.arange(0, tail_coords.shape[0] // 2), 

101 _np.arange(tail_coords.shape[0] // 2, tail_coords.shape[0])]).T # Spars 

102 ), axis=0) 

103 

104 # Create the bending directions, we will do positive z for all 

105 fuselage_bend_direction_1 = _np.array( 

106 [_np.zeros(fuselage_connectivity.shape[0]), 

107 _np.zeros(fuselage_connectivity.shape[0]), 

108 _np.ones(fuselage_connectivity.shape[0])] 

109 ).T 

110 wing_bend_direction_1 = _np.array( 

111 [_np.zeros(wing_connectivity.shape[0]), 

112 _np.zeros(wing_connectivity.shape[0]), 

113 _np.ones(wing_connectivity.shape[0])] 

114 ).T 

115 transmission_simulator_bend_direction_1 = _np.array( 

116 [_np.zeros(transmission_simulator_connectivity.shape[0]), 

117 _np.zeros(transmission_simulator_connectivity.shape[0]), 

118 _np.ones(transmission_simulator_connectivity.shape[0])] 

119 ).T 

120 tail_bend_direction_1 = _np.array( 

121 [_np.zeros(tail_connectivity.shape[0]), 

122 _np.zeros(tail_connectivity.shape[0]), 

123 _np.ones(tail_connectivity.shape[0])] 

124 ).T 

125 

126 # Define beam parameters 

127 beam_width = 0.1 

128 beam_height = 0.15 

129 E = 69e9 

130 nu = 0.33 

131 rho = 2830 

132 I1 = beam_width * beam_height**3 / 12 

133 I2 = beam_width**3 * beam_height / 12 

134 G = E / (2 * (1 - nu)) 

135 J = I1 + I2 

136 Ixx_per_L = (1 / 12) * rho * beam_width * beam_height * (beam_width**2 + beam_height**2) 

137 

138 # Rather than doing all the math to create matrices 3 times, let's just do it once in a for loop. 

139 # Let's use dictionaries to store the matrices 

140 all_systems = {} 

141 all_geometries = {} 

142 names = ['fuselage', 'wing', 'tail', 'transmission_simulator'] 

143 colors = [1, 7, 11, 13] 

144 

145 for coord, conn, bend_direction, name, color in zip([fuselage_coords, wing_coords, tail_coords, transmission_simulator_coords], 

146 [fuselage_connectivity, wing_connectivity, 

147 tail_connectivity, transmission_simulator_connectivity], 

148 [fuselage_bend_direction_1, wing_bend_direction_1, 

149 tail_bend_direction_1, transmission_simulator_bend_direction_1], 

150 names, colors): 

151 # Create arguments for the beamkm function 

152 ae = beam_width * beam_height * E * _np.ones(conn.shape[0]) 

153 jg = J * G * _np.ones(conn.shape[0]) 

154 ei1 = E * I1 * _np.ones(conn.shape[0]) 

155 ei2 = E * I2 * _np.ones(conn.shape[0]) 

156 mass_per_length = rho * beam_width * beam_height * _np.ones(conn.shape[0]) 

157 tmmi_per_length = Ixx_per_L * _np.ones(conn.shape[0]) 

158 

159 # Compute K and M via beamkm 

160 this_K, this_M = _beamkm(coord, conn, bend_direction, ae, jg, ei1, 

161 ei2, mass_per_length, tmmi_per_length) 

162 

163 # Create objects 

164 # Create geometry 

165 all_geometries[name] = _Geometry( 

166 _node_array(_np.arange(coord.shape[0]) + 1, coord, color), 

167 _coordinate_system_array(), 

168 _traceline_array(_np.arange(conn.shape[0]) + 1, color=color, connectivity=conn + 1) 

169 ) 

170 # Create system 

171 all_systems[name] = _System( 

172 _from_nodelist(all_geometries[name].node.id, [1, 2, 3, 4, 5, 6]), 

173 this_M, this_K 

174 ) 

175 

176 # Now let's create the full airplane 

177 systems = [all_systems[name] for name in names if name not in ['transmission_simulator']] 

178 geometries = [all_geometries[name] for name in names if name not in ['transmission_simulator']] 

179 

180 full_system, full_geometry = _substructure_by_position(systems, geometries) 

181 

182 # Now let's create the stubby airplane 

183 systems = [all_systems[name] for name in names if name not in ['wing']] 

184 geometries = [all_geometries[name] for name in names if name not in ['wing']] 

185 

186 transmission_system, transmission_geometry = _substructure_by_position(systems, geometries) 

187 

188 return full_system, full_geometry, transmission_system, transmission_geometry, all_systems, all_geometries 

189 

190 

191(system, geometry, transmission_system, transmission_geometry, 

192 component_systems, component_geometries) = create_models()