Skip to content

Commit 4d07971

Browse files
committed
#155 V3_kite example now creates wing and solver from VSMSettings
1 parent cffe014 commit 4d07971

File tree

4 files changed

+150
-54
lines changed

4 files changed

+150
-54
lines changed
Lines changed: 88 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,91 @@
1-
Model:
2-
VSM: Vortex Step Method
3-
LLT: Lifting Line Theory
4-
PanelDistribution:
5-
LINEAR: Linear distribution
6-
COSINE: Cosine distribution
7-
COSINE_VAN_GARREL: van Garrel cosine distribution
8-
SPLIT_PROVIDED: Split provided sections
9-
UNCHANGED: Keep original sections
10-
InitialGammaDistribution:
11-
ELLIPTIC: Elliptic distribution
12-
ZEROS: Constant distribution
1+
# =============================================================================
2+
# VSM Settings Configuration File
3+
# =============================================================================
4+
#
5+
# This YAML file configures the Vortex Step Method (VSM) aerodynamic solver
6+
# for wing analysis. All simulation parameters are centralized here.
7+
#
8+
# FILE STRUCTURE:
9+
# ├── condition: Flight conditions (wind speed, angles, rates)
10+
# ├── wings: Wing geometry and discretization settings
11+
# └── solver_settings: Numerical solver parameters and convergence criteria
12+
#
13+
# AERODYNAMIC MODELS:
14+
# VSM: Vortex Step Method - Full 3D potential flow with wake modeling
15+
# LLT: Lifting Line Theory - Classical 1D approach for high aspect ratios
16+
#
17+
# PANEL DISTRIBUTIONS:
18+
# LINEAR: Uniform panel spacing along wingspan
19+
# COSINE: Cosine clustering (more panels at tips)
20+
# COSINE_VAN_GARREL: Van Garrel's modified cosine distribution
21+
# SPLIT_PROVIDED: Use predefined section splits from geometry
22+
# UNCHANGED: Preserve original geometry discretization
23+
#
24+
# INITIAL CIRCULATION DISTRIBUTIONS:
25+
# ELLIPTIC: Elliptical distribution (optimal for efficiency)
26+
# ZEROS: Start with zero circulation (cold start)
27+
#
28+
# SOLVER TYPES:
29+
# LOOP: Iterative fixed-point solver
30+
# NEWTON: Newton-Raphson nonlinear solver
31+
#
32+
# USAGE NOTES:
33+
# - n_panels should be divisible by n_groups for proper load balancing
34+
# - Higher n_panels improves accuracy but increases computation time
35+
# - Lower relaxation_factor if convergence issues occur
36+
#
37+
# =============================================================================
1338

39+
# =============================================================================
40+
# FLIGHT CONDITIONS
41+
# =============================================================================
42+
# Define the flight state for the aerodynamic analysis
43+
condition:
44+
wind_speed: 10.0 # [m/s] Free stream velocity magnitude
45+
alpha: 5.0 # [°] Angle of attack (pitch angle relative to flow)
46+
beta: 0.0 # [°] Sideslip angle (yaw angle relative to flow)
47+
yaw_rate: 0.0 # [°/s] Yaw rate (for dynamic analysis, 0 for static)
48+
49+
# =============================================================================
50+
# WING CONFIGURATION
51+
# =============================================================================
52+
# Define wing geometry files and discretization parameters
1453
wings:
15-
- name: main_wing
16-
n_panels: 40
17-
n_groups: 40
18-
spanwise_panel_distribution: LINEAR
19-
spanwise_direction: [0.0, 1.0, 0.0]
20-
remove_nan: true
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
61+
62+
# =============================================================================
63+
# SOLVER CONFIGURATION
64+
# =============================================================================
65+
# Numerical method settings and convergence criteria
2166
solver_settings:
22-
n_panels: 40
23-
n_groups: 40
24-
aerodynamic_model_type: VSM
25-
density: 1.225 # air density [kg/m³]
26-
max_iterations: 1500
27-
rtol: 1e-5 # relative error [-]
28-
tol_reference_error: 0.001
29-
relaxation_factor: 0.03 # relaxation factor for convergence
30-
artificial_damping: false # whether to apply artificial damping
31-
k2: 0.1 # artificial damping parameter
32-
k4: 0.0 # artificial damping parameter
33-
type_initial_gamma_distribution: ELLIPTIC
34-
core_radius_fraction: 1e-20
35-
mu: 1.81e-5 # dynamic viscosity [N·s/m²]
36-
calc_only_f_and_gamma: false # whether to only output f and gamma
67+
# --- Core Aerodynamic Model ---
68+
aerodynamic_model_type: VSM # VSM=3D vortex method, LLT=lifting line theory
69+
solver_type: LOOP # LOOP=fixed-point iteration, NEWTON=Newton-Raphson
70+
71+
# --- Physical Properties ---
72+
density: 1.225 # [kg/m³] Air density (ISA sea level)
73+
mu: 1.81e-5 # [N·s/m²] Dynamic viscosity (ISA sea level)
74+
75+
# --- Convergence Control ---
76+
max_iterations: 5000 # Maximum solver iterations before timeout
77+
rtol: 1e-6 # Relative tolerance for convergence
78+
tol_reference_error: 0.001 # Reference error tolerance
79+
relaxation_factor: 0.01 # [0.001-0.1] Under-relaxation for stability
80+
81+
# --- Numerical Stability ---
82+
artificial_damping: false # Enable artificial damping for unstable cases
83+
k2: 0.1 # 2nd-order damping coefficient
84+
k4: 0.0 # 4th-order damping coefficient
85+
core_radius_fraction: 1e-20 # Vortex core radius (fraction of chord)
86+
87+
# --- Initial Conditions ---
88+
type_initial_gamma_distribution: ELLIPTIC # Starting circulation distribution
89+
90+
# --- Output Control ---
91+
calc_only_f_and_gamma: false # true=compute only forces & circulation

data/TUDELFT_V3_KITE/geometry_CAD_CFD_polars_pchip_fitted.yaml renamed to data/TUDELFT_V3_KITE/wing_geometry_CAD_CFD_polars_pchip_fitted.yaml

File renamed without changes.

examples/V3_kite.jl

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@ using LinearAlgebra
22
using VortexStepMethod
33
using ControlPlots
44

5-
# --- User-specified parameters ---
6-
wind_speed = 3.05 # [m/s]
7-
angle_of_attack_deg = 5.0 # [deg]
8-
sideslip_deg = 0.0
9-
yaw_rate = 0.0 # [rad/s] (not used in static analysis)
10-
115
project_dir = dirname(dirname(pathof(VortexStepMethod))) # Go up one level from src to project root
12-
yaml_geometry_path = joinpath(project_dir, "data", "TUDELFT_V3_KITE", "geometry_CAD_CFD_polars_pchip_fitted.yaml")
6+
7+
# Load VSM settings from YAML configuration file
8+
settings = vs("TUDELFT_V3_KITE/vsm_settings.yaml")
9+
10+
# Extract flight conditions from settings
11+
wind_speed = settings.condition.wind_speed
12+
angle_of_attack_deg = settings.condition.alpha
13+
sideslip_deg = settings.condition.beta
14+
yaw_rate = settings.condition.yaw_rate
15+
16+
# Use wing geometry path from settings if provided, otherwise use default
17+
yaml_geometry_path = if !isempty(settings.wings[1].yaml_path)
18+
joinpath(project_dir, settings.wings[1].yaml_path)
19+
else
20+
joinpath(project_dir, "data", "TUDELFT_V3_KITE", "wing_geometry_CAD_CFD_polars_pchip_fitted.yaml")
21+
end
1322
literature_paths = [
1423
joinpath(project_dir, "data", "TUDELFT_V3_KITE", "literature_results","CFD_RANS_Rey_5e5_Poland2025_alpha_sweep_beta_0_NoStruts.csv"),
1524
joinpath(project_dir, "data", "TUDELFT_V3_KITE", "literature_results","CFD_RANS_Rey_10e5_Poland2025_alpha_sweep_beta_0.csv"),
@@ -19,23 +28,28 @@ literature_paths = [
1928
labels= [
2029
"Julia VSM 2D CFD PCHIP",
2130
"CFD RANS Re=5e5",
22-
"CFD RANS Re=10e5",
31+
"CFD RANS Re=10e5 (With Struts)",
2332
"Python VSM 2D CFD PCHIP Re=5e5",
24-
"Wind Tunnel Re=5e5"
33+
"Wind Tunnel Re=5e5 (With Struts)"
2534
]
2635

27-
# Create wing, body_aero, and solver objects
28-
wing = YamlWing(yaml_geometry_path; n_panels=36, spanwise_distribution=LINEAR)
36+
# Load VSM settings from YAML configuration file
37+
settings = vs("TUDELFT_V3_KITE/vsm_settings.yaml")
38+
39+
# Create wing, body_aero, and solver objects using settings
40+
wing = YamlWing(yaml_geometry_path;
41+
n_panels=settings.wings[1].n_panels,
42+
n_groups=settings.wings[1].n_groups,
43+
spanwise_distribution=settings.wings[1].spanwise_panel_distribution
44+
)
2945
body_aero = BodyAerodynamics([wing])
3046
solver = Solver(body_aero;
31-
aerodynamic_model_type=VSM,
32-
is_with_artificial_damping=false,
33-
solver_type=LOOP,
34-
density=1.225,
35-
max_iterations=5000,
36-
rtol = 1e-6,
37-
relaxation_factor=0.01,
38-
core_radius_fraction=1e-20,
47+
aerodynamic_model_type=settings.solver_settings.aerodynamic_model_type,
48+
density=settings.solver_settings.density,
49+
max_iterations=settings.solver_settings.max_iterations,
50+
rtol=settings.solver_settings.rtol,
51+
relaxation_factor=settings.solver_settings.relaxation_factor,
52+
core_radius_fraction=settings.solver_settings.core_radius_fraction,
3953
)
4054

4155
# Using plotting modules, to create more comprehensive plots
@@ -48,12 +62,12 @@ PLOT && plot_polars(
4862
[body_aero],
4963
labels,
5064
literature_path_list=literature_paths,
51-
angle_range=range(1, 20, length=20),
65+
angle_range=range(-5, 25, length=30),
5266
angle_type="angle_of_attack",
5367
angle_of_attack=angle_of_attack_deg,
5468
side_slip=sideslip_deg,
5569
v_a=wind_speed,
56-
title="$(wing.n_panels)_distribution_$(wing.spanwise_distribution)",
70+
title="$(wing.n_panels)_panels_$(wing.spanwise_distribution)_from_yaml_settings",
5771
data_type=".pdf",
5872
is_save=false,
5973
is_show=true,

src/settings.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
@with_kw mutable struct ConditionSettings
2+
wind_speed::Float64 = 10.0 # wind speed [m/s]
3+
alpha::Float64 = 5.0 # angle of attack [°]
4+
beta::Float64 = 0.0 # sideslip angle [°]
5+
yaw_rate::Float64 = 0.0 # yaw rate [°/s]
6+
end
7+
18
@with_kw mutable struct WingSettings
29
name::String = "main_wing"
10+
yaml_path::String = "" # path to wing geometry YAML file
311
n_panels::Int64 = 40
412
n_groups::Int64 = 40
513
spanwise_panel_distribution::PanelDistribution = LINEAR
@@ -11,6 +19,7 @@ end
1119
n_panels::Int64 = 40
1220
n_groups::Int64 = 40
1321
aerodynamic_model_type::Model = VSM
22+
solver_type::String = "LOOP" # type of solver
1423
density::Float64 = 1.225 # air density [kg/m³]
1524
max_iterations::Int64 = 1500
1625
rtol::Float64 = 1e-5 # relative error [-]
@@ -26,6 +35,7 @@ end
2635
end
2736

2837
@Base.kwdef mutable struct VSMSettings
38+
condition::ConditionSettings = ConditionSettings()
2939
wings::Vector{WingSettings} = []
3040
solver_settings::SolverSettings = SolverSettings()
3141
end
@@ -35,10 +45,23 @@ function vs(filename)
3545
data = YAML.load_file(joinpath("data", filename))
3646
n_panels = 0
3747
n_groups = 0
48+
49+
# Load condition settings if present
50+
if haskey(data, "condition")
51+
condition = data["condition"]
52+
res.condition.wind_speed = condition["wind_speed"]
53+
res.condition.alpha = condition["alpha"]
54+
res.condition.beta = condition["beta"]
55+
res.condition.yaw_rate = condition["yaw_rate"]
56+
end
57+
3858
# add and update wing settings
3959
for (i, wing) in pairs(data["wings"])
4060
push!(res.wings, WingSettings())
4161
res.wings[i].name = wing["name"]
62+
if haskey(wing, "yaml_path")
63+
res.wings[i].yaml_path = wing["yaml_path"]
64+
end
4265
res.wings[i].n_panels = wing["n_panels"]
4366
n_panels += res.wings[i].n_panels
4467
res.wings[i].n_groups = wing["n_groups"]
@@ -52,6 +75,9 @@ function vs(filename)
5275
res.solver_settings.n_panels = n_panels
5376
res.solver_settings.n_groups = n_groups
5477
res.solver_settings.aerodynamic_model_type = eval(Symbol(solver["aerodynamic_model_type"]))
78+
if haskey(solver, "solver_type")
79+
res.solver_settings.solver_type = solver["solver_type"]
80+
end
5581
res.solver_settings.density = solver["density"]
5682
res.solver_settings.max_iterations = solver["max_iterations"]
5783
res.solver_settings.rtol = solver["rtol"]
@@ -69,6 +95,7 @@ end
6995

7096
function Base.show(io::IO, vs::VSMSettings)
7197
println(io, "VSMSettings:")
98+
print(io, replace(repr(vs.condition), "\n" => "\n "))
7299
for (i, wing) in pairs(vs.wings)
73100
if i==1
74101
print(io, " ")

0 commit comments

Comments
 (0)