Skip to content

Commit 320654b

Browse files
committed
Add result tests
1 parent 661fc83 commit 320654b

File tree

8 files changed

+195
-155
lines changed

8 files changed

+195
-155
lines changed

examples/ram_air_kite.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ if LINEARIZE
4949
body_aero,
5050
wing,
5151
[zeros(4); vel_app; zeros(3)];
52-
alpha_idxs=1:4,
52+
theta_idxs=1:4,
5353
va_idxs=5:7,
5454
omega_idxs=8:10,
5555
moment_frac=0.1)
@@ -58,7 +58,7 @@ if LINEARIZE
5858
body_aero,
5959
wing,
6060
[zeros(4); vel_app; zeros(3)];
61-
alpha_idxs=1:4,
61+
theta_idxs=1:4,
6262
va_idxs=5:7,
6363
omega_idxs=8:10,
6464
moment_frac=0.1)

src/body_aerodynamics.jl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,17 @@ Construct a [BodyAerodynamics](@ref) object for aerodynamic calculations.
4848
4949
# Keyword Arguments
5050
- `kite_body_origin=zeros(MVec3)`: Origin point of kite body reference frame in CAD reference frame
51+
- `va=[15.0, 0.0, 0.0]`: Apparent wind vector
52+
- `omega=zeros(3)`: Turn rate in kite body frame x y and z
5153
5254
# Returns
5355
- [BodyAerodynamics](@ref) object initialized with panels and wings
5456
"""
5557
function BodyAerodynamics(
5658
wings::Vector{T};
57-
kite_body_origin=zeros(MVec3)
59+
kite_body_origin=zeros(MVec3),
60+
va=[15.0, 0.0, 0.0],
61+
omega=zeros(MVec3)
5862
) where T <: AbstractWing
5963
# Initialize panels
6064
panels = Panel[]
@@ -78,7 +82,7 @@ function BodyAerodynamics(
7882
end
7983

8084
body_aero = BodyAerodynamics{length(panels)}(; panels, wings)
81-
init!(body_aero)
85+
init!(body_aero; va, omega)
8286
return body_aero
8387
end
8488

@@ -107,11 +111,17 @@ Initialize a BodyAerodynamics struct in-place by setting up panels and coefficie
107111
108112
# Keyword Arguments
109113
- `init_aero::Bool`: Wether to initialize the aero data or not
114+
- `va=[15.0, 0.0, 0.0]`: Apparent wind vector
115+
- `omega=zeros(3)`: Turn rate in kite body frame x y and z
110116
111117
# Returns
112118
nothing
113119
"""
114-
function init!(body_aero::BodyAerodynamics; init_aero=true)
120+
function init!(body_aero::BodyAerodynamics;
121+
init_aero=true,
122+
va=[15.0, 0.0, 0.0],
123+
omega=zeros(MVec3)
124+
)
115125
idx = 1
116126
vec = zeros(MVec3)
117127
for wing in body_aero.wings
@@ -151,6 +161,7 @@ function init!(body_aero::BodyAerodynamics; init_aero=true)
151161
body_aero.alpha_array .= 0.0
152162
body_aero.v_a_array .= 0.0
153163
body_aero.AIC .= 0.0
164+
set_va!(body_aero, va, omega)
154165
return nothing
155166
end
156167

