Coverage for /opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/hypervehicle/hangar/hifire8.py: 96%

108 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-25 22:58 +0000

1import numpy as np 

2from hypervehicle import Vehicle 

3from hypervehicle.generator import Generator 

4from hypervehicle.geometry import Vector3, Line, Polyline, Bezier 

5from hypervehicle.components import ( 

6 Wing, 

7 Fin, 

8 RevolvedComponent, 

9 CompositeComponent, 

10 common, 

11) 

12 

13 

14def leading_edge_width_function(r): 

15 temp = Bezier( 

16 [ 

17 Vector3(x=0.0, y=0.01), 

18 Vector3(x=0.5, y=0.1), 

19 Vector3(x=1.0, y=0.01), 

20 ] 

21 ) 

22 le_width = temp(r).y 

23 return le_width 

24 

25 

26class ParametricHIFiRE8(Generator): 

27 """Parametric generator for mock-up of the HIFiRE 8. 

28 

29 Dimensions have been approximated based on vehicle's visual proportions. 

30 """ 

31 

32 def __init__(self, **kwargs) -> None: 

33 # Vehicle parameters 

34 self.L = 1.2 

35 self.R_base = 0.175 

36 self.R_nose = 0.1 

37 self.nozzle_length = 0.1 

38 

39 # Complete instantiation 

40 super().__init__(**kwargs) 

41 

42 def create_instance(self) -> Vehicle: 

43 # Instantiate hypervehicle and add all components 

44 hifire8 = Vehicle() 

45 hifire8.configure( 

46 name="HIFiRE-8", 

47 verbosity=1, 

48 ) 

49 

50 # Construct fuselage 

51 # ==================== 

52 

53 fuse_slope = np.arctan((self.R_base - self.R_nose) / self.L) 

54 

55 Xn = self.L 

56 X1 = 1 * self.L 

57 X2 = 0.0 

58 X3 = -self.nozzle_length # Nozzle length 

59 

60 Rn = self.R_nose 

61 R1 = self.R_base - X1 * np.tan(fuse_slope) 

62 R2 = self.R_base - X2 * np.tan(fuse_slope) 

63 R3 = R2 # R_base - X3*np.tan(fuse_slope) 

64 

65 fuse_line = Polyline( 

66 [ 

67 Line(p0=Vector3(X1, R1), p1=Vector3(X2, R2)), 

68 Line(p0=Vector3(X2, R2), p1=Vector3(X3, R3)), 

69 Line(p0=Vector3(X3, R3), p1=Vector3(X3, 0)), 

70 ] 

71 ) 

72 fuselage_0 = RevolvedComponent(fuse_line) 

73 

74 fuse_base_line = Line(p0=Vector3(X1, 0), p1=Vector3(X1, R1)) 

75 fuselage_1 = RevolvedComponent(fuse_base_line) 

76 

77 # Create composite component for fuselage 

78 fuselage = CompositeComponent(stl_resolution=8) 

79 fuselage.add_component(fuselage_0) 

80 fuselage.add_component(fuselage_1) 

81 

82 # Construct fins 

83 # ==================== 

84 # |--p1-----p2 

85 # | | \ 

86 # | | \ 

87 # | | \ 

88 # |--p0______________p3 

89 

90 fin_length = 0.4 # length from p0 to p3 

91 fin_height = 0.4 * fin_length 

92 fin_thickness = 0.02 * fin_length 

93 fin_angle = np.deg2rad(90 - 45) 

94 

95 def eval_r_at_x(x): 

96 """Returns the R value at a given x.""" 

97 return self.R_base - x * np.tan(fuse_slope) 

98 

99 p0 = Vector3(x=0, y=eval_r_at_x(0)) 

100 p1 = Vector3(x=0.2 * fin_length, y=eval_r_at_x(0.2 * fin_length) + fin_height) 

101 p2 = Vector3(x=0.7 * fin_length, y=eval_r_at_x(0.7 * fin_length) + fin_height) 

102 p3 = Vector3(x=fin_length, y=eval_r_at_x(fin_length)) 

103 

104 fin1 = Fin( 

105 p0=p0, 

106 p1=p1, 

107 p2=p2, 

108 p3=p3, 

109 fin_thickness=fin_thickness, 

110 fin_angle=fin_angle, 

111 top_thickness_function=common.uniform_thickness_function( 

112 fin_thickness, "top" 

113 ), 

114 bot_thickness_function=common.uniform_thickness_function( 

115 fin_thickness, "bot" 

116 ), 

117 LE_wf=leading_edge_width_function, 

118 mirror=False, 

119 stl_resolution=3, 

120 ) 

121 

122 # Copy for second fin 

123 fin2 = Fin( 

124 p0=p0, 

125 p1=p1, 

126 p2=p2, 

127 p3=p3, 

128 fin_thickness=fin_thickness, 

129 fin_angle=fin_angle + np.deg2rad(90), 

130 top_thickness_function=common.uniform_thickness_function( 

131 fin_thickness, "top" 

132 ), 

133 bot_thickness_function=common.uniform_thickness_function( 

134 fin_thickness, "bot" 

135 ), 

136 LE_wf=leading_edge_width_function, 

137 mirror=False, 

138 stl_resolution=3, 

139 ) 

140 

141 # Copy for third fin - this should be improved. Maybe 

142 # make a fin geom func and modify fin height 

143 fin3 = Fin( 

144 p0=p0, 

145 p1=0.5 * p1, 

146 p2=0.5 * p2, 

147 p3=p3, 

148 fin_thickness=fin_thickness, 

149 fin_angle=np.deg2rad(-90), 

150 top_thickness_function=common.uniform_thickness_function( 

151 fin_thickness, "top" 

152 ), 

153 bot_thickness_function=common.uniform_thickness_function( 

154 fin_thickness, "bot" 

155 ), 

156 LE_wf=leading_edge_width_function, 

157 mirror=False, 

158 stl_resolution=3, 

159 ) 

