Skip to content

Commit 773ecd6

Browse files
committed
working low allocation ram kite
1 parent e72739d commit 773ecd6

File tree

9 files changed

+189
-146
lines changed

9 files changed

+189
-146
lines changed

examples/bench.jl

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using LinearAlgebra
22
using ControlPlots
33
using VortexStepMethod
4+
using Interpolations
45
using BenchmarkTools
56

67
plot = true
@@ -17,15 +18,40 @@ alpha = deg2rad(alpha_deg)
1718
# Step 2: Create wing geometry with linear panel distribution
1819
wing = Wing(n_panels, spanwise_panel_distribution=:linear)
1920

20-
# Add wing sections - defining only tip sections with inviscid airfoil model
21+
# Test data generation
22+
n_angles = 5
23+
n_flaps = 5
24+
25+
# Define angle ranges
26+
alphas = range(-deg2rad(10), deg2rad(10), n_angles) # AoA range
27+
d_trailing_edge_angles = range(-deg2rad(30), deg2rad(30), n_flaps) # Flap deflection range
28+
29+
# Initialize coefficient matrices
30+
cl_matrix = zeros(n_angles, n_flaps)
31+
cd_matrix = zeros(n_angles, n_flaps)
32+
cm_matrix = zeros(n_angles, n_flaps)
33+
34+
# Fill matrices with realistic aerodynamic data
35+
for (i, α) in enumerate(alphas)
36+
for (j, δ) in enumerate(d_trailing_edge_angles)
37+
cl_matrix[i,j] = 2π * α + π/2 * δ
38+
cd_matrix[i,j] = 0.01 + 0.05 * α^2 + 0.03 * δ^2
39+
cm_matrix[i,j] = -0.1 * α - 0.2 * δ
40+
end
41+
end
42+
43+
cl_interp = extrapolate(scale(interpolate(cl_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
44+
cd_interp = extrapolate(scale(interpolate(cd_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
45+
cm_interp = extrapolate(scale(interpolate(cm_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
46+
2147
add_section!(wing,
2248
[0.0, span/2, 0.0], # Left tip LE
2349
[chord, span/2, 0.0], # Left tip TE
24-
:inviscid)
50+
(:interpolations, (cl_interp, cd_interp, cm_interp)))
2551
add_section!(wing,
2652
[0.0, -span/2, 0.0], # Right tip LE
2753
[chord, -span/2, 0.0], # Right tip TE
28-
:inviscid)
54+
(:interpolations, (cl_interp, cd_interp, cm_interp)))
2955

3056
# Step 3: Initialize aerodynamics
3157
wa = BodyAerodynamics([wing])
@@ -39,8 +65,9 @@ llt_solver = Solver(aerodynamic_model_type=:LLT)
3965
vsm_solver = Solver(aerodynamic_model_type=:VSM)
4066

4167
# Step 5: Solve using both methods
42-
@btime results_llt = solve($vsm_solver, $wa)
43-
@btime results_vsm = solve($vsm_solver, $wa)
68+
# @btime results_llt = solve($vsm_solver, $wa; log=false)
69+
# @btime results_vsm = solve($vsm_solver, $wa; log=false)
70+
@time results_vsm = solve(vsm_solver, wa; log=false)
4471
# time Python: 32.0 ms Ryzen 7950x
4572
# time Julia: 0.6 ms Ryzen 7950x
4673
# 0.8 ms laptop, performance mode, battery

examples/ram_air_kite.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ end
99
using CSV
1010
using DataFrames
1111

12-
plot = true
12+
plot = false
1313

1414
# Create wing geometry
1515
wing = KiteWing("data/ram_air_kite_body.obj", "data/ram_air_kite_foil.dat")

scripts/polars.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Distributed, Timers, Serialization, SharedArrays
1+
using Distributed, Timers, Serialization, SharedArrays, StaticArrays
22
using Interpolations
33
using Xfoil
44
using ControlPlots
@@ -204,6 +204,10 @@ try
204204
cl_matrix[:, j], cd_matrix[:, j], cm_matrix[:, j] = run_solve_alpha(alphas, d_trailing_edge_angles[j],
205205
reynolds_number, x, y, lower, upper, kite_speed, SPEED_OF_SOUND, x_turn)
206206
end
207+
cl_matrix = SMatrix{size(cl_matrix)...}(cl_matrix)
208+
cd_matrix = SMatrix{size(cd_matrix)...}(cd_matrix)
209+
cm_matrix = SMatrix{size(cm_matrix)...}(cm_matrix)
210+
207211
display(cl_matrix)
208212

209213
function plot_values(alphas, d_trailing_edge_angles, matrix, interp, name)
@@ -213,7 +217,8 @@ try
213217
X_data = collect(d_trailing_edge_angles) .+ zeros(length(alphas))'
214218
Y_data = collect(alphas)' .+ zeros(length(d_trailing_edge_angles))
215219

216-
interp_matrix = similar(matrix)
220+
matrix = Matrix{Float64}(matrix)
221+
interp_matrix = zeros(size(matrix)...)
217222
int_alphas, int_d_trailing_edge_angles = alphas .+ deg2rad(0.5), d_trailing_edge_angles .+ deg2rad(0.5)
218223
interp_matrix .= [interp(alpha, d_trailing_edge_angle) for alpha in int_alphas, d_trailing_edge_angle in int_d_trailing_edge_angles]
219224
X_int = collect(int_d_trailing_edge_angles) .+ zeros(length(int_alphas))'
@@ -241,7 +246,7 @@ try
241246
@info "Relative trailing_edge height: $(upper - lower)"
242247
@info "Reynolds number for flying speed of $kite_speed is $reynolds_number"
243248

244-
serialize(polar_path, (cl_interp, cd_interp, cm_interp))
249+
serialize(polar_path, (alphas, d_trailing_edge_angles, cl_matrix, cd_matrix, cm_matrix))
245250

246251
catch e
247252
@info "Removing processes"

src/VortexStepMethod.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ using ControlPlots
1010
using Measures
1111
using LaTeXStrings
1212
using NonlinearSolve
13-
using Interpolations: linear_interpolation, Line, Extrapolation
13+
using Interpolations
14+
using Interpolations: linear_interpolation, Line, Extrapolation, FilledExtrapolation
1415
using Serialization
1516
using SharedArrays
1617

src/kite_geometry.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,15 +241,15 @@ mutable struct KiteWing <: AbstractWing
241241
end
242242

243243
@info "Loding polars and kite info from $polar_path and $info_path"
244-
(cl_interp, cd_interp, cm_interp) = deserialize(polar_path)
244+
(alpha_range, beta_range, cl_matrix::SMatrix, cd_matrix::SMatrix, cm_matrix::SMatrix) = deserialize(polar_path)
245245

246246
(center_of_mass, inertia_tensor, circle_center_z, radius, gamma_tip,
247247
le_interp, te_interp, area_interp) = deserialize(info_path)
248248

249249
# Create sections
250250
sections = Section[]
251251
for gamma in range(-gamma_tip, gamma_tip, n_sections)
252-
aero_input = (:interpolations, (cl_interp, cd_interp, cm_interp))
252+
aero_input = (:polar_data, (alpha_range, beta_range, cl_matrix, cd_matrix, cm_matrix))
253253
LE_point = [0.0, 0.0, circle_center_z] .+ [le_interp(gamma), sin(gamma) * radius, cos(gamma) * radius]
254254
if !isapprox(alpha, 0.0)
255255
local_y_vec = [0.0, sin(-gamma), cos(gamma)] × [1.0, 0.0, 0.0]

src/panel.jl

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using LinearAlgebra
22

3+
const Interp1 = Interpolations.FilledExtrapolation{Float64, 1, Interpolations.GriddedInterpolation{Float64, 1, Vector{Float64}, Interpolations.Gridded{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{Vector{Float64}}}, Interpolations.Gridded{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Float64}
4+
const Interp2 = Interpolations.FilledExtrapolation{Float64, 2, Interpolations.ScaledInterpolation{Float64, 2, Interpolations.BSplineInterpolation{Float64, 2, Interpolations.OffsetArrays.OffsetMatrix{Float64, Matrix{Float64}}, Interpolations.BSpline{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{Base.Slice{UnitRange{Int64}}, Base.Slice{UnitRange{Int64}}}}, Interpolations.BSpline{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}}, Interpolations.BSpline{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Float64}
5+
36
"""
47
Panel
58
@@ -36,9 +39,9 @@ mutable struct Panel
3639
cl_coefficients::Vector{Float64}
3740
cd_coefficients::Vector{Float64}
3841
cm_coefficients::Vector{Float64}
39-
cl_interp::Function
40-
cd_interp::Function
41-
cm_interp::Function
42+
cl_interp::Union{Nothing, Interp1, Interp2}
43+
cd_interp::Union{Nothing, Interp1, Interp2}
44+
cm_interp::Union{Nothing, Interp1, Interp2}
4245
aerodynamic_center::MVec3
4346
control_point::MVec3
4447
bound_point_1::MVec3
@@ -82,45 +85,58 @@ mutable struct Panel
8285

8386
# Initialize aerodynamic properties
8487
cl_coeffs, cd_coeffs, cm_coeffs = zeros(3), zeros(3), zeros(3)
85-
cl_interp, cd_interp, cm_interp =::Float64)->0.0, (α::Float64)->0.0, (α::Float64)->0.0
8688

89+
# Calculate width
90+
width = norm(bound_point_2 - bound_point_1)
91+
92+
# Initialize filaments
93+
filaments = [
94+
BoundFilament(bound_point_2, bound_point_1),
95+
BoundFilament(bound_point_1, TE_point_1),
96+
BoundFilament(TE_point_2, bound_point_2)
97+
]
98+
8799
if aero_model === :lei_airfoil_breukels
88100
cl_coeffs, cd_coeffs, cm_coeffs = compute_lei_coefficients(section_1, section_2)
101+
89102
elseif aero_model === :polar_data
90103
aero_1 = section_1.aero_input[2]
91104
aero_2 = section_2.aero_input[2]
92-
if size(aero_1) != size(aero_2)
105+
if !all(size.(aero_1) .== size.(aero_2))
93106
throw(ArgumentError("Polar data must have same shape"))
94107
end
95-
polar_data = (aero_1 + aero_2) / 2
96-
cl_interp_ = linear_interpolation(polar_data[:,1], polar_data[:,2]; extrapolation_bc=NaN)
97-
cd_interp_ = linear_interpolation(polar_data[:,1], polar_data[:,3]; extrapolation_bc=NaN)
98-
cm_interp_ = linear_interpolation(polar_data[:,1], polar_data[:,4]; extrapolation_bc=NaN)
99-
cl_interp =::Float64) -> cl_interp_(α)
100-
cd_interp =::Float64) -> cd_interp_(α)
101-
cm_interp =::Float64) -> cm_interp_(α)
102-
elseif aero_model === :interpolations
103-
cl_left, cd_left, cm_left = section_1.aero_input[2]
104-
cl_right, cd_right, cm_right = section_2.aero_input[2]
105-
cl_interp = cl_left === cl_right ?::Float64) -> cl_left(α, 0.0) :
106-
::Float64) -> 0.5cl_left(α, 0.0) + 0.5cl_right(α, 0.0) # TODO: add trailing edge deflection
107-
cd_interp = cd_left === cd_right ?::Float64) -> cd_left(α, 0.0) :
108-
::Float64) -> 0.5cd_left(α, 0.0) + 0.5cd_right(α, 0.0)
109-
cm_interp = cm_left === cm_right ?::Float64) -> cm_left(α, 0.0) :
110-
::Float64) -> 0.5cm_left(α, 0.0) + 0.5cm_right(α, 0.0)
108+
109+
if length(aero_1) == 4
110+
!all(isapprox.(aero_1[1], aero_2[1])) && @error "Make sure you use the same alpha range for all your interpolations."
111+
polar_data = (
112+
(aero_1[2] + aero_2[2]) / 2,
113+
(aero_1[3] + aero_2[3]) / 2,
114+
(aero_1[4] + aero_2[4]) / 2
115+
)
116+
cl_interp = linear_interpolation(aero_1[1], polar_data[1]; extrapolation_bc=NaN)
117+
cd_interp = linear_interpolation(aero_1[1], polar_data[2]; extrapolation_bc=NaN)
118+
cm_interp = linear_interpolation(aero_1[1], polar_data[3]; extrapolation_bc=NaN)
119+
120+
elseif length(aero_1) == 5
121+
!all(isapprox.(aero_1[1], aero_2[1])) && @error "Make sure you use the same alpha range for all your interpolations."
122+
!all(isapprox.(aero_1[2], aero_2[2])) && @error "Make sure you use the same beta range for all your interpolations."
123+
124+
polar_data = (
125+
(aero_1[3] + aero_2[3]) / 2,
126+
(aero_1[4] + aero_2[4]) / 2,
127+
(aero_1[5] + aero_2[5]) / 2
128+
)
129+
cl_interp = linear_interpolation((aero_1[1], aero_1[2]), polar_data[1]; extrapolation_bc=NaN)
130+
cd_interp = linear_interpolation((aero_1[1], aero_1[2]), polar_data[2]; extrapolation_bc=NaN)
131+
cm_interp = linear_interpolation((aero_1[1], aero_1[2]), polar_data[3]; extrapolation_bc=NaN)
132+
# cl_interp = extrapolate(scale(interpolate(cl_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
133+
# cd_interp = extrapolate(scale(interpolate(cl_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
134+
# cm_interp = extrapolate(scale(interpolate(cl_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
135+
end
136+
111137
elseif !(aero_model === :inviscid)
112138
throw(ArgumentError("Unsupported aero model: $aero_model"))
113139
end
114-
115-
# Calculate width
116-
width = norm(bound_point_2 - bound_point_1)
117-
118-
# Initialize filaments
119-
filaments = [
120-
BoundFilament(bound_point_2, bound_point_1),
121-
BoundFilament(bound_point_1, TE_point_1),
122-
BoundFilament(TE_point_2, bound_point_2)
123-
]
124140

125141
new(
126142
TE_point_1, LE_point_1, TE_point_2, LE_point_2,
@@ -262,8 +278,12 @@ function calculate_cl(panel::Panel, alpha::Float64)::Float64
262278
end
263279
elseif panel.aero_model === :inviscid
264280
cl = 2π * alpha
265-
elseif panel.aero_model === :polar_data || panel.aero_model === :interpolations
266-
cl = panel.cl_interp(alpha)::Float64
281+
elseif panel.aero_model === :polar_data
282+
if isa(panel.cl_interp, Interp1)
283+
cl = panel.cl_interp(alpha)::Float64
284+
elseif isa(panel.cl_interp, Interp2)
285+
cl = panel.cl_interp(alpha, 0.0)::Float64
286+
end
267287
else
268288
throw(ArgumentError("Unsupported aero model: $(panel.aero_model)"))
269289
end
@@ -284,9 +304,14 @@ function calculate_cd_cm(panel::Panel, alpha::Float64)
284304
if abs(alpha) >/9) # Outside ±20 degrees
285305
cd = 2 * sin(alpha)^3
286306
end
287-
elseif panel.aero_model === :polar_data || panel.aero_model === :interpolations
288-
cd = panel.cd_interp(alpha)::Float64
289-
cm = panel.cm_interp(alpha)::Float64
307+
elseif panel.aero_model === :polar_data
308+
if isa(panel.cd_interp, Interp1)
309+
cd = panel.cd_interp(alpha)::Float64
310+
cm = panel.cm_interp(alpha)::Float64
311+
elseif isa(panel.cd_interp, Interp2)
312+
cd = panel.cd_interp(alpha, 0.0)::Float64
313+
cm = panel.cm_interp(alpha, 0.0)::Float64
314+
end
290315
elseif !(panel.aero_model === :inviscid)
291316
throw(ArgumentError("Unsupported aero model: $(panel.aero_model)"))
292317
end

src/solver.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function solve(solver::Solver, body_aero::BodyAerodynamics, gamma_distribution=n
127127
)
128128
# Try again with reduced relaxation factor if not converged
129129
if !converged && relaxation_factor > 1e-3
130-
@warn "Running again with half the relaxation_factor = $(relaxation_factor/2)"
130+
log && @warn "Running again with half the relaxation_factor = $(relaxation_factor/2)"
131131
converged, gamma_new, alpha_array, v_a_array = gamma_loop(
132132
solver,
133133
body_aero,
@@ -138,7 +138,8 @@ function solve(solver::Solver, body_aero::BodyAerodynamics, gamma_distribution=n
138138
y_airf_array,
139139
z_airf_array,
140140
panels,
141-
relaxation_factor/2
141+
relaxation_factor/2;
142+
log
142143
)
143144
end
144145

0 commit comments

Comments
 (0)