Skip to content

Commit 2b03015

Browse files
committed
Don't deform tuple
1 parent df97a21 commit 2b03015

File tree

4 files changed

+184
-3
lines changed

4 files changed

+184
-3
lines changed

examples/Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[deps]
2+
ControlPlots = "23c2ee80-7a9e-4350-b264-8e670f12517c"
3+
VortexStepMethod = "ed3cd733-9f0f-46a9-93e0-89b8d4998dd9"

src/wing_geometry.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ function reinit!(section::Section, LE_point, TE_point, aero_model=nothing, aero_
4444
section.TE_point .= TE_point
4545
(!isnothing(aero_model)) && (section.aero_model = aero_model)
4646
if !isnothing(aero_data)
47-
if !isnothing(section.aero_data)
48-
section.aero_data .= aero_data
49-
else
47+
# NTuple is immutable, so we must assign directly
48+
# For mutable types (Vector, Matrix), we can broadcast for efficiency
49+
if aero_data isa NTuple || isnothing(section.aero_data)
5050
section.aero_data = aero_data
51+
else
52+
section.aero_data .= aero_data
5153
end
5254
end
5355
nothing

test/yaml_geometry/test_yaml_geometry.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ using Test
44
# Include specific test files for better organization
55
include("test_load_polar_data.jl")
66
include("test_wing_constructor.jl")
7+
include("test_yaml_wing_deformation.jl")
78
end
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
using VortexStepMethod
2+
using LinearAlgebra
3+
using Test
4+
5+
@testset "YAML Wing Deformation Tests" begin
6+
@testset "Simple Wing Deformation" begin
7+
# Load existing simple_wing.yaml
8+
simple_wing_file = test_data_path("yaml_geometry", "simple_wing.yaml")
9+
wing = Wing(simple_wing_file; n_panels=4, n_groups=2)
10+
body_aero = BodyAerodynamics([wing])
11+
12+
# Store original TE point for comparison
13+
i = length(body_aero.panels) ÷ 2
14+
original_te_point = copy(body_aero.panels[i].TE_point_1)
15+
original_le_point = copy(body_aero.panels[i].LE_point_1)
16+
17+
# Apply deformation with non-zero angles
18+
theta_dist = fill(deg2rad(30.0), wing.n_panels) # 30 degrees twist
19+
delta_dist = fill(deg2rad(5.0), wing.n_panels) # 5 degrees trailing edge deflection
20+
21+
VortexStepMethod.deform!(wing, theta_dist, delta_dist)
22+
VortexStepMethod.reinit!(body_aero)
23+
24+
# Check if TE point changed after deformation
25+
deformed_te_point = copy(body_aero.panels[i].TE_point_1)
26+
deformed_le_point = copy(body_aero.panels[i].LE_point_1)
27+
28+
# TE point should change significantly due to twist and deflection
29+
@test !isapprox(original_te_point, deformed_te_point, atol=1e-2)
30+
@test deformed_te_point[3] < original_te_point[3] # TE should move down with positive twist
31+
32+
# LE point should also change due to twist
33+
@test !isapprox(original_le_point, deformed_le_point, atol=1e-2)
34+
35+
# Check delta is set correctly
36+
@test body_aero.panels[i].delta deg2rad(5.0)
37+
38+
# Reset deformation with zero angles
39+
zero_theta_dist = zeros(wing.n_panels)
40+
zero_delta_dist = zeros(wing.n_panels)
41+
42+
VortexStepMethod.deform!(wing, zero_theta_dist, zero_delta_dist)
43+
VortexStepMethod.reinit!(body_aero)
44+
45+
# Check if TE point returned to original position
46+
reset_te_point = copy(body_aero.panels[i].TE_point_1)
47+
reset_le_point = copy(body_aero.panels[i].LE_point_1)
48+
@test original_te_point reset_te_point atol=1e-4
49+
@test original_le_point reset_le_point atol=1e-4
50+
@test body_aero.panels[i].delta 0.0 atol=1e-4
51+
end
52+
53+
@testset "Complex Wing Deformation" begin
54+
# Load existing complex_wing.yaml with multiple sections
55+
complex_wing_file = test_data_path("yaml_geometry", "complex_wing.yaml")
56+
wing = Wing(complex_wing_file; n_panels=12, n_groups=3)
57+
body_aero = BodyAerodynamics([wing])
58+
59+
# Store original points for multiple panels
60+
original_points = []
61+
test_indices = [1, length(body_aero.panels) ÷ 2, length(body_aero.panels)]
62+
for i in test_indices
63+
push!(original_points, (
64+
LE=copy(body_aero.panels[i].LE_point_1),
65+
TE=copy(body_aero.panels[i].TE_point_1)
66+
))
67+
end
68+
69+
# Apply spanwise-varying deformation
70+
theta_dist = [deg2rad(10.0 * i / wing.n_panels) for i in 1:wing.n_panels] # Linear twist distribution
71+
delta_dist = [deg2rad(-5.0 + 10.0 * i / wing.n_panels) for i in 1:wing.n_panels] # Varying deflection
72+
73+
VortexStepMethod.deform!(wing, theta_dist, delta_dist)
74+
VortexStepMethod.reinit!(body_aero)
75+
76+
# Check that different panels have different deformations
77+
for (idx, i) in enumerate(test_indices)
78+
deformed_te = body_aero.panels[i].TE_point_1
79+
deformed_le = body_aero.panels[i].LE_point_1
80+
81+
# Points should have changed
82+
@test !isapprox(original_points[idx].TE, deformed_te, atol=1e-2)
83+
@test !isapprox(original_points[idx].LE, deformed_le, atol=1e-2)
84+
end
85+
86+
# Check that the deformation is applied correctly
87+
# First panel should have smaller theta, last panel should have larger theta
88+
@test body_aero.panels[1].delta < body_aero.panels[end].delta
89+
90+
# Reset and verify
91+
VortexStepMethod.deform!(wing, zeros(wing.n_panels), zeros(wing.n_panels))
92+
VortexStepMethod.reinit!(body_aero)
93+
94+
for (idx, i) in enumerate(test_indices)
95+
reset_te = body_aero.panels[i].TE_point_1
96+
reset_le = body_aero.panels[i].LE_point_1
97+
@test original_points[idx].TE reset_te atol=1e-4
98+
@test original_points[idx].LE reset_le atol=1e-4
99+
@test body_aero.panels[i].delta 0.0 atol=1e-4
100+
end
101+
end
102+
103+
@testset "Multiple Reinit Calls with NTuple aero_data" begin
104+
# This test specifically checks the NTuple handling fix
105+
simple_wing_file = test_data_path("yaml_geometry", "simple_wing.yaml")
106+
wing = Wing(simple_wing_file; n_panels=4, n_groups=2)
107+
108+
# Verify that sections have NTuple aero_data (for wings with simple polars)
109+
# or other valid AeroData types
110+
@test wing.sections[1].aero_data !== nothing
111+
112+
# Perform multiple reinit! calls to ensure NTuple handling works
113+
for _ in 1:5
114+
VortexStepMethod.reinit!(wing)
115+
end
116+
117+
# Wing should still be valid after multiple reinits
118+
@test wing.sections[1].aero_data !== nothing
119+
@test length(wing.sections) == 2
120+
end
121+
122+
@testset "Deformation with BodyAerodynamics Reinit" begin
123+
# Test that reinit! on BodyAerodynamics properly handles deformed wings
124+
simple_wing_file = test_data_path("yaml_geometry", "simple_wing.yaml")
125+
wing = Wing(simple_wing_file; n_panels=4, n_groups=2)
126+
body_aero = BodyAerodynamics([wing])
127+
128+
# Apply deformation
129+
theta_dist = fill(deg2rad(15.0), wing.n_panels)
130+
delta_dist = fill(deg2rad(3.0), wing.n_panels)
131+
VortexStepMethod.deform!(wing, theta_dist, delta_dist)
132+
133+
# Store state after deformation
134+
i = length(body_aero.panels) ÷ 2
135+
136+
# Multiple reinit calls should work without errors
137+
for _ in 1:3
138+
VortexStepMethod.reinit!(body_aero;
139+
va=zeros(3),
140+
omega=zeros(3),
141+
init_aero=true
142+
)
143+
end
144+
145+
# Panel should maintain deformation
146+
@test body_aero.panels[i].delta deg2rad(3.0) atol=1e-6
147+
end
148+
149+
@testset "Edge Cases" begin
150+
simple_wing_file = test_data_path("yaml_geometry", "simple_wing.yaml")
151+
wing = Wing(simple_wing_file; n_panels=2, n_groups=1)
152+
body_aero = BodyAerodynamics([wing])
153+
154+
# Test zero deformation
155+
VortexStepMethod.deform!(wing, zeros(wing.n_panels), zeros(wing.n_panels))
156+
VortexStepMethod.reinit!(body_aero)
157+
@test all(p.delta 0.0 for p in body_aero.panels)
158+
159+
# Test large deformation angles
160+
theta_dist = fill(deg2rad(60.0), wing.n_panels)
161+
delta_dist = fill(deg2rad(30.0), wing.n_panels)
162+
163+
# Should not error even with large angles
164+
VortexStepMethod.deform!(wing, theta_dist, delta_dist)
165+
VortexStepMethod.reinit!(body_aero)
166+
@test all(p.delta deg2rad(30.0) for p in body_aero.panels)
167+
168+
# Test negative angles
169+
theta_dist = fill(deg2rad(-20.0), wing.n_panels)
170+
delta_dist = fill(deg2rad(-10.0), wing.n_panels)
171+
VortexStepMethod.deform!(wing, theta_dist, delta_dist)
172+
VortexStepMethod.reinit!(body_aero)
173+
@test all(p.delta deg2rad(-10.0) for p in body_aero.panels)
174+
end
175+
end

0 commit comments

Comments
 (0)