Skip to content

Commit 7a4cbea

Browse files
authored
Plot polars (#115)
* add xfoil and timers as normal dependency * add plotting function for polar data * fix aqua test * test bin plot * test without showing * improve gitignore * ignore right files * add latex kwarg
1 parent ab705db commit 7a4cbea

13 files changed

+165742
-98
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ Manifest.toml
22
.vscode/settings.json
33
venv
44
results/TUDELFT_V3_LEI_KITE/polars/$C_L$ vs $C_D$.pdf
5-
*.bin
5+
data/*.bin
66
results/TUDELFT_V3_LEI_KITE/polars/tutorial_testing_stall_model_n_panels_54_distribution_split_provided.pdf
77
docs/build/
88
results/TUDELFT_V3_LEI_KITE/polars/tutorial_testing_stall_model_n_panels_54_distribution_SPLIT_PROVIDED.pdf
9+
!test/data/*.bin

Project.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
1919
SharedArrays = "1a1011a3-84de-559e-8e89-a11a2f7dc383"
2020
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2121
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
22+
Timers = "21f18d07-b854-4dab-86f0-c15a3821819a"
23+
Xfoil = "19641d66-a62d-11e8-2441-8f57a969a9c4"
2224

2325
[weakdeps]
2426
ControlPlots = "23c2ee80-7a9e-4350-b264-8e670f12517c"
@@ -29,9 +31,9 @@ VortexStepMethodControlPlotsExt = "ControlPlots"
2931
[compat]
3032
Aqua = "0.8"
3133
BenchmarkTools = "1"
34+
CSV = "0.10"
3235
Colors = "0.13"
3336
ControlPlots = "0.2.5"
34-
CSV = "0.10"
3537
DataFrames = "1.7"
3638
DefaultApplication = "1"
3739
DelimitedFiles = "1"
@@ -49,8 +51,8 @@ Serialization = "1"
4951
SharedArrays = "1"
5052
StaticArrays = "1"
5153
Statistics = "1"
52-
Timers = "0.1"
5354
Test = "1"
55+
Timers = "0.1"
5456
Xfoil = "0.5"
5557
julia = "1.10, 1.11"
5658

@@ -63,8 +65,6 @@ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
6365
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
6466
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
6567
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
66-
Timers = "21f18d07-b854-4dab-86f0-c15a3821819a"
67-
Xfoil = "19641d66-a62d-11e8-2441-8f57a969a9c4"
6868

6969
[targets]
70-
test = ["Test", "DataFrames", "CSV", "Distributed", "Documenter", "Xfoil", "Timers", "BenchmarkTools", "ControlPlots", "Aqua"]
70+
test = ["Test", "DataFrames", "CSV", "Distributed", "Documenter", "BenchmarkTools", "ControlPlots", "Aqua"]

examples/ram_air_kite.jl

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
using ControlPlots
22
using VortexStepMethod
33
using LinearAlgebra
4-
using Pkg
5-
6-
if !("CSV" keys(Pkg.project().dependencies))
7-
using TestEnv
8-
TestEnv.activate()
9-
end
10-
using CSV
11-
using DataFrames
124

135
PLOT = true
146
USE_TEX = false
@@ -44,6 +36,9 @@ vel_app = [
4436
] * v_a
4537
set_va!(body_aero, vel_app)
4638

39+
# Plotting polar data
40+
PLOT && plot_polar_data(body_aero)
41+
4742
# Plotting geometry
4843
PLOT && plot_geometry(
4944
body_aero,

ext/VortexStepMethodControlPlotsExt.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ using ControlPlots, LaTeXStrings, VortexStepMethod, LinearAlgebra, Statistics, D
33
import ControlPlots: plt
44
import VortexStepMethod: calculate_filaments_for_plotting
55

6-
export plot_wing, plot_circulation_distribution, plot_geometry, plot_distribution, plot_polars, save_plot, show_plot
6+
export plot_wing, plot_circulation_distribution, plot_geometry, plot_distribution, plot_polars, save_plot, show_plot, plot_polar_data
77

88
include("../src/plotting.jl")
99

scripts/polars.jl

Lines changed: 5 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Distributed, Timers, Serialization, SharedArrays, StaticArrays
22
using Interpolations
33
using Xfoil
4-
using ControlPlots
54
using Logging
65

76
const SPEED_OF_SOUND = 343 # [m/s] at 20 °C, see: https://en.wikipedia.org/wiki/Speed_of_sound
@@ -133,42 +132,6 @@ try
133132
return lower_trailing_edge, upper_trailing_edge
134133
end
135134

136-
function replace_nan!(matrix)
137-
rows, cols = size(matrix)
138-
distance = max(rows, cols)
139-
for i in 1:rows
140-
for j in 1:cols
141-
if isnan(matrix[i, j])
142-
neighbors = []
143-
for d in 1:distance
144-
found = false
145-
if i-d >= 1 && !isnan(matrix[i-d, j]);
146-
push!(neighbors, matrix[i-d, j])
147-
found = true
148-
end
149-
if i+d <= rows && !isnan(matrix[i+d, j])
150-
push!(neighbors, matrix[i+d, j])
151-
found = true
152-
end
153-
if j-d >= 1 && !isnan(matrix[i, j-d])
154-
push!(neighbors, matrix[i, j-d])
155-
found = true
156-
end
157-
if j+d <= cols && !isnan(matrix[i, j+d])
158-
push!(neighbors, matrix[i, j+d])
159-
found = true
160-
end
161-
if found; break; end
162-
end
163-
if !isempty(neighbors)
164-
matrix[i, j] = sum(neighbors) / length(neighbors)
165-
end
166-
end
167-
end
168-
end
169-
return nothing
170-
end
171-
172135
kite_speed = v_wind
173136
chord_length = area / width
174137
local reynolds_number = kite_speed * chord_length / KINEMATIC_VISCOSITY # https://en.wikipedia.org/wiki/Reynolds_number
@@ -208,40 +171,12 @@ try
208171
cd_matrix = Matrix{Float64}(cd_matrix)
209172
cm_matrix = Matrix{Float64}(cm_matrix)
210173

174+
println("Generated lift matrix:")
211175
display(cl_matrix)
212-
213-
function plot_values(alphas, d_trailing_edge_angles, matrix, interp, name)
214-
fig = plt.figure()
215-
ax = fig.add_subplot(projection="3d")
216-
217-
X_data = collect(d_trailing_edge_angles) .+ zeros(length(alphas))'
218-
Y_data = collect(alphas)' .+ zeros(length(d_trailing_edge_angles))
219-
220-
matrix = Matrix{Float64}(matrix)
221-
interp_matrix = zeros(size(matrix)...)
222-
int_alphas, int_d_trailing_edge_angles = alphas .+ deg2rad(0.5), d_trailing_edge_angles .+ deg2rad(0.5)
223-
interp_matrix .= [interp(alpha, d_trailing_edge_angle) for alpha in int_alphas, d_trailing_edge_angle in int_d_trailing_edge_angles]
224-
X_int = collect(int_d_trailing_edge_angles) .+ zeros(length(int_alphas))'
225-
Y_int = collect(int_alphas)' .+ zeros(length(int_d_trailing_edge_angles))
226-
227-
ax.plot_wireframe(X_data, Y_data, matrix, edgecolor="royalblue", lw=0.5, rstride=5, cstride=5, alpha=0.6)
228-
ax.plot_wireframe(X_int, Y_int, interp_matrix, edgecolor="orange", lw=0.5, rstride=5, cstride=5, alpha=0.6)
229-
plt.xlabel("Alpha")
230-
plt.ylabel("Flap angle")
231-
plt.zlabel("$name values")
232-
plt.title("$name for different d_flap and angle")
233-
plt.legend()
234-
plt.grid(true)
235-
plt.show()
236-
end
237-
238-
cl_interp = extrapolate(scale(interpolate(cl_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
239-
cd_interp = extrapolate(scale(interpolate(cd_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
240-
cm_interp = extrapolate(scale(interpolate(cm_matrix, BSpline(Linear())), alphas, d_trailing_edge_angles), NaN)
241-
242-
plot_values(alphas, d_trailing_edge_angles, cl_matrix, cl_interp, "Cl")
243-
plot_values(alphas, d_trailing_edge_angles, cd_matrix, cd_interp, "Cd")
244-
plot_values(alphas, d_trailing_edge_angles, cm_matrix, cm_interp, "Cm")
176+
println("Generated drag matrix:")
177+
display(cd_matrix)
178+
println("Generated moment matrix:")
179+
display(cm_matrix)
245180

246181
@info "Relative trailing_edge height: $(upper - lower)"
247182
@info "Reynolds number for flying speed of $kite_speed is $reynolds_number"

src/VortexStepMethod.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export PanelDistribution, LINEAR, COSINE, COSINE_VAN_GARREL, SPLIT_PROVIDED, UNC
3131
export InitialGammaDistribution, ELLIPTIC, ZEROS
3232
export SolverStatus, FEASIBLE, INFEASIBLE, FAILURE
3333

34-
export plot_geometry, plot_distribution, plot_circulation_distribution, plot_geometry, plot_polars, save_plot, show_plot
34+
export plot_geometry, plot_distribution, plot_circulation_distribution, plot_geometry, plot_polars, save_plot, show_plot, plot_polar_data
3535

3636
# the following functions are defined in ext/VortexStepMethodExt.jl
3737
function plot_geometry end
@@ -41,6 +41,7 @@ function plot_geometry end
4141
function plot_polars end
4242
function save_plot end
4343
function show_plot end
44+
function plot_polar_data end
4445

4546
"""
4647
const MVec3 = MVector{3, Float64}

src/plotting.jl

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,4 +836,75 @@ function VortexStepMethod.plot_polars(
836836
end
837837

838838
return fig
839-
end
839+
end
840+
841+
"""
842+
plot_polar_data(body_aero::BodyAerodynamics; alphas=collect(deg2rad.(-5:0.3:25)), beta_tes=collect(deg2rad.(-5:0.3:25)))
843+
844+
Plot polar data (Cl, Cd, Cm) as 3D surfaces against alpha and beta_te angles. Beta_te is the trailing edge deflection angle
845+
relative to the 2d airfoil or panel chord line.
846+
847+
# Arguments
848+
- `body_aero`: Wing aerodynamics struct
849+
850+
# Keyword arguments
851+
- `alphas`: Range of angle of attack values in radians (default: -5° to 25° in 0.3° steps)
852+
- `beta_tes`: Range of trailing edge angles in radians (default: -5° to 25° in 0.3° steps)
853+
- `is_show`: Whether to display plots (default: true)
854+
- `use_tex`: if the external `pdflatex` command shall be used
855+
"""
856+
function VortexStepMethod.plot_polar_data(body_aero::BodyAerodynamics;
857+
alphas=collect(deg2rad.(-5:0.3:25)),
858+
beta_tes = collect(deg2rad.(-5:0.3:25)),
859+
is_show = true,
860+
use_tex = false
861+
)
862+
if body_aero.panels[1].aero_model === POLAR_MATRICES
863+
set_plot_style()
864+
865+
# Create figure with subplots
866+
fig = plt.figure(figsize=(15, 6))
867+
868+
# Get interpolation functions and labels
869+
interp_data = [
870+
(body_aero.panels[1].cl_interp, L"$C_l$"),
871+
(body_aero.panels[1].cd_interp, L"$C_d$"),
872+
(body_aero.panels[1].cm_interp, L"$C_m$")
873+
]
874+
875+
# Create each subplot
876+
for (idx, (interp, label)) in enumerate(interp_data)
877+
ax = fig.add_subplot(1, 3, idx, projection="3d")
878+
879+
# Create interpolation matrix
880+
interp_matrix = zeros(length(alphas), length(beta_tes))
881+
interp_matrix .= [interp(alpha, beta_te) for alpha in alphas, beta_te in beta_tes]
882+
X = collect(beta_tes) .+ zeros(length(alphas))'
883+
Y = collect(alphas)' .+ zeros(length(beta_tes))
884+
885+
# Plot surface
886+
ax.plot_wireframe(X, Y, interp_matrix,
887+
edgecolor="blue",
888+
lw=0.5,
889+
rstride=5,
890+
cstride=5,
891+
alpha=0.6)
892+
893+
# Set labels and title
894+
ax.set_xlabel(L"$\beta$ [rad]")
895+
ax.set_ylabel(L"$\alpha$ [rad]")
896+
ax.set_zlabel(label)
897+
ax.set_title(label * L" vs $\alpha$ and $\beta$")
898+
ax.grid(true)
899+
end
900+
901+
# Adjust layout and display
902+
plt.tight_layout(rect=(0.01, 0.01, 0.99, 0.99))
903+
if is_show
904+
show_plot(fig)
905+
end
906+
return fig
907+
else
908+
throw(ArgumentError("Plotting polar data for $(body_aero.panels[1].aero_model) is not implemented."))
909+
end
910+
end

test/aqua.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
using Aqua
2-
Aqua.test_all(VortexStepMethod)
2+
@testset "Aqua.jl" begin
3+
Aqua.test_all(
4+
VortexStepMethod;
5+
stale_deps=(ignore=[:Xfoil, :Timers],),
6+
)
7+
end

0 commit comments

Comments
 (0)