Skip to content

Commit 2f78beb

Browse files
committed
Test all equally
1 parent 1fa9805 commit 2f78beb

6 files changed

Lines changed: 410 additions & 486 deletions

File tree

ext/VortexStepMethodControlPlotsExt.jl

Lines changed: 54 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -512,143 +512,6 @@ Generate polar data for aerodynamic analysis over a range of angles.
512512
# Returns
513513
- Tuple of polar data array and Reynolds number
514514
"""
515-
function generate_polar_data(
516-
solver,
517-
body_aero::BodyAerodynamics,
518-
angle_range;
519-
angle_type="angle_of_attack",
520-
angle_of_attack=0.0,
521-
side_slip=0.0,
522-
v_a=10.0,
523-
use_latex=false
524-
)
525-
_ = use_latex
526-
527-
n_panels = length(body_aero.panels)
528-
n_angles = length(angle_range)
529-
530-
# Initialize arrays
531-
cl = zeros(n_angles)
532-
cd = zeros(n_angles)
533-
cs = zeros(n_angles)
534-
cmx = fill(NaN, n_angles)
535-
cmy = fill(NaN, n_angles)
536-
cmz = fill(NaN, n_angles)
537-
gamma_distribution = zeros(n_angles, n_panels)
538-
cl_distribution = zeros(n_angles, n_panels)
539-
cd_distribution = zeros(n_angles, n_panels)
540-
cs_distribution = zeros(n_angles, n_panels)
541-
reynolds_number = zeros(n_angles)
542-
543-
for (i, angle_i) in enumerate(angle_range)
544-
# Set angle based on type
545-
if angle_type == "angle_of_attack"
546-
α = deg2rad(angle_i)
547-
β = side_slip
548-
elseif angle_type == raw"side_slip"
549-
α = angle_of_attack
550-
β = deg2rad(angle_i)
551-
else
552-
throw(ArgumentError(
553-
"angle_type must be 'angle_of_attack' or 'side_slip'"))
554-
end
555-
556-
# Update inflow conditions
557-
set_va!(
558-
body_aero,
559-
[
560-
cos(α) * cos(β),
561-
sin(β),
562-
sin(α)
563-
] * v_a
564-
)
565-
566-
# Solve and store results
567-
results = solve(solver, body_aero, gamma_distribution[i, :])
568-
569-
cl[i] = results["cl"]
570-
cd[i] = results["cd"]
571-
cs[i] = results["cs"]
572-
cmx[i] = get(results, "cmx", NaN)
573-
cmy[i] = get(results, "cmy", NaN)
574-
cmz[i] = get(results, "cmz", NaN)
575-
gamma_distribution[i, :] = results["gamma_distribution"]
576-
cl_distribution[i, :] = results["cl_distribution"]
577-
cd_distribution[i, :] = results["cd_distribution"]
578-
cs_distribution[i, :] = results["cs_distribution"]
579-
reynolds_number[i] = results["Rey"]
580-
end
581-
582-
polar_data = [
583-
angle_range,
584-
cl,
585-
cd,
586-
cs,
587-
gamma_distribution,
588-
cl_distribution,
589-
cd_distribution,
590-
cs_distribution,
591-
reynolds_number
592-
]
593-
594-
return (polar_data=polar_data, cmx=cmx, cmy=cmy, cmz=cmz,
595-
rey=reynolds_number[1])
596-
end
597-
598-
function _extract_literature_polar_data(raw_data, path;
599-
angle_type="angle_of_attack")
600-
table, header = if raw_data isa Tuple
601-
# readdlm(...; header=true) returns (data, header)
602-
raw_table, raw_header = raw_data
603-
raw_table, lowercase.(strip.(string.(vec(raw_header))))
604-
else
605-
# Header is in first row when a single matrix is returned
606-
raw_data[2:end, :], lowercase.(strip.(string.(raw_data[1, :])))
607-
end
608-
609-
# Find angle column based on angle_type
610-
alpha_idx = if angle_type == "side_slip"
611-
findfirst(
612-
x -> occursin("beta", x) ||
613-
occursin("side_slip", x), header)
614-
else
615-
findfirst(
616-
x -> occursin("alpha", x) || x == "aoa", header)
617-
end
618-
cl_idx = findfirst(x -> occursin("cl", x), header)
619-
cd_idx = findfirst(x -> occursin("cd", x), header)
620-
cs_idx = findfirst(x -> occursin("cs", x), header)
621-
cmx_idx = findfirst(x -> occursin("cmx", x), header)
622-
cmy_idx = findfirst(x -> occursin("cmy", x), header)
623-
cmz_idx = findfirst(x -> occursin("cmz", x), header)
624-
625-
(isnothing(alpha_idx) || isnothing(cl_idx) || isnothing(cd_idx)) &&
626-
throw(ArgumentError(
627-
"Literature CSV must contain alpha/aoa, cl and cd " *
628-
"columns: $path"))
629-
630-
n_rows = size(table, 1)
631-
cs_col = cs_idx === nothing ?
632-
zeros(n_rows) : table[:, cs_idx]
633-
cmx_col = cmx_idx === nothing ?
634-
fill(NaN, n_rows) : table[:, cmx_idx]
635-
cmy_col = cmy_idx === nothing ?
636-
fill(NaN, n_rows) : table[:, cmy_idx]
637-
cmz_col = cmz_idx === nothing ?
638-
fill(NaN, n_rows) : table[:, cmz_idx]
639-
640-
return (
641-
polar_data=[
642-
table[:, alpha_idx],
643-
table[:, cl_idx],
644-
table[:, cd_idx],
645-
cs_col
646-
],
647-
cmx=cmx_col,
648-
cmy=cmy_col,
649-
cmz=cmz_col
650-
)
651-
end
652515

653516
"""
654517
plot_polars(solver_list, body_aero_list, label_list;
@@ -712,7 +575,7 @@ function VortexStepMethod.plot_polars(
712575
polar_data_list = []
713576
cm_data_list = []
714577
for (i, (solver, body_aero)) in enumerate(zip(solver_list, body_aero_list))
715-
result = generate_polar_data(
578+
result = VortexStepMethod.generate_polar_data(
716579
solver, body_aero, angle_range;
717580
angle_type,
718581
angle_of_attack,
@@ -729,7 +592,7 @@ function VortexStepMethod.plot_polars(
729592
if !isempty(literature_path_list)
730593
for path in literature_path_list
731594
raw_data = readdlm(path, ',')
732-
lit = _extract_literature_polar_data(
595+
lit = VortexStepMethod.extract_literature_polar_data(
733596
raw_data, path; angle_type)
734597
push!(polar_data_list, lit.polar_data)
735598
push!(cm_data_list, (cmx=lit.cmx, cmy=lit.cmy,
@@ -965,6 +828,7 @@ function VortexStepMethod.plot_combined_analysis(
965828
body_aero,
966829
results;
967830
solver_label="VSM",
831+
labels=nothing,
968832
angle_range=range(0, 20, length=20),
969833
angle_type="angle_of_attack",
970834
angle_of_attack=0.0,
@@ -980,61 +844,79 @@ function VortexStepMethod.plot_combined_analysis(
980844
use_tex=false,
981845
literature_path_list=String[],
982846
cl_over_cd=true,
847+
angle_of_attack_for_spanwise_distribution=5.0,
983848
)
984849
# Normalize inputs to arrays for consistent handling
985850
solvers = solver isa Vector ? solver : [solver]
986851
body_aeros = body_aero isa Vector ? body_aero : [body_aero]
987852
results_list = results isa Vector ? results : [results]
988-
labels = solver_label isa Vector ? solver_label : [solver_label]
853+
n_solvers = length(solvers)
854+
n_literature = length(literature_path_list)
855+
856+
# Label normalization (matches Makie version)
857+
label_source = isnothing(labels) ? solver_label : labels
858+
labels_in = label_source isa AbstractVector ?
859+
string.(label_source) : [string(label_source)]
860+
solver_labels = length(labels_in) == 1 ?
861+
fill(labels_in[1], n_solvers) :
862+
labels_in[1:n_solvers]
863+
864+
# Compute spanwise results at specified AoA
865+
results_spanwise = copy(results_list)
866+
if !isnothing(angle_of_attack_for_spanwise_distribution)
867+
α_span = deg2rad(
868+
angle_of_attack_for_spanwise_distribution)
869+
β_span = deg2rad(side_slip)
870+
for (i, (s, ba)) in enumerate(
871+
zip(solvers, body_aeros))
872+
va_old = copy(getfield(ba, :_va))
873+
omega_old = copy(ba.omega)
874+
set_va!(ba, [cos(α_span) * cos(β_span),
875+
sin(β_span), sin(α_span)] * v_a)
876+
results_spanwise[i] = solve(s, ba,
877+
s.sol.gamma_distribution)
878+
set_va!(ba, va_old, omega_old)
879+
end
880+
end
989881

990-
# Extract y-coordinates for distribution plot (use first body_aero)
991-
body_y_coordinates = [panel.aero_center[2] for panel in body_aeros[1].panels]
992-
y_coords_list = [body_y_coordinates for _ in 1:length(solvers)]
882+
# Extract y-coordinates for distribution plot
883+
y_coords_list = [
884+
[p.aero_center[2] for p in ba.panels]
885+
for ba in body_aeros]
993886

994-
# Plot geometry (only use first body_aero)
887+
# Plot geometry (first body_aero only)
995888
plot_geometry(
996889
body_aeros[1],
997890
title;
998-
data_type=data_type,
999-
save_path=save_path,
1000-
is_save=is_save,
1001-
is_show=is_show,
1002-
view_elevation=view_elevation,
1003-
view_azimuth=view_azimuth,
1004-
use_tex=use_tex
891+
data_type, save_path, is_save, is_show,
892+
view_elevation, view_azimuth, use_tex
1005893
)
1006894

1007895
# Plot spanwise distributions
1008896
plot_distribution(
1009897
y_coords_list,
1010-
results_list,
1011-
labels;
898+
results_spanwise,
899+
solver_labels;
1012900
title=title * " - Distributions",
1013-
data_type=data_type,
1014-
save_path=save_path,
1015-
is_save=is_save,
1016-
is_show=is_show,
1017-
use_tex=use_tex
901+
data_type, save_path, is_save, is_show, use_tex
1018902
)
1019903

1020-
# Plot polars
904+
# Plot polars (include literature labels)
905+
polar_labels = if n_literature > 0 &&
906+
length(labels_in) == n_solvers + n_literature
907+
labels_in
908+
else
909+
solver_labels
910+
end
1021911
plot_polars(
1022912
solvers,
1023913
body_aeros,
1024-
labels;
1025-
literature_path_list=literature_path_list,
1026-
angle_range=angle_range,
1027-
angle_type=angle_type,
1028-
angle_of_attack=angle_of_attack,
1029-
side_slip=side_slip,
1030-
v_a=v_a,
914+
polar_labels;
915+
literature_path_list, angle_range, angle_type,
916+
angle_of_attack, side_slip, v_a,
1031917
title=title * " - Polars",
1032-
data_type=data_type,
1033-
save_path=save_path,
1034-
is_save=is_save,
1035-
is_show=is_show,
1036-
use_tex=use_tex,
1037-
cl_over_cd=cl_over_cd
918+
data_type, save_path, is_save, is_show,
919+
use_tex, cl_over_cd
1038920
)
1039921
end
1040922

0 commit comments

Comments
 (0)