160 

161 # Construct wing 

162 # ==================== 

163 

164 # |---B0-------B1__ 

165 # | | ----____ 

166 # | | ----_____ 

167 # | | B2-----------____B3 

168 # |---A0-----------------------------A1---------------TT 

169 # 

170 # |------------------- wing_L ---------------------| 

171 

172 wing_L = 1.3 

173 wing_thickness = 0.04 

174 wing_width = 0.4 

175 wing_origin = 0.2 

176 flap_length = 0.2 

177 

178 # Required points 

179 A0 = Vector3(x=wing_origin, y=0) 

180 A1 = Vector3(x=A0.x + 0.5 * wing_L, y=0) 

181 TT = Vector3(x=A0.x + wing_L, y=0) 

182 B0 = Vector3(x=A0.x, y=wing_width) 

183 

184 # Construction points 

185 B1 = Vector3(x=A0.x + 0.1 * wing_L, y=B0.y) 

186 B2 = Vector3(x=A1.x, y=0.5 * wing_width) 

187 B3 = Vector3(x=TT.x, y=0.13 * wing_width) 

188 

189 # Leading edge line 

190 B0B1 = Line(p0=B0, p1=B1) 

191 B1B2 = Line(p0=B1, p1=B2) 

192 B2B3 = Line(p0=B2, p1=B3) 

193 B3TT = Line(p0=B3, p1=TT) 

194 Line_B0TT = Polyline([B0B1, B1B2, B2B3, B3TT]) 

195 

196 wing = Wing( 

197 A0=A0, 

198 A1=A1, 

199 TT=TT, 

200 B0=B0, 

201 Line_B0TT=Line_B0TT, 

202 top_tf=common.uniform_thickness_function(wing_thickness, "top"), 

203 bot_tf=common.uniform_thickness_function(wing_thickness, "bot"), 

204 LE_wf=leading_edge_width_function, 

205 flap_length=flap_length, 

206 stl_resolution=4, 

207 ) 

208 

209 # Construct nose cap 

210 # ==================== 

211 L_n = 0.5 

212 r_b = eval_r_at_x(Xn) 

213 t_n = 0.005 

214 w_n = 0.15 

215 

216 # Side width angle 

217 side_theta = np.arctan((r_b - 0.5 * w_n) / L_n) 

218 

219 # Points 

220 A0n = Vector3(x=Xn, y=0) 

221 A1n = Vector3(x=Xn + 0.5 * L_n, y=0) 

222 TTn = Vector3(x=Xn + L_n, y=0) 

223 

224 B0n = Vector3(x=A0n.x, y=r_b) 

225 B1n = Vector3(x=A1n.x, y=r_b - (A1n.x - Xn) * np.tan(side_theta)) 

226 B2n = Vector3(x=TTn.x, y=0.5 * w_n) 

227 

228 B0B1n = Line(p0=B0n, p1=B1n) 

229 B1B2n = Line(p0=B1n, p1=B2n) 

230 B2TTn = Line(p0=B2n, p1=TTn) 

231 

232 Line_B0TTn = Polyline([B0B1n, B1B2n, B2TTn]) 

233 

234 def nose_tf_top(x, y, z=0): 

235 # Calculate function weightings for linear blending 

236 circular_weighting = 1 - (1 / L_n) * (x - Xn) 

237 flat_weighting = 1 - circular_weighting 

238 

239 # Calculate functions at x 

240 z_circle = np.sqrt(r_b**2 - y**2) 

241 z_flat = t_n 

242 # z_flat = t_n*np.sqrt(w_n - y**2) 

243 

244 # Weighted sum of function contributions 

245 z = circular_weighting * z_circle + flat_weighting * z_flat 

246 # z = t_n 

247 return Vector3(x=0, y=0, z=-z) 

248 

249 def nose_tf_bot(x, y, z=0): 

250 # Calculate function weightings for linear blending 

251 circular_weighting = 1 - (1 / L_n) * (x - Xn) 

252 flat_weighting = 1 - circular_weighting 

253 

254 # Calculate functions at x 

255 z_circle = np.sqrt(r_b**2 - y**2) 

256 z_flat = t_n 

257 # z_flat = np.sqrt(w_n - y**2) 

258 

259 # Weighted sum of function contributions 

260 z = circular_weighting * z_circle + flat_weighting * z_flat 

261 # z = t_n 

262 return Vector3(x=0, y=0, z=z) 

263 

264 nose = Wing( 

265 A0=A0n, 

266 A1=A1n, 

267 TT=TTn, 

268 B0=B0n, 

269 Line_B0TT=Line_B0TTn, 

270 top_tf=nose_tf_top, 

271 bot_tf=nose_tf_bot, 

272 LE_wf=leading_edge_width_function, 

273 LE_type="FLAT", 

274 stl_resolution=4, 

275 ) 

276 

277 # Add components 

278 hifire8.add_component(fuselage, name="fuselage") 

279 hifire8.add_component(wing, reflection_axis="y", name="wing") 

280 hifire8.add_component(nose, reflection_axis="y", name="nose") 

281 hifire8.add_component(fin1, name="fin1") 

282 hifire8.add_component(fin2, name="fin2") 

283 hifire8.add_component(fin3, name="fin3") 

284 

285 return hifire8 

286 

287 

288if __name__ == "__main__": 

289 # To create the nominal geometry 

290 parametric_generator = ParametricHIFiRE8() 

291 hifire8 = parametric_generator.create_instance() 

292 hifire8.generate() 

293 hifire8.to_stl()