Skip to content

Commit df2baca

Browse files
committed
add results against output test
1 parent 9bc2e9c commit df2baca

File tree

6 files changed

+401
-541
lines changed

6 files changed

+401
-541
lines changed

src/panel.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,12 @@ Calculate lift coefficient for given angle of attack.
239239
function calculate_cl(panel::Panel, alpha::Float64)
240240
if panel.panel_aero_model == "lei_airfoil_breukels"
241241
cl = evalpoly(rad2deg(alpha), reverse(panel.cl_coefficients))
242-
if abs(alpha) >/9) # Outside ±20 degrees
242+
if abs(alpha) >/9)
243243
cl = 2 * cos(alpha) * sin(alpha)^2
244244
end
245245
return cl
246246
elseif panel.panel_aero_model == "inviscid"
247-
return 2π * alpha # Changed: 2 * π to 2π for more idiomatic Julia
247+
return 2π * alpha
248248
elseif panel.panel_aero_model == "polar_data"
249249
return linear_interpolation(
250250
panel.panel_polar_data[:,1],

src/solver.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ end
6060
Main solving routine for the aerodynamic model.
6161
"""
6262
function solve(solver::Solver, wing_aero::WingAerodynamics, gamma_distribution=nothing)
63-
isnothing(wing_aero.va) && throw(ArgumentError("Inflow conditions are not set"))
63+
isnothing(wing_aero.panels[1].va) && throw(ArgumentError("Inflow conditions are not set, use set_va!(wing_aero, va)"))
6464

6565
# Initialize variables
6666
panels = wing_aero.panels

test/test_wing_aerodynamics.jl

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# using VortexStepMethod: Wing, WingAerodynamics, BoundFilament, SemiInfiniteFilament, add_section!, set_va!, solve, calculate_cl
2+
using VortexStepMethod
3+
using VortexStepMethod: calculate_cl, calculate_cd_cm, calculate_projected_area
4+
using LinearAlgebra
5+
using Test
6+
using Logging
7+
8+
include("utils.jl")
9+
10+
@testset "Calculate results against output results" begin
11+
# Setup
12+
density = 1.225
13+
N = 40
14+
max_chord = 1.0
15+
span = 15.709 # AR = 20
16+
Umag = 20.0
17+
AR = span^2 /* span * max_chord / 4)
18+
aoa = deg2rad(5)
19+
Uinf = [cos(aoa), 0.0, sin(aoa)] .* Umag
20+
model = "VSM"
21+
22+
# Setup wing geometry
23+
dist = "cos"
24+
core_radius_fraction = 1e-20
25+
coord = generate_coordinates_el_wing(max_chord, span, N, dist)
26+
coord_left_to_right = flip_created_coord_in_pairs(deepcopy(coord))
27+
wing = Wing(N; spanwise_panel_distribution="unchanged")
28+
for idx in 1:2:length(coord_left_to_right[:, 1])
29+
@debug "coord_left_to_right[$idx] = $(coord_left_to_right[idx,:])"
30+
add_section!(
31+
wing,
32+
coord_left_to_right[idx,:],
33+
coord_left_to_right[idx+1,:],
34+
"inviscid"
35+
)
36+
end
37+
38+
wing_aero = WingAerodynamics([wing])
39+
set_va!(wing_aero, (Uinf, 0.0))
40+
41+
# Run analysis
42+
solver_object = Solver(
43+
aerodynamic_model_type=model,
44+
core_radius_fraction=core_radius_fraction
45+
)
46+
results_NEW = solve(solver_object, wing_aero)
47+
48+
@test results_NEW isa Dict
49+
50+
# Calculate forces using uncorrected alpha
51+
alpha = results_NEW["alpha_uncorrected"]
52+
dyn_visc = 0.5 * density * norm(Uinf)^2
53+
n_panels = length(wing_aero.panels)
54+
lift = zeros(n_panels)
55+
drag = zeros(n_panels)
56+
moment = zeros(n_panels)
57+
58+
for (i, panel) in enumerate(wing_aero.panels)
59+
lift[i] = dyn_visc * calculate_cl(panel, alpha[i]) * panel.chord
60+
cd_cm = calculate_cd_cm(panel, alpha[i])
61+
drag[i] = dyn_visc * cd_cm[1] * panel.chord
62+
moment[i] = dyn_visc * cd_cm[2] * panel.chord^2
63+
@info "lift: $lift, drag: $drag, moment: $moment"
64+
end
65+
Fmag = hcat(lift, drag, moment)
66+
67+
# Calculate coefficients using corrected alpha
68+
alpha = results_NEW["alpha_at_ac"]
69+
aero_coeffs = hcat(
70+
[alpha[i] for (i, panel) in enumerate(wing_aero.panels)],
71+
[calculate_cl(panel, alpha[i]) for (i, panel) in enumerate(wing_aero.panels)],
72+
[calculate_cd_cm(panel, alpha[i])[1] for (i, panel) in enumerate(wing_aero.panels)],
73+
[calculate_cd_cm(panel, alpha[i])[2] for (i, panel) in enumerate(wing_aero.panels)]
74+
)
75+
76+
ringvec = [Dict("r0" => panel.width * panel.z_airf) for panel in wing_aero.panels]
77+
controlpoints = [Dict("tangential" => panel.y_airf, "normal" => panel.x_airf)
78+
for panel in wing_aero.panels]
79+
Atot = calculate_projected_area(wing)
80+
81+
F_rel_ref, F_gl_ref, Ltot_ref, Dtot_ref, CL_ref, CD_ref, CS_ref =
82+
output_results(Fmag, aero_coeffs, ringvec, Uinf, controlpoints, Atot)
83+
84+
# Compare results
85+
@info "Comparing results"
86+
@info "cl_calculated: $(results_NEW["cl"]), CL_ref: $CL_ref"
87+
@info "cd_calculated: $(results_NEW["cd"]), CD_ref: $CD_ref"
88+
@info "cs_calculated: $(results_NEW["cs"]), CS_ref: $CS_ref"
89+
@info "L_calculated: $(results_NEW["lift"]), Ltot_ref: $Ltot_ref"
90+
@info "D_calculated: $(results_NEW["drag"]), Dtot_ref: $Dtot_ref"
91+
92+
# Assert results
93+
@test isapprox(results_NEW["cl"], CL_ref, rtol=1e-4)
94+
@test isapprox(results_NEW["cd"], CD_ref, rtol=1e-4)
95+
@test isapprox(results_NEW["cs"], CS_ref, rtol=1e-4)
96+
@test isapprox(results_NEW["lift"], Ltot_ref, rtol=1e-4)
97+
@test isapprox(results_NEW["drag"], Dtot_ref, rtol=1e-4)
98+
99+
# Check array shapes
100+
@test length(results_NEW["cl_distribution"]) == length(wing_aero.panels)
101+
@test length(results_NEW["cd_distribution"]) == length(wing_aero.panels)
102+
end

test/thesis_oriol_cayon.jl

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""
2+
Post-process results to get global forces and aerodynamic coefficients
3+
4+
Parameters
5+
----------
6+
Fmag : Lift, Drag and Moment magnitudes
7+
aero_coeffs : alpha, cl, cd, cm
8+
ringvec : List of dictionaries containing the vectors that define each ring
9+
Uinf : Wind speed velocity vector
10+
controlpoints : List of dictionaries with the variables needed to define each wing section
11+
Atot : Planform area
12+
13+
Returns
14+
-------
15+
F_rel : Lift and drag forces relative to the local angle of attack
16+
F_gl : Lift and drag forces relative to the wind direction
17+
Ltot : Total lift
18+
Dtot : Total drag
19+
CL : Global CL
20+
CD : Global CD
21+
"""
22+
function output_results(Fmag, aero_coeffs, ringvec, Uinf, controlpoints, Atot)
23+
rho = 1.225
24+
alpha = aero_coeffs[:, 1]
25+
F_rel = []
26+
F_gl = []
27+
Fmag_gl = []
28+
SideF = []
29+
Ltot = 0.0
30+
Dtot = 0.0
31+
SFtot = 0.0
32+
33+
for i in eachindex(alpha)
34+
r0 = ringvec[i]["r0"]
35+
# Relative wind speed direction
36+
dir_urel = cos(alpha[i]) * controlpoints[i]["tangential"] +
37+
sin(alpha[i]) * controlpoints[i]["normal"]
38+
dir_urel = dir_urel / norm(dir_urel)
39+
40+
# Lift direction relative to Urel
41+
dir_L = cross(dir_urel, r0)
42+
dir_L = dir_L / norm(dir_L)
43+
44+
# Drag direction relative to Urel
45+
dir_D = cross([0.0, 1.0, 0.0], dir_L)
46+
dir_D = dir_D / norm(dir_D)
47+
48+
# Lift and drag relative to Urel
49+
L_rel = dir_L * Fmag[i, 1]
50+
D_rel = dir_D * Fmag[i, 2]
51+
push!(F_rel, [L_rel, D_rel])
52+
53+
# Lift direction relative to the wind speed
54+
dir_L_gl = cross(Uinf, [0.0, 1.0, 0.0])
55+
dir_L_gl = dir_L_gl / norm(dir_L_gl)
56+
57+
# Lift and drag relative to the windspeed
58+
L_gl = vector_projection(L_rel, dir_L_gl) + vector_projection(D_rel, dir_L_gl)
59+
D_gl = vector_projection(L_rel, Uinf) + vector_projection(D_rel, Uinf)
60+
push!(F_gl, [L_gl, D_gl])
61+
62+
push!(Fmag_gl, [
63+
dot(L_rel, dir_L_gl) + dot(D_rel, dir_L_gl),
64+
dot(L_rel, Uinf / norm(Uinf)) + dot(D_rel, Uinf / norm(Uinf))
65+
])
66+
67+
push!(SideF, dot(L_rel, [0.0, 1.0, 0.0]) + dot(D_rel, [0.0, 1.0, 0.0]))
68+
end
69+
70+
# Calculate total aerodynamic forces
71+
for i in eachindex(Fmag_gl)
72+
Ltot += Fmag_gl[i][1] * norm(ringvec[i]["r0"])
73+
Dtot += Fmag_gl[i][2] * norm(ringvec[i]["r0"])
74+
SFtot += SideF[i] * norm(ringvec[i]["r0"])
75+
end
76+
77+
Umag = norm(Uinf)
78+
CL = Ltot / (0.5 * Umag^2 * Atot * rho)
79+
CD = Dtot / (0.5 * Umag^2 * Atot * rho)
80+
CS = SFtot / (0.5 * Umag^2 * Atot * rho)
81+
82+
return F_rel, F_gl, Ltot, Dtot, CL, CD, CS
83+
end
84+
85+
"""
86+
Find the projection of a vector into a direction
87+
88+
Parameters
89+
----------
90+
v : vector to be projected
91+
u : direction
92+
93+
Returns
94+
-------
95+
proj : projection of the vector v onto u
96+
"""
97+
function vector_projection(v, u)
98+
unit_u = u / norm(u)
99+
proj = dot(v, unit_u) * unit_u
100+
return proj
101+
end

0 commit comments

Comments
 (0)