Skip to content

Commit 8942409

Browse files
committed
#155 working, with Wing constructor
1 parent dd659ca commit 8942409

File tree

7 files changed

+55
-138
lines changed

7 files changed

+55
-138
lines changed

data/TUDELFT_V3_KITE/vsm_settings.yaml

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,35 +33,24 @@
3333
# - n_panels should be divisible by n_groups for proper load balancing
3434
# - Higher n_panels improves accuracy but increases computation time
3535
# - Lower relaxation_factor if convergence issues occur
36-
#
37-
# =============================================================================
3836

39-
# =============================================================================
40-
# FLIGHT CONDITIONS
41-
# =============================================================================
4237
# Define the flight state for the aerodynamic analysis
4338
condition:
4439
wind_speed: 10.0 # [m/s] Free stream velocity magnitude
4540
alpha: 5.0 # [°] Angle of attack (pitch angle relative to flow)
4641
beta: 0.0 # [°] Sideslip angle (yaw angle relative to flow)
4742
yaw_rate: 0.0 # [°/s] Yaw rate (for dynamic analysis, 0 for static)
4843

49-
# =============================================================================
50-
# WING CONFIGURATION
51-
# =============================================================================
5244
# Define wing geometry files and discretization parameters
5345
wings:
54-
- name: V3_Kite # Wing identifier for output labeling
55-
yaml_path: data/TUDELFT_V3_KITE/wing_geometry_CAD_CFD_polars_pchip_fitted.yaml
56-
n_panels: 36 # Total number of panels along wingspan
57-
n_groups: 1 # Number of panel groups (must divide n_panels)
58-
spanwise_panel_distribution: LINEAR # Panel spacing algorithm
59-
spanwise_direction: [0.0, 1.0, 0.0] # Unit vector defining wingspan direction
60-
remove_nan: true # Remove NaN values from polar data
46+
- name: V3_Kite # Wing identifier for output labeling
47+
geometry_file: data/TUDELFT_V3_KITE/wing_geometry_CAD_CFD_polars_pchip_fitted.yaml
48+
n_panels: 36 # Total number of panels along wingspan
49+
n_groups: 1 # Number of panel groups (must divide n_panels)
50+
spanwise_panel_distribution: LINEAR # Panel spacing algorithm
51+
spanwise_direction: [0.0, 1.0, 0.0] # Unit vector defining wingspan direction
52+
remove_nan: true # Remove NaN values from polar data
6153

62-
# =============================================================================
63-
# SOLVER CONFIGURATION
64-
# =============================================================================
6554
# Numerical method settings and convergence criteria
6655
solver_settings:
6756
# --- Core Aerodynamic Model ---