src/kite_geometry.jl

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,8 @@ Represents a curved wing that inherits from Wing with additional geometric prope
368368
369369
# Fields
370370
- All fields from Wing:
371-
- `n_panels::Int64`: Number of panels in aerodynamic mesh
371+
- `n_panels::Int16`: Number of panels in aerodynamic mesh
372+
- `n_groups::Int16`: Number of panel groups, each panel group has it's own twisting moment
372373
- `spanwise_distribution`::PanelDistribution: see: [PanelDistribution](@ref)
373374
- `spanwise_direction::MVec3`: Wing span direction vector
374375
- `sections::Vector{Section}`: List of wing sections, see: [Section](@ref)
@@ -387,7 +388,8 @@ Represents a curved wing that inherits from Wing with additional geometric prope
387388
388389
"""
389390
mutable struct RamAirWing <: AbstractWing
390-
n_panels::Int64
391+
n_panels::Int16
392+
n_groups::Int16
391393
spanwise_distribution::PanelDistribution
392394
panel_props::PanelProperties
393395
spanwise_direction::MVec3
@@ -422,19 +424,19 @@ Constructor for a [RamAirWing](@ref) that allows to use an `.obj` and a `.dat` f
422424
- dat_path: Path to the `.dat` file, a standard format for 2d foil geometry
423425
424426
# Keyword Parameters
425-
- alpha=0.0: Angle of attack of each segment relative to the x axis [rad]
426-
- crease_frac=0.75: The x coordinate around which the trailing edge rotates on a normalized 2d foil,
427+
- crease_frac=0.9: The x coordinate around which the trailing edge rotates on a normalized 2d foil,
427428
used in the xfoil polar generation
428429
- wind_vel=10.0: Apparent wind speed in m/s, used in the xfoil polar generation
429430
- mass=1.0: Mass of the wing in kg, used for the inertia calculations
430431
- `n_panels`=56: Number of panels.
431-
- `n_sections`=n_panels+1: Number of sections (there is a section on each side of each panel.)
432+
- `n_sections=n_panels+1`: Number of sections (there is a section on each side of each panel.)
433+
- `n_groups=n_panels ÷ 4`: Number of panel groups
432434
- `spanwise_distribution`=UNCHANGED: see: [PanelDistribution](@ref)
433435
- `spanwise_direction`=[0.0, 1.0, 0.0]
434436
- `remove_nan::Bool`: Wether to remove the NaNs from interpolations or not
435437
"""
436-
function RamAirWing(obj_path, dat_path; alpha=0.0, crease_frac=0.75, wind_vel=10., mass=1.0,
437-
n_panels=56, n_sections=n_panels+1, spanwise_distribution=UNCHANGED,
438+
function RamAirWing(obj_path, dat_path; crease_frac=0.9, wind_vel=10., mass=1.0,
439+
n_panels=56, n_sections=n_panels+1, n_groups=n_panels÷4, spanwise_distribution=UNCHANGED,
438440
spanwise_direction=[0.0, 1.0, 0.0], remove_nan=true, align_to_principal=false,
439441
alpha_range=deg2rad.(-5:1:20), delta_range=deg2rad.(-5:1:20), interp_steps=n_sections
440442
)
@@ -508,7 +510,7 @@ function RamAirWing(obj_path, dat_path; alpha=0.0, crease_frac=0.75, wind_vel=10
508510
panel_props = PanelProperties{n_panels}()
509511
cache = [LazyBufferCache()]
510512

511-
RamAirWing(n_panels, spanwise_distribution, panel_props, spanwise_direction, sections,
513+
RamAirWing(n_panels, n_groups, spanwise_distribution, panel_props, spanwise_direction, sections,
512514
refined_sections, remove_nan, non_deformed_sections,
513515
mass, gamma_tip, inertia_tensor, center_of_mass, radius,
514516
le_interp, te_interp, area_interp, zeros(n_panels), zeros(n_panels), cache)

src/wing_geometry.jl

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ end
194194
Represents a wing composed of multiple sections with aerodynamic properties.
195195
196196
# Fields
197-
- `n_panels::Int64`: Number of panels in aerodynamic mesh
197+
- `n_panels::Int16`: Number of panels in aerodynamic mesh
198+
- `n_groups::Int16`: Number of panel groups
198199
- `spanwise_distribution`::PanelDistribution: [PanelDistribution](@ref)
199200
- `spanwise_direction::MVec3`: Wing span direction vector
200201
- `sections::Vector{Section}`: Vector of wing sections, see: [Section](@ref)
@@ -203,7 +204,8 @@ Represents a wing composed of multiple sections with aerodynamic properties.
203204
204205
"""
205206
mutable struct Wing <: AbstractWing
206-
n_panels::Int64
207+
n_panels::Int16
208+
n_groups::Int16
207209
spanwise_distribution::PanelDistribution
208210
panel_props::PanelProperties
209211
spanwise_direction::MVec3
@@ -214,6 +216,7 @@ end
214216

215217
"""
216218
Wing(n_panels::Int;
219+
n_groups=n_panels,
217220
spanwise_distribution::PanelDistribution=LINEAR,
218221
spanwise_direction::PosVector=MVec3([0.0, 1.0, 0.0]),
219222
remove_nan::Bool=true)
@@ -222,17 +225,19 @@ Constructor for a [Wing](@ref) struct with default values that initializes the s
222225
and refined sections as empty arrays.
223226
224227
# Parameters
225-
- `n_panels::Int64`: Number of panels in aerodynamic mesh
228+
- `n_panels::Int`: Number of panels in aerodynamic mesh
229+
- `n_groups::Int`: Number of panel groups in aerodynamic mesh
226230
- `spanwise_distribution`::PanelDistribution = LINEAR: [PanelDistribution](@ref)
227231
- `spanwise_direction::MVec3` = MVec3([0.0, 1.0, 0.0]): Wing span direction vector
228232
- `remove_nan::Bool`: Wether to remove the NaNs from interpolations or not
229233
"""
230234
function Wing(n_panels::Int;
235+
n_groups = n_panels,
231236
spanwise_distribution::PanelDistribution=LINEAR,
232237
spanwise_direction::PosVector=MVec3([0.0, 1.0, 0.0]),
233238
remove_nan=true)
234239
panel_props = PanelProperties{n_panels}()
235-
Wing(n_panels, spanwise_distribution, panel_props, spanwise_direction, Section[], Section[], remove_nan)
240+
Wing(n_panels, n_groups, spanwise_distribution, panel_props, spanwise_direction, Section[], Section[], remove_nan)
236241
end
237242

238243
function init!(wing::AbstractWing)

test/runtests.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@ end::Bool
1919
cd("..")
2020
println("Running tests...")
2121
@testset verbose = true "Testing VortexStepMethod..." begin
22+
23+
cp("data/ram_air_kite_body.obj", "/tmp/ram_air_kite_body.obj"; force=true)
24+
cp("data/ram_air_kite_foil.dat", "/tmp/ram_air_kite_foil.dat"; force=true)
25+
ram_wing = RamAirWing("/tmp/ram_air_kite_body.obj", "/tmp/ram_air_kite_foil.dat"; alpha_range=deg2rad.(-1:1), delta_range=deg2rad.(-1:1))
26+
2227
if build_is_production_build
2328
include("bench.jl")
2429
end
2530
include("test_bound_filament.jl")
2631
include("test_panel.jl")
2732
include("test_semi_infinite_filament.jl")
2833
include("test_body_aerodynamics.jl")
34+
include("test_results.jl")
2935
include("test_kite_geometry.jl")
3036
include("test_wing_geometry.jl")
3137
include("test_plotting.jl")

test/test_body_aerodynamics.jl

Lines changed: 0 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -113,140 +113,6 @@ include("utils.jl")
113113
end
114114

115115

116-
@testset "Calculate results against output results" begin
117-
# Setup
118-
density = 1.225
119-
N = 40
120-
max_chord = 1.0
121-
span = 15.709 # AR = 20
122-
v_a = 20.0
123-
AR = span^2 /* span * max_chord / 4)
124-
aoa = deg2rad(5)
125-
v_a = [cos(aoa), 0.0, sin(aoa)] .* v_a
126-
model = VSM
127-
128-
# Setup wing geometry
129-
dist = "cos"
130-
core_radius_fraction = 1e-20
131-
coord = generate_coordinates_el_wing(max_chord, span, N, dist)
132-
coord_left_to_right = flip_created_coord_in_pairs(deepcopy(coord))
133-
wing = Wing(N; spanwise_distribution=UNCHANGED)
134-
for idx in 1:2:length(coord_left_to_right[:, 1])
135-
@debug "coord_left_to_right[$idx] = $(coord_left_to_right[idx,:])"
136-
add_section!(
137-
wing,
138-
coord_left_to_right[idx,:],
139-
coord_left_to_right[idx+1,:],
140-
INVISCID
141-
)
142-
end
143-
144-
body_aero = BodyAerodynamics([wing])
145-
set_va!(body_aero, v_a)
146-
147-
# Run analysis
148-
P = length(body_aero.panels)
149-
loop_solver = Solver{P}(
150-
aerodynamic_model_type=model,
151-
core_radius_fraction=core_radius_fraction,
152-
solver_type=LOOP,
153-
atol=1e-8,
154-
rtol=1e-8
155-
)
156-
nonlin_solver = Solver{P}(
157-
aerodynamic_model_type=model,
158-
core_radius_fraction=core_radius_fraction,
159-
solver_type=NONLIN,
160-
atol=1e-8,
161-
rtol=1e-8
162-
)
163-
results_NEW = solve(loop_solver, body_aero; reference_point=[0,1,0])
164-
# println(results_NEW)
165-
166-
@test results_NEW isa Dict
167-
168-
@testset "Loop and nonlin solve!" begin
169-
loop_sol = solve!(loop_solver, body_aero; reference_point=[0,1,0])
170-
nonlin_sol = solve!(nonlin_solver, body_aero; reference_point=[0,1,0])
171-
172-
@test all(isapprox.(nonlin_sol.gamma_distribution, loop_sol.gamma_distribution; atol=1e-4))
173-
174-
@test loop_sol.force.x -117.96518414816444 atol=1e-4
175-
@test loop_sol.force.y 0.0 atol=1e-10
176-
@test loop_sol.force.z 1481.996390329679 atol=1e-4 rtol= 1e-4
177-
178-
@test loop_sol.moment.x -1481.996390329678 atol=1e-4 rtol= 1e-4
179-
@test loop_sol.moment.y 0.0 atol=1e-10
180-
@test loop_sol.moment.z -117.9651841481644 atol=1e-4
181-
182-
@test loop_sol.force_coefficients[1] -0.039050322560956294 atol=1e-4 # CFx
183-
@test loop_sol.force_coefficients[2] 0.0 atol=1e-4 # CFy
184-
@test loop_sol.force_coefficients[3] 0.49055973654418716 atol=1e-4 # CFz
185-
@test loop_sol.force_coefficients[3] / loop_sol.force_coefficients[1] loop_sol.force[3] / loop_sol.force[1]
186-
@test loop_sol.moment_distribution[1] -0.0006683569356186426 atol=1e-8
187-
@test loop_sol.moment_coeff_dist[1] -2.212405554436003e-7 atol=1e-10
188-
@test loop_sol.moment_distribution[1] / loop_sol.moment_distribution[2] loop_sol.moment_coeff_dist[1] / loop_sol.moment_coeff_dist[2]
189-
190-
@test loop_sol.solver_status == FEASIBLE
191-
end
192-
193-
# Calculate forces using uncorrected alpha
194-
alpha = results_NEW["alpha_uncorrected"]
195-
dyn_visc = 0.5 * density * norm(v_a)^2
196-
n_panels = length(body_aero.panels)
197-
lift = zeros(n_panels)
198-
drag = zeros(n_panels)
199-
moment = zeros(n_panels)
200-
201-
for (i, panel) in enumerate(body_aero.panels)
202-
lift[i] = dyn_visc * calculate_cl(panel, alpha[i]) * panel.chord
203-
cd_cm = calculate_cd_cm(panel, alpha[i])
204-
drag[i] = dyn_visc * cd_cm[1] * panel.chord
205-
moment[i] = dyn_visc * cd_cm[2] * panel.chord^2
206-
# @info "lift: $lift, drag: $drag, moment: $moment"
207-
end
208-
Fmag = hcat(lift, drag, moment)
209-
210-
# Calculate coefficients using corrected alpha
211-
alpha = results_NEW["alpha_at_ac"]
212-
aero_coeffs = hcat(
213-
[alpha[i] for (i, panel) in enumerate(body_aero.panels)],
214-
[calculate_cl(panel, alpha[i]) for (i, panel) in enumerate(body_aero.panels)],
215-
[calculate_cd_cm(panel, alpha[i])[1] for (i, panel) in enumerate(body_aero.panels)],
216-
[calculate_cd_cm(panel, alpha[i])[2] for (i, panel) in enumerate(body_aero.panels)]
217-
)
218-
219-
ringvec = [Dict("r0" => panel.width * panel.y_airf) for panel in body_aero.panels]
220-
controlpoints = [Dict("tangential" => panel.x_airf, "normal" => panel.z_airf)
221-
for panel in body_aero.panels]
222-
Atot = calculate_projected_area(wing)
223-
224-
F_rel_ref, F_gl_ref, Ltot_ref, Dtot_ref, CL_ref, CD_ref, CS_ref =
225-
output_results(Fmag, aero_coeffs, ringvec, v_a, controlpoints, Atot)
226-
227-
# Compare results
228-
@info "Comparing results"
229-
@info "cl_calculated: $(results_NEW["cl"]), CL_ref: $CL_ref"
230-
@info "cd_calculated: $(results_NEW["cd"]), CD_ref: $CD_ref"
231-
@info "cs_calculated: $(results_NEW["cs"]), CS_ref: $CS_ref"
232-
@info "L_calculated: $(results_NEW["lift"]), Ltot_ref: $Ltot_ref"
233-
@info "D_calculated: $(results_NEW["drag"]), Dtot_ref: $Dtot_ref"
234-
235-
# Assert results
236-
@test isapprox(results_NEW["cl"], CL_ref, rtol=1e-4)
237-
@test isapprox(results_NEW["cd"], CD_ref, rtol=1e-4)
238-
@test isapprox(results_NEW["cs"], CS_ref, rtol=1e-4)
239-
@test isapprox(results_NEW["lift"], Ltot_ref, rtol=1e-4)
240-
@test isapprox(results_NEW["drag"], Dtot_ref, rtol=1e-4)
241-
@test isapprox(results_NEW["Fx"], results_NEW["Mz"], rtol=1e-4) # 1 meter arm
242-
@test isapprox(results_NEW["My"], 0.0, atol=1e-3)
243-
@test isapprox(results_NEW["Fz"], -results_NEW["Mx"], rtol=1e-4) # 1 meter arm
244-
245-
# Check array shapes
246-
@test length(results_NEW["cl_distribution"]) == length(body_aero.panels)
247-
@test length(results_NEW["cd_distribution"]) == length(body_aero.panels)
248-
end
249-
250116
@testset "Wing Geometry Creation" begin
251117
@testset "Origin Translation" begin
252118
# Create minimal wing with three sections (2 panels)

test/test_plotting.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,7 @@ plt.ioff()
103103
rm("/tmp/Rectangular_Wing_Polars.pdf")
104104

105105
# Step 9: Test polar data plotting
106-
cp("data/ram_air_kite_body.obj", "/tmp/ram_air_kite_body.obj"; force=true)
107-
cp("data/ram_air_kite_foil.dat", "/tmp/ram_air_kite_foil.dat"; force=true)
108-
wing = RamAirWing("/tmp/ram_air_kite_body.obj", "/tmp/ram_air_kite_foil.dat"; alpha_range=deg2rad.(-1:1), delta_range=deg2rad.(-1:1))
109-
body_aero = BodyAerodynamics([wing])
106+
body_aero = BodyAerodynamics([ram_wing])
110107
fig = plot_polar_data(body_aero; is_show=false)
111108
@test fig isa plt.PyPlot.Figure
112109
end

0 commit comments

Comments
 (0)