Skip to content

Commit 9bc2e9c

Browse files
committed
add tests
1 parent 608e9e4 commit 9bc2e9c

File tree

9 files changed

+464
-401
lines changed

9 files changed

+464
-401
lines changed

examples/testing_stall_model.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# using Revise
1+
using Revise
22
using VortexStepMethod
33
using CSV
44
using DataFrames

src/panel.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,34 @@ mutable struct Panel
118118
end
119119
end
120120

121+
"""
122+
calculate_relative_alpha_and_relative_velocity(panel::Panel, induced_velocity::Vector{Float64})
123+
124+
Calculate the relative angle of attack and relative velocity of the panel.
125+
126+
# Arguments
127+
- `panel::Panel`: The panel object
128+
- `induced_velocity::Vector{Float64}`: Induced velocity at the control point
129+
130+
# Returns
131+
- `Tuple{Float64,Vector{Float64}}`: Tuple containing:
132+
- alpha: Relative angle of attack of the panel (in radians)
133+
- relative_velocity: Relative velocity vector of the panel
134+
"""
135+
function calculate_relative_alpha_and_relative_velocity(
136+
panel::Panel,
137+
induced_velocity::Vector{Float64}
138+
)
139+
# Calculate relative velocity and angle of attack
140+
# Constants throughout iterations: panel.va, panel.x_airf, panel.y_airf
141+
relative_velocity = panel.va .+ induced_velocity
142+
v_normal = dot(panel.x_airf, relative_velocity)
143+
v_tangential = dot(panel.y_airf, relative_velocity)
144+
alpha = atan(v_normal / v_tangential)
145+
146+
return alpha, relative_velocity
147+
end
148+
121149
"""
122150
compute_lei_coefficients(section_1::Section, section_2::Section)
123151

src/wing_geometry.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct Section
2323

2424
# Default constructor
2525
function Section()
26-
new(zeros(3), zeros(3), Any[])
26+
new(zeros(3), zeros(3), "")
2727
end
2828
end
2929

test/runtests.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using VortexStepMethod
21
using Test
32

43
cd("..")
5-
println("Running tests...")
4+
println("Running tests...")
5+
@testset verbose = true "Testing VortexStepMethod..." begin
6+
include("test_bound_filament.jl")
7+
end

test/test_bound_filament.jl

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
using VortexStepMethod: BoundFilament, velocity_3D_bound_vortex!
2+
using LinearAlgebra
3+
using Test
4+
5+
# Test helper functions
6+
function create_test_filament()
7+
BoundFilament([0.0, 0.0, 0.0], [1.0, 0.0, 0.0])
8+
end
9+
10+
function analytical_solution(control_point, gamma)
11+
A = [0.0, 0.0, 0.0]
12+
B = [1.0, 0.0, 0.0]
13+
P = control_point
14+
15+
r0 = B - A
16+
r1 = P - A
17+
r2 = P - B
18+
19+
r1Xr2 = cross(r1, r2)
20+
norm_r1Xr2 = norm(r1Xr2)
21+
22+
return (gamma / (4π)) * (r1Xr2 / (norm_r1Xr2^2)) *
23+
dot(r0, r1/norm(r1) - r2/norm(r2))
24+
end
25+
26+
@testset "BoundFilament Tests" begin
27+
gamma = 1.0
28+
core_radius_fraction = 0.01
29+
induced_velocity = zeros(3)
30+
31+
@testset "Calculate Induced Velocity" begin
32+
filament = create_test_filament()
33+
control_point = [0.5, 1.0, 0.0]
34+
35+
velocity_3D_bound_vortex!(
36+
induced_velocity,
37+
filament,
38+
control_point,
39+
gamma,
40+
core_radius_fraction
41+
)
42+
analytical_velocity = analytical_solution(control_point, gamma)
43+
44+
@test isapprox(induced_velocity, analytical_velocity, rtol=1e-6)
45+
end
46+
47+
@testset "Point Exactly on Filament" begin
48+
filament = create_test_filament()
49+
test_points = [
50+
[0.0, 0.0, 0.0], # start point
51+
[1.0, 0.0, 0.0], # end point
52+
[0.5, 0.0, 0.0], # middle point
53+
]
54+
55+
for point in test_points
56+
velocity_3D_bound_vortex!(
57+
induced_velocity,
58+
filament,
59+
point,
60+
gamma,
61+
core_radius_fraction
62+
)
63+
@test all(isapprox.(induced_velocity, zeros(3), atol=1e-10))
64+
@test !any(isnan.(induced_velocity))
65+
end
66+
end
67+
68+
@testset "Long Filament" begin
69+
filament = BoundFilament([0.0, 0.0, 0.0], [1e6, 0.0, 0.0])
70+
control_point = [5e5, 1.0, 0.0]
71+
72+
velocity_3D_bound_vortex!(
73+
induced_velocity,
74+
filament,
75+
control_point,
76+
gamma,
77+
core_radius_fraction
78+
)
79+
80+
@test !any(isnan.(induced_velocity))
81+
@test isapprox(induced_velocity[1], 0.0, atol=1e-8)
82+
@test abs(induced_velocity[2]) < 1e-8
83+
@test isapprox(induced_velocity[3], 0.0)
84+
end
85+
86+
@testset "Point Far from Filament" begin
87+
filament = create_test_filament()
88+
control_point = [0.5, 1e6, 0.0]
89+
90+
velocity_3D_bound_vortex!(
91+
induced_velocity,
92+
filament,
93+
control_point,
94+
gamma,
95+
core_radius_fraction
96+
)
97+
98+
@test !any(isnan.(induced_velocity))
99+
@test all(isapprox.(induced_velocity, zeros(3), atol=1e-12))
100+
end
101+
102+
v1, v2, v4 = zeros(3), zeros(3), zeros(3)
103+
104+
@testset "Different Gamma Values" begin
105+
filament = create_test_filament()
106+
control_point = [0.5, 1.0, 0.0]
107+
108+
velocity_3D_bound_vortex!(v1, filament, control_point, 1.0, core_radius_fraction)
109+
velocity_3D_bound_vortex!(v2, filament, control_point, 2.0, core_radius_fraction)
110+
velocity_3D_bound_vortex!(v4, filament, control_point, 4.0, core_radius_fraction)
111+
112+
@test isapprox(v4, 2 * v2)
113+
@test isapprox(v4, 4 * v1)
114+
end
115+
116+
@testset "Symmetry" begin
117+
filament = BoundFilament([-1.0, 0.0, 0.0], [1.0, 0.0, 0.0])
118+
119+
velocity_3D_bound_vortex!(v1, filament, [0.0, 1.0, 0.0], gamma, core_radius_fraction)
120+
velocity_3D_bound_vortex!(v2, filament, [0.0, -1.0, 0.0], gamma, core_radius_fraction)
121+
122+
@test isapprox(v1, -v2)
123+
end
124+
125+
@testset "Around Core Radius" begin
126+
filament = create_test_filament()
127+
delta = 1e-5
128+
129+
points = [
130+
[0.5, core_radius_fraction - delta, 0.0],
131+
[0.5, core_radius_fraction, 0.0],
132+
[0.5, core_radius_fraction + delta, 0.0]
133+
]
134+
135+
velocities = [zeros(3) for p in points]
136+
[
137+
velocity_3D_bound_vortex!(velocities[i], filament, p, gamma, core_radius_fraction)
138+
for (i, p) in enumerate(points)
139+
]
140+
141+
# Check for NaN and finite values
142+
@test all(!any(isnan.(v)) for v in velocities)
143+
@test all(all(isfinite.(v)) for v in velocities)
144+
145+
# Check magnitude is maximum at core radius
146+
@test norm(velocities[2]) > norm(velocities[1])
147+
@test norm(velocities[2]) > norm(velocities[3])
148+
149+
# Check continuity around core radius
150+
@test isapprox(velocities[1], velocities[2], rtol=1e-3)
151+
152+
# Check non-zero velocities
153+
@test !all(isapprox.(velocities[1], zeros(3), atol=1e-10))
154+
@test !all(isapprox.(velocities[2], zeros(3), atol=1e-10))
155+
@test !all(isapprox.(velocities[3], zeros(3), atol=1e-10))
156+
157+
# Check symmetry
158+
v_neg = zeros(3)
159+
velocity_3D_bound_vortex!(
160+
v_neg,
161+
filament,
162+
[0.5, -core_radius_fraction, 0.0],
163+
gamma,
164+
core_radius_fraction
165+
)
166+
@test isapprox(velocities[2], -v_neg)
167+
end
168+
end

test/test_panel.jl

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using VortexStepMethod: Panel, Section, calculate_relative_alpha_and_relative_velocity
2+
using LinearAlgebra
3+
using Test
4+
using BenchmarkTools
5+
6+
function create_panel(section1::Section, section2::Section)
7+
# Calculate panel geometry
8+
section = Dict(
9+
"p1" => section1.LE_point,
10+
"p2" => section2.LE_point,
11+
"p3" => section2.TE_point,
12+
"p4" => section1.TE_point
13+
)
14+
15+
bound_1 = section["p1"] .* 3/4 .+ section["p4"] .* 1/4
16+
bound_2 = section["p2"] .* 3/4 .+ section["p3"] .* 1/4
17+
18+
mid_LE_point = section2.LE_point .+ 0.5 .* (section1.LE_point .- section2.LE_point)
19+
mid_TE_point = section2.TE_point .+ 0.5 .* (section1.TE_point .- section2.TE_point)
20+
mid_LE_vector = mid_TE_point .- mid_LE_point
21+
aerodynamic_center = bound_1 .+ 0.5 .* (bound_2 .- bound_1)
22+
control_point = aerodynamic_center .+ 0.5 .* mid_LE_vector
23+
24+
LLpoint = aerodynamic_center
25+
VSMpoint = control_point
26+
x_airf = cross(VSMpoint .- LLpoint, section["p2"] .- section["p1"])
27+
x_airf = x_airf ./ norm(x_airf)
28+
29+
# TANGENTIAL y_airf defined parallel to the chord-line
30+
y_airf = VSMpoint .- LLpoint
31+
y_airf = y_airf ./ norm(y_airf)
32+
33+
# SPAN z_airf along the LE
34+
z_airf = bound_2 .- bound_1
35+
z_airf = z_airf ./ norm(z_airf)
36+
37+
Panel(
38+
section1,
39+
section2,
40+
aerodynamic_center,
41+
control_point,
42+
bound_1,
43+
bound_2,
44+
x_airf,
45+
y_airf,
46+
z_airf
47+
)
48+
end
49+
50+
@testset "Panel Tests" begin
51+
@testset "Basic Panel Properties" begin
52+
section1 = Section([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], "inviscid")
53+
section2 = Section([0.0, 10.0, 0.0], [1.0, 10.0, 0.0], "inviscid")
54+
panel = create_panel(section1, section2)
55+
56+
# Test panel initialization
57+
@test panel isa Panel
58+
59+
# Test TE/LE points
60+
@test isapprox(panel.TE_point_1, [1.0, 0.0, 0.0])
61+
@test isapprox(panel.TE_point_2, [1.0, 10.0, 0.0])
62+
@test isapprox(panel.LE_point_1, [0.0, 0.0, 0.0])
63+
@test isapprox(panel.LE_point_2, [0.0, 10.0, 0.0])
64+
65+
# Test corner points
66+
expected_corners = [
67+
# LE1 TE1 TE2 TE1
68+
0.0 1.0 1.0 0.0; # x coordinates
69+
0.0 0.0 10.0 10.0; # y coordinates
70+
0.0 0.0 0.0 0.0 # z coordinates
71+
]
72+
@test all(isapprox.(panel.corner_points, expected_corners))
73+
74+
# Test chord calculation
75+
rib_1 = panel.TE_point_1 .- panel.LE_point_1 # Vector from LE to TE for first section
76+
rib_2 = panel.TE_point_2 .- panel.LE_point_2 # Vector from LE to TE for second section
77+
expected_chord = (norm(rib_1) + norm(rib_2)) / 2
78+
@test isapprox(panel.chord, expected_chord)
79+
end
80+
81+
@testset "Panel Reference Frame" begin
82+
section1 = Section([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], "inviscid")
83+
section2 = Section([0.0, 10.0, 0.0], [1.0, 10.0, 0.0], "inviscid")
84+
panel = create_panel(section1, section2)
85+
86+
# Test reference frame vectors
87+
@test isapprox(panel.x_airf, [0.0, 0.0, 1.0])
88+
@test isapprox(panel.y_airf, [1.0, 0.0, 0.0])
89+
@test isapprox(panel.z_airf, [0.0, 1.0, 0.0])
90+
end
91+
92+
@testset "Velocity Calculations" begin
93+
section1 = Section([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], "inviscid")
94+
section2 = Section([0.0, 10.0, 0.0], [1.0, 10.0, 0.0], "inviscid")
95+
panel = create_panel(section1, section2)
96+
97+
# Test relative velocity calculations
98+
panel.va = [10.0, 0.0, 0.0]
99+
induced_velocity = [1.0, 1.0, 1.0]
100+
alpha, rel_vel = calculate_relative_alpha_and_relative_velocity(panel, induced_velocity)
101+
102+
# Verify calculations
103+
norm_airf = panel.x_airf
104+
tan_airf = panel.y_airf
105+
relative_velocity = panel.va .+ induced_velocity
106+
vn = dot(norm_airf, relative_velocity)
107+
vtan = dot(tan_airf, relative_velocity)
108+
expected_alpha = atan(vn / vtan)
109+
110+
@test isapprox(alpha, expected_alpha)
111+
@test isapprox(rel_vel, relative_velocity)
112+
end
113+
end

0 commit comments

Comments
 (0)