examples/V3_kite.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ labels= [
3131
settings = vs("TUDELFT_V3_KITE/vsm_settings.yaml")
3232

3333
# Create wing, body_aero, and solver objects using settings
34-
wing = YamlWing(settings.wings[1].yaml_path;
34+
wing = YamlWing(settings.wings[1].geometry_file;
3535
n_panels=settings.wings[1].n_panels,
3636
n_groups=settings.wings[1].n_groups,
3737
spanwise_distribution=settings.wings[1].spanwise_panel_distribution

src/body_aerodynamics.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,24 @@ Main structure for calculating aerodynamic properties of bodies. Use the constru
1818
- `work_vectors`::NTuple{10, MVec3} = ntuple(_ -> zeros(MVec3), 10)
1919
- `AIC::Array{Float64, 3}` = zeros(3, P, P)
2020
- `projected_area::Float64` = 1.0: The area projected onto the xy-plane of the kite body reference frame [m²]
21-
- `y::MVector{P, Float64}` = zeros(MVector{P, Float64})
21+
- `y::MVector{P, Float64}` = MVector{P,Float64}(zeros(P))
2222
- `cache::Vector{PreallocationTools.LazyBufferCache{typeof(identity), typeof(identity)}}` = [LazyBufferCache() for _ in 1:5]
2323
"""
2424
@with_kw mutable struct BodyAerodynamics{P}
2525
panels::Vector{Panel}
26-
wings::Union{Vector{Wing}, Vector{RamAirWing}, Vector{YamlWing}}
26+
wings::Union{Vector{Wing}, Vector{RamAirWing}}
2727
_va::MVec3 = zeros(MVec3)
2828
omega::MVec3 = zeros(MVec3)
29-
gamma_distribution::MVector{P, Float64} = zeros(MVector{P, Float64})
30-
alpha_uncorrected::MVector{P, Float64} = zeros(MVector{P, Float64})
31-
alpha_corrected::MVector{P, Float64} = zeros(MVector{P, Float64})
32-
stall_angle_list::MVector{P, Float64} = zeros(MVector{P, Float64})
33-
alpha_array::MVector{P, Float64} = zeros(MVector{P, Float64})
34-
v_a_array::MVector{P, Float64} = zeros(MVector{P, Float64})
29+
gamma_distribution::MVector{P, Float64} = zeros(P)
30+
alpha_uncorrected::MVector{P, Float64} = zeros(P)
31+
alpha_corrected::MVector{P, Float64} = zeros(P)
32+
stall_angle_list::MVector{P, Float64} = zeros(P)
33+
alpha_array::MVector{P, Float64} = zeros(P)
34+
v_a_array::MVector{P, Float64} = zeros(P)
3535
work_vectors::NTuple{10,MVec3} = ntuple(_ -> zeros(MVec3), 10)
3636
AIC::Array{Float64, 3} = zeros(3, P, P)
3737
projected_area::Float64 = one(Float64)
38-
y::MVector{P, Float64} = zeros(MVector{P, Float64})
38+
y::MVector{P, Float64} = zeros(P)
3939
cache::Vector{PreallocationTools.LazyBufferCache{typeof(identity), typeof(identity)}} = [LazyBufferCache() for _ in 1:5]
4040
end
4141

src/precompile.jl

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
@setup_workload begin
22
# Putting some things in `@setup_workload` instead of `@compile_workload` can reduce the size of the
33
# precompile file and potentially make loading faster.
4-
# list = [OtherType("hello"), OtherType("world!")]
5-
path = dirname(pathof(@__MODULE__))
6-
4+
75
@compile_workload begin
6+
# Minimal precompilation to avoid segfault
87
# all calls in this block will be precompiled, regardless of whether
98
# they belong to your package or not (on Julia 1.8 and higher)
10-
vss = vs(joinpath(path, "../data/vsm_settings_dual.yaml"))
9+
1110
# Step 1: Define wing parameters
12-
n_panels = 20 # Number of panels
13-
span = 20.0 # Wing span [m]
11+
n_panels = 2 # Reduced number of panels for faster precompilation
12+
span = 10.0 # Wing span [m]
1413
chord = 1.0 # Chord length [m]
15-
v_a = 20.0 # Magnitude of inflow velocity [m/s]
16-
density = 1.225 # Air density [kg/m³]
17-
alpha_deg = 30.0 # Angle of attack [degrees]
18-
alpha = deg2rad(alpha_deg)
1914

2015
# Step 2: Create wing geometry with linear panel distribution
2116
wing = Wing(n_panels, spanwise_distribution=LINEAR)
@@ -30,11 +25,8 @@
3025
[chord, -span/2, 0.0], # Right tip TE
3126
INVISCID)
3227

33-
# Step 3: Initialize aerodynamics
34-
body_aero::BodyAerodynamics = BodyAerodynamics([wing])
35-
36-
gamma_initial = zeros(length(body_aero.panels))
37-
calculate_circulation_distribution_elliptical_wing(gamma_initial, body_aero)
28+
# Step 3: Initialize aerodynamics (simplified)
29+
body_aero = BodyAerodynamics([wing])
3830

3931
nothing
4032
end

src/settings.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ end
77

88
@with_kw mutable struct WingSettings
99
name::String = "main_wing"
10-
yaml_path::String = "" # path to wing geometry YAML file
10+
geometry_file::String = "" # path to wing geometry YAML file
1111
n_panels::Int64 = 40
1212
n_groups::Int64 = 40
1313
spanwise_panel_distribution::PanelDistribution = LINEAR
@@ -59,8 +59,8 @@ function vs(filename)
5959
for (i, wing) in pairs(data["wings"])
6060
push!(res.wings, WingSettings())
6161
res.wings[i].name = wing["name"]
62-
if haskey(wing, "yaml_path")
63-
res.wings[i].yaml_path = wing["yaml_path"]
62+
if haskey(wing, "geometry_file")
63+
res.wings[i].geometry_file = wing["geometry_file"]
6464
end
6565
res.wings[i].n_panels = wing["n_panels"]
6666
n_panels += res.wings[i].n_panels

src/solver.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,23 @@ Struct for storing the solution of the [solve!](@ref) function. Must contain all
4747
moment::MVec3 = zeros(MVec3)
4848
force_coeffs::MVec3 = zeros(MVec3)
4949
moment_coeffs::MVec3 = zeros(MVec3)
50-
moment_dist::MVector{P, Float64} = zeros(MVector{P, Float64})
51-
moment_coeff_dist::MVector{P, Float64} = zeros(MVector{P, Float64})
52-
group_moment_dist::MVector{G, Float64} = zeros(MVector{G, Float64})
53-
group_moment_coeff_dist::MVector{G, Float64} = zeros(MVector{G, Float64})
50+
moment_dist::MVector{P, Float64} = zeros(P)
51+
moment_coeff_dist::MVector{P, Float64} = zeros(P)
52+
group_moment_dist::MVector{G, Float64} = zeros(G)
53+
group_moment_coeff_dist::MVector{G, Float64} = zeros(G)
5454
solver_status::SolverStatus = FAILURE
5555
end
5656

5757
# Output of the function gamma_loop!
5858
@with_kw mutable struct LoopResult{P}
5959
converged::Bool = false
60-
gamma_new::MVector{P, Float64} = zeros(MVector{P, Float64})
61-
alpha_array::MVector{P, Float64} = zeros(MVector{P, Float64}) # TODO: Is this different from BodyAerodynamics.alpha_array ?
62-
v_a_array::MVector{P, Float64} = zeros(MVector{P, Float64})
60+
gamma_new::MVector{P, Float64} = zeros(P)
61+
alpha_array::MVector{P, Float64} = zeros(P) # TODO: Is this different from BodyAerodynamics.alpha_array ?
62+
v_a_array::MVector{P, Float64} = zeros(P)
6363
end
6464

6565
@with_kw struct BaseResult{P}
66-
va_norm_array::MVector{P, Float64} = zeros(MVector{P, Float64})
66+
va_norm_array::MVector{P, Float64} = zeros(P)
6767
va_unit_array::Matrix{Float64} = zeros(P, 3)
6868
end
6969

src/yaml_geometry.jl

Lines changed: 20 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,4 @@
1-
"""
2-
@with_kw mutable struct AirfoilSettings
3-
4-
Configuration settings for airfoils loaded from YAML files.
5-
6-
This struct stores the mapping between airfoil IDs and their aerodynamic data sources,
7-
typically CSV files containing polar data. It preserves the original YAML configuration
8-
for reference and enables reconstruction of the wing geometry from YAML specifications.
9-
10-
# Fields
11-
- `airfoil_id::Int64`: Unique identifier for the airfoil section
12-
- `type::String`: Type of aerodynamic data (e.g., "polars", "inviscid")
13-
- `info_dict::Dict{String, Any}`: Additional configuration data, typically containing
14-
file paths to CSV polar data files and other airfoil-specific parameters
15-
16-
# Example
17-
```julia
18-
# Typical usage when parsing YAML wing configuration
19-
settings = AirfoilSettings(
20-
airfoil_id = 1,
21-
type = "polars",
22-
info_dict = Dict("csv_file_path" => "polars/airfoil_1.csv")
23-
)
24-
```
25-
"""
26-
@with_kw mutable struct AirfoilSettings
27-
airfoil_id::Int64
28-
type::String
29-
info_dict::Dict{String, Any}
30-
end
311

32-
"""
33-
YamlWing <: AbstractWing
34-
35-
A wing model created from YAML configuration files with CSV polar data.
36-
37-
## Core Features
38-
- Wing geometry defined through YAML section coordinates
39-
- Aerodynamic properties based on CSV polar data files
40-
- Support for multiple airfoil types per wing
41-
- Configurable panel distribution and geometry parameters
42-
43-
## Notable Fields
44-
- `n_panels::Int16`: Number of panels in aerodynamic mesh
45-
- `n_groups::Int16`: Number of control groups
46-
- `spanwise_distribution::PanelDistribution`: Panel distribution type
47-
- `sections::Vector{Section}`: Wing cross-sections with aerodynamic data
48-
- `airfoil_settings::Vector{AirfoilSettings}`: Airfoil configuration data
49-
50-
See constructor `YamlWing(yaml_path; kwargs...)` for usage details.
51-
"""
52-
mutable struct YamlWing <: AbstractWing
53-
n_panels::Int16
54-
n_groups::Int16
55-
spanwise_distribution::PanelDistribution
56-
panel_props::PanelProperties
57-
spanwise_direction::MVec3
58-
sections::Vector{Section}
59-
refined_sections::Vector{Section}
60-
remove_nan::Bool
61-
62-
# Essential YAML-specific fields
63-
airfoil_settings::Vector{AirfoilSettings}
64-
end
652

663
"""
674
load_polar_data(csv_file_path)
@@ -124,7 +61,7 @@ end
12461

12562

12663
"""
127-
YamlWing(yaml_path; kwargs...)
64+
YamlWing(geometry_file; kwargs...)
12865
12966
Create a wing model from YAML configuration file with CSV polar data.
13067
@@ -135,7 +72,7 @@ This constructor builds a complete aerodynamic model by:
13572
4. Setting up panel distribution and geometric properties
13673
13774
# Arguments
138-
- `yaml_path`: Path to YAML file containing wing geometry and airfoil specifications
75+
- `geometry_file`: Path to YAML file containing wing geometry and airfoil specifications
13976
14077
# Keyword Arguments
14178
- `n_panels=20`: Number of aerodynamic panels across wingspan
@@ -146,7 +83,7 @@ This constructor builds a complete aerodynamic model by:
14683
- `prn=true`: Print info messages during construction
14784
14885
# Returns
149-
A fully initialized `YamlWing` instance ready for aerodynamic simulation.
86+
A fully initialized `Wing` instance ready for aerodynamic simulation.
15087
15188
# Example YAML format
15289
```yaml
@@ -176,7 +113,7 @@ wing = YamlWing(
176113
```
177114
"""
178115
function YamlWing(
179-
yaml_path;
116+
geometry_file;
180117
n_panels=20,
181118
n_groups=1,
182119
spanwise_distribution=LINEAR,
@@ -187,27 +124,30 @@ function YamlWing(
187124
!(n_panels % n_groups == 0) && throw(ArgumentError("Number of panels should be divisible by number of groups"))
188125
!isapprox(spanwise_direction, [0.0, 1.0, 0.0]) && throw(ArgumentError("Spanwise direction has to be [0.0, 1.0, 0.0], not $spanwise_direction"))
189126

190-
prn && @info "Reading YAML wing configuration from $yaml_path"
127+
prn && @info "Reading YAML wing configuration from $geometry_file"
191128

192129
# Read and parse YAML file
193-
yaml_data = YAML.load_file(yaml_path)
130+
yaml_data = YAML.load_file(geometry_file)
194131

195132
# Parse airfoils and create CSV file mapping
196133
airfoil_csv_map = Dict{Int64, String}()
197-
airfoil_settings = AirfoilSettings[]
198134

199135
for row in yaml_data["wing_airfoils"]["data"]
200136
airfoil_dict = Dict(zip(yaml_data["wing_airfoils"]["headers"], row))
201137
airfoil_id, airfoil_type, info_dict = airfoil_dict["airfoil_id"], airfoil_dict["type"], airfoil_dict["info_dict"]
202138

203-
push!(airfoil_settings, AirfoilSettings(airfoil_id, airfoil_type, info_dict))
204139
haskey(info_dict, "csv_file_path") && (airfoil_csv_map[airfoil_id] = info_dict["csv_file_path"])
205140
end
206141

207-
# Parse sections and create wing sections
208-
sections = Section[]
209-
refined_sections = Section[]
142+
# Create Wing using the standard constructor
143+
wing = Wing(n_panels;
144+
n_groups=n_groups,
145+
spanwise_distribution=spanwise_distribution,
146+
spanwise_direction=MVec3(spanwise_direction),
147+
remove_nan=remove_nan
148+
)
210149

150+
# Parse sections and populate wing
211151
for row in yaml_data["wing_sections"]["data"]
212152
section_dict = Dict(zip(yaml_data["wing_sections"]["headers"], row))
213153
airfoil_id = section_dict["airfoil_id"]
@@ -220,21 +160,17 @@ function YamlWing(
220160
csv_file_path = get(airfoil_csv_map, airfoil_id, "")
221161
if !isempty(csv_file_path) && !isabspath(csv_file_path)
222162
# Make relative paths relative to YAML file directory
223-
csv_file_path = joinpath(dirname(yaml_path), csv_file_path)
163+
csv_file_path = joinpath(dirname(geometry_file), csv_file_path)
224164
end
225165
aero_data, aero_model = load_polar_data(csv_file_path)
226166

227167
prn && println("Section airfoil_id $airfoil_id: Using $aero_model model")
228168

229-
section = Section(le_coord, te_coord, aero_model, aero_data)
230-
push!(sections, section)
231-
push!(refined_sections, Section(le_coord, te_coord, aero_model, aero_data))
169+
add_section!(wing, le_coord, te_coord, aero_model, aero_data)
232170
end
233171

234-
# Create YamlWing
235-
YamlWing(
236-
n_panels, n_groups, spanwise_distribution, PanelProperties{n_panels}(),
237-
MVec3(spanwise_direction), sections, refined_sections, remove_nan,
238-
airfoil_settings
239-
)
172+
# Initialize the wing after adding all sections
173+
reinit!(wing)
174+
175+
return wing
240176
end

0 commit comments

Comments
 (0)