Skip to content

Commit e2cf69f

Browse files
committed
code runs but doesnt converge
1 parent bb8dddd commit e2cf69f

File tree

5 files changed

+98
-56
lines changed

5 files changed

+98
-56
lines changed

src/VortexStepMethod.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ using DelimitedFiles
99
using Plots
1010
using Measures
1111
using LaTeXStrings
12+
using NonlinearSolve
13+
using Interpolations: linear_interpolation
1214

1315
# Export public interface
14-
export Wing, Section
16+
export Wing, Section, KiteWing
1517
export WingAerodynamics
1618
export Solver, solve
1719
export calculate_results, solve_circulation_distribution
@@ -34,16 +36,17 @@ Position vector, either a `MVec3` or a `Vector` for use in function signatures.
3436
const PosVector=Union{MVec3, Vector}
3537
const VelVector=Union{MVec3, Vector}
3638

39+
abstract type AbstractWing end
40+
3741
# Include core functionality
3842
include("wing_geometry.jl")
43+
include("kite_geometry.jl")
3944
include("filament.jl")
4045
include("panel.jl")
4146
include("wake.jl")
4247
include("wing_aerodynamics.jl")
4348
include("solver.jl")
4449

45-
include("init.jl")
46-
4750
# include plotting
4851
include("color_palette.jl")
4952
include("plotting.jl")

src/kite_geometry.jl

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function find_circle_center_and_radius(vertices)
6969
end
7070

7171
prob = NonlinearProblem(r_diff!, [z_min], nothing)
72-
result = solve(prob, NewtonRaphson(; autodiff=AutoFiniteDiff(; relstep = 1e-3, absstep = 1e-3)); abstol = 1e-2)
72+
result = NonlinearSolve.solve(prob, NewtonRaphson(; autodiff=AutoFiniteDiff(; relstep = 1e-3, absstep = 1e-3)); abstol = 1e-2)
7373
r_diff!(zeros(1), result, nothing)
7474
z = result[1]
7575

@@ -196,7 +196,7 @@ Represents a curved wing that inherits from Wing with additional geometric prope
196196
# Distribution types
197197
Same as Wing
198198
"""
199-
mutable struct KiteWing <: Wing
199+
mutable struct KiteWing <: AbstractWing
200200
n_panels::Int
201201
spanwise_panel_distribution::String
202202
spanwise_direction::Vector{Float64}
@@ -206,32 +206,57 @@ mutable struct KiteWing <: Wing
206206
mass::Float64
207207
center_of_mass::Vector{Float64}
208208
circle_center_z::Float64
209+
gamma_tip::Float64
209210
inertia_tensor::Matrix{Float64}
210211
radius::Float64
211212
le_interp::Function
212213
te_interp::Function
213214
area_interp::Function
214215

215-
function Wing(obj_path; mass=1.0, n_panels=54, spanwise_panel_distribution="linear", spanwise_direction=[0.0, 1.0, 0.0])
216+
function KiteWing(obj_path; mass=1.0, n_panels=54, spanwise_panel_distribution="linear", spanwise_direction=[0.0, 1.0, 0.0])
216217
!isapprox(spanwise_direction, [0.0, 1.0, 0.0]) && @error "Spanwise direction has to be [0.0, 1.0, 0.0]"
217218
if !isfile(obj_path)
218219
error("OBJ file not found: $obj_path")
219220
end
220221
vertices, faces = read_faces(obj_path)
221222
center_of_mass = calculate_com(vertices, faces)
222-
inertia_tensor = calculate_inertia_tensor(vertices, faces, wing_mass, com)
223+
inertia_tensor = calculate_inertia_tensor(vertices, faces, mass, center_of_mass)
223224

224225
circle_center_z, radius, gamma_tip = find_circle_center_and_radius(vertices)
225-
le_interp, te_interp, area_interp, gammas, max_xs, min_xs = create_interpolations(vertices, circle_center_z, radius, gamma_tip)
226-
le_interp = (γ) -> le_interp(γ)
227-
te_interp = (γ) -> te_interp(γ)
228-
area_interp = (γ) -> area_interp(γ)
226+
le_interp_, te_interp_, area_interp_, gammas, max_xs, min_xs = create_interpolations(vertices, circle_center_z, radius, gamma_tip)
227+
le_interp = (γ) -> le_interp_(γ)
228+
te_interp = (γ) -> te_interp_(γ)
229+
area_interp = (γ) -> area_interp_(γ)
229230

230231
sections = Section[]
231232
new(
232233
n_panels, spanwise_panel_distribution, spanwise_direction, sections,
233-
mass, center_of_mass, circle_center_z, inertia_tensor, radius,
234+
mass, center_of_mass, circle_center_z, gamma_tip, inertia_tensor, radius,
234235
le_interp, te_interp, area_interp
235236
)
236237
end
237238
end
239+
240+
"""
241+
add_section!(wing::KiteWing, LE_point::PosVector,
242+
TE_point::PosVector, aero_input::Vector{Any})
243+
244+
Add a new section to the wing.
245+
"""
246+
function add_section!(wing::KiteWing, gamma, aero_input; α=0.0)
247+
LE_point = [0.0, 0.0, wing.circle_center_z] .+ [wing.le_interp(gamma), sin(gamma) * wing.radius, cos(gamma) * wing.radius]
248+
if !isapprox(α, 0.0)
249+
local_y_vec = [0.0, sin(-gamma), cos(gamma)] × [1.0, 0.0, 0.0]
250+
TE_point = LE_point .+ rotate_v_around_k([wing.te_interp(gamma) - wing.le_interp(gamma), 0.0, 0.0], local_y_vec, α)
251+
else
252+
TE_point = LE_point .+ [wing.te_interp(gamma) - wing.le_interp(gamma), 0.0, 0.0]
253+
end
254+
push!(wing.sections, Section(LE_point, TE_point, aero_input))
255+
nothing
256+
end
257+
258+
function rotate_v_around_k(v, k, θ)
259+
k = normalize(k)
260+
v_rot = v * cos(θ) + (k × v) * sin(θ) + k * (k v) * (1 - cos(θ))
261+
return v_rot
262+
end

src/panel.jl

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,8 @@ function calculate_cl(panel::Panel, alpha::Float64)
248248
elseif panel.panel_aero_model == "polar_data"
249249
return linear_interpolation(
250250
panel.panel_polar_data[:,1],
251-
panel.panel_polar_data[:,2],
252-
alpha
253-
)
251+
panel.panel_polar_data[:,2]
252+
)(alpha)
254253
else
255254
throw(ArgumentError("Unsupported aero model: $(panel.panel_aero_model)"))
256255
end
@@ -274,14 +273,12 @@ function calculate_cd_cm(panel::Panel, alpha::Float64)
274273
elseif panel.panel_aero_model == "polar_data"
275274
cd = linear_interpolation(
276275
panel.panel_polar_data[:,1],
277-
panel.panel_polar_data[:,3],
278-
alpha
279-
)
276+
panel.panel_polar_data[:,3]
277+
)(alpha)
280278
cm = linear_interpolation(
281279
panel.panel_polar_data[:,1],
282-
panel.panel_polar_data[:,4],
283-
alpha
284-
)
280+
panel.panel_polar_data[:,4]
281+
)(alpha)
285282
return cd, cm
286283
else
287284
throw(ArgumentError("Unsupported aero model: $(panel.panel_aero_model)"))

src/wing_aerodynamics.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Main structure for calculating aerodynamic properties of wings.
77
mutable struct WingAerodynamics
88
panels::Vector{Panel}
99
n_panels::Int
10-
wings::Vector{Wing}
10+
wings::Vector{AbstractWing}
1111
_va::Union{Nothing, Vector{Float64}, Tuple{Vector{Float64}, Float64}}
1212
gamma_distribution::Union{Nothing, Vector{Float64}}
1313
alpha_uncorrected::Union{Nothing, Vector{Float64}}
@@ -19,10 +19,10 @@ mutable struct WingAerodynamics
1919
work_vectors::NTuple{10,Vector{Float64}}
2020

2121
function WingAerodynamics(
22-
wings::Vector{Wing};
22+
wings::Vector{T};
2323
aerodynamic_center_location::Float64=0.25,
2424
control_point_location::Float64=0.75
25-
)
25+
) where T <: AbstractWing
2626
# Initialize panels
2727
panels = Panel[]
2828
for wing in wings

src/wing_geometry.jl

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ Represents a wing section with leading edge, trailing edge, and aerodynamic prop
88
- `LE_point::Vector{Float64}`: Leading edge point coordinates
99
- `TE_point::Vector{Float64}`: Trailing edge point coordinates
1010
- `aero_input::Vector{Any}`: Aerodynamic input data for the section:
11-
- `["inviscid"]`: Inviscid aerodynamics
12-
- `["polar_data", [alpha,CL,CD,CM]]`: Polar data aerodynamics
13-
- `["lei_airfoil_breukels", [d_tube,camber]]`: LEI airfoil with Breukels parameters
11+
- `("inviscid")`: Inviscid aerodynamics
12+
- `("polar_data", [alpha_column,CL_column,CD_column,CM_column])`: Polar data aerodynamics
13+
- `("lei_airfoil_breukels", [d_tube,camber])`: LEI airfoil with Breukels parameters
1414
"""
1515
struct Section
1616
LE_point::Vector{Float64}
1717
TE_point::Vector{Float64}
18-
aero_input::Union{String, Tuple{String, Vector{Float64}}}
18+
aero_input::Union{String, Tuple{String, Vector{Float64}}, Tuple{String, Matrix{Float64}}}
1919

20-
function Section(LE_point::Vector{Float64}, TE_point::Vector{Float64}, aero_input::Union{String, Tuple{String, Vector{Float64}}})
20+
function Section(
21+
LE_point::Vector{Float64},
22+
TE_point::Vector{Float64},
23+
aero_input::Union{String, Tuple{String, Vector{Float64}}, Tuple{String, Matrix{Float64}}})
2124
new(LE_point, TE_point, aero_input)
2225
end
2326

@@ -45,7 +48,7 @@ Represents a wing composed of multiple sections with aerodynamic properties.
4548
- "split_provided": Split provided sections
4649
- "unchanged": Keep original sections
4750
"""
48-
mutable struct Wing
51+
mutable struct Wing <: AbstractWing
4952
n_panels::Int
5053
spanwise_panel_distribution::String
5154
spanwise_direction::Vector{Float64}
@@ -68,7 +71,7 @@ end
6871
Add a new section to the wing.
6972
"""
7073
function add_section!(wing::Wing, LE_point::Vector{Float64},
71-
TE_point::Vector{Float64}, aero_input::Union{String, Tuple{String, Vector{Float64}}})
74+
TE_point::Vector{Float64}, aero_input)
7275
push!(wing.sections, Section(LE_point, TE_point, aero_input))
7376
end
7477

@@ -92,14 +95,14 @@ end
9295

9396

9497
"""
95-
refine_aerodynamic_mesh(wing::Wing)
98+
refine_aerodynamic_mesh(wing::AbstractWing)
9699
97100
Refine the aerodynamic mesh of the wing based on spanwise panel distribution.
98101
99102
Returns:
100103
Vector{Section}: List of refined sections
101104
"""
102-
function refine_aerodynamic_mesh(wing::Wing)
105+
function refine_aerodynamic_mesh(wing::AbstractWing)
103106
# Sort sections from left to right
104107
sort!(wing.sections, by=s -> s.LE_point[2], rev=true)
105108

@@ -163,14 +166,22 @@ end
163166
164167
Interpolate aerodynamic coefficients to a common alpha range.
165168
"""
166-
function interpolate_to_common_alpha(alpha_common::Vector{Float64},
167-
alpha_orig::Vector{Float64},
168-
CL_orig::Vector{Float64},
169-
CD_orig::Vector{Float64},
170-
CM_orig::Vector{Float64})
171-
CL_common = interpolate(alpha_orig, CL_orig, alpha_common)
172-
CD_common = interpolate(alpha_orig, CD_orig, alpha_common)
173-
CM_common = interpolate(alpha_orig, CM_orig, alpha_common)
169+
function interpolate_to_common_alpha(alpha_common,
170+
alpha_orig,
171+
CL_orig,
172+
CD_orig,
173+
CM_orig)
174+
175+
# Create interpolation objects
176+
itp_CL = linear_interpolation(alpha_orig, CL_orig)
177+
itp_CD = linear_interpolation(alpha_orig, CD_orig)
178+
itp_CM = linear_interpolation(alpha_orig, CM_orig)
179+
180+
# Evaluate at common alpha points
181+
CL_common = itp_CL.(alpha_common)
182+
CD_common = itp_CD.(alpha_common)
183+
CM_common = itp_CM.(alpha_common)
184+
174185
return CL_common, CD_common, CM_common
175186
end
176187

@@ -182,7 +193,7 @@ end
182193
183194
Interpolate aerodynamic input between two sections.
184195
"""
185-
function calculate_new_aero_input(aero_input::Union{Vector{String}, Vector{Tuple{String, Vector{Float64}}}},
196+
function calculate_new_aero_input(aero_input,
186197
section_index::Int,
187198
left_weight::Float64,
188199
right_weight::Float64)
@@ -201,8 +212,14 @@ function calculate_new_aero_input(aero_input::Union{Vector{String}, Vector{Tuple
201212
polar_right = aero_input[section_index + 1][2]
202213

203214
# Unpack polar data
204-
alpha_left, CL_left, CD_left, CM_left = polar_left
205-
alpha_right, CL_right, CD_right, CM_right = polar_right
215+
@views begin
216+
alpha_left, CL_left, CD_left, CM_left = (
217+
polar_left[:, i] for i in 1:4
218+
)
219+
alpha_right, CL_right, CD_right, CM_right = (
220+
polar_right[:, i] for i in 1:4
221+
)
222+
end
206223

207224
# Create common alpha array
208225
alpha_common = sort(unique(vcat(alpha_left, alpha_right)))
@@ -220,7 +237,7 @@ function calculate_new_aero_input(aero_input::Union{Vector{String}, Vector{Tuple
220237
CD_interp = CD_left_common .* left_weight .+ CD_right_common .* right_weight
221238
CM_interp = CM_left_common .* left_weight .+ CM_right_common .* right_weight
222239

223-
return ("polar_data", [alpha_common, CL_interp, CD_interp, CM_interp])
240+
return ("polar_data", hcat(alpha_common, CD_interp, CL_interp, CM_interp))
224241

225242
elseif model_type == "lei_airfoil_breukels"
226243
tube_diameter_left = aero_input[section_index][2][1]
@@ -263,9 +280,9 @@ Returns:
263280
function refine_mesh_for_linear_cosine_distribution(
264281
spanwise_panel_distribution::String,
265282
n_sections::Int,
266-
LE::Union{Matrix{Float64}, Adjoint{Float64, Matrix{Float64}}},
267-
TE::Union{Matrix{Float64}, Adjoint{Float64, Matrix{Float64}}},
268-
aero_input::Union{Vector{String}, Vector{Tuple{String, Vector{Float64}}}})
283+
LE,
284+
TE,
285+
aero_input)
269286

270287
# 1. Compute quarter chord line
271288
quarter_chord = LE .+ 0.25 .* (TE .- LE)
@@ -408,14 +425,14 @@ end
408425

409426

410427
"""
411-
refine_mesh_by_splitting_provided_sections(wing::Wing)
428+
refine_mesh_by_splitting_provided_sections(wing::AbstractWing)
412429
413430
Refine mesh by splitting provided sections into desired number of panels.
414431
415432
Returns:
416433
Vector{Section}: Refined sections
417434
"""
418-
function refine_mesh_by_splitting_provided_sections(wing::Wing)
435+
function refine_mesh_by_splitting_provided_sections(wing::AbstractWing)
419436
n_sections_provided = length(wing.sections)
420437
n_panels_provided = n_sections_provided - 1
421438
n_panels_desired = wing.n_panels
@@ -491,14 +508,14 @@ function refine_mesh_by_splitting_provided_sections(wing::Wing)
491508
end
492509

493510
"""
494-
calculate_span(wing::Wing)
511+
calculate_span(wing::AbstractWing)
495512
496513
Calculate wing span along spanwise direction.
497514
498515
Returns:
499516
Float64: Wing span
500517
"""
501-
function calculate_span(wing::Wing)
518+
function calculate_span(wing::AbstractWing)
502519
# Normalize spanwise direction
503520
vector_axis = wing.spanwise_direction ./ norm(wing.spanwise_direction)
504521

@@ -512,14 +529,14 @@ function calculate_span(wing::Wing)
512529
end
513530

514531
"""
515-
calculate_projected_area(wing::Wing, z_plane_vector::Vector{Float64}=[0.0, 0.0, 1.0])
532+
calculate_projected_area(wing::AbstractWing, z_plane_vector::Vector{Float64}=[0.0, 0.0, 1.0])
516533
517534
Calculate projected wing area onto plane defined by normal vector.
518535
519536
Returns:
520537
Float64: Projected area
521538
"""
522-
function calculate_projected_area(wing::Wing,
539+
function calculate_projected_area(wing::AbstractWing,
523540
z_plane_vector::Vector{Float64}=[0.0, 0.0, 1.0])
524541
# Normalize plane normal vector
525542
z_plane_vector = z_plane_vector ./ norm(z_plane_vector)
@@ -557,8 +574,8 @@ function calculate_projected_area(wing::Wing,
557574
end
558575

559576
# Add span property to Wing struct
560-
Base.propertynames(w::Wing) = (fieldnames(typeof(w))..., :span)
561-
function Base.getproperty(w::Wing, s::Symbol)
577+
Base.propertynames(w::AbstractWing) = (fieldnames(typeof(w))..., :span)
578+
function Base.getproperty(w::AbstractWing, s::Symbol)
562579
if s === :span
563580
return calculate_span(w)
564581
else

0 commit comments

Comments
 (0)