Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9196bce
Fix warnings
ufechner7 Apr 6, 2026
b5014f3
Fix warnings
ufechner7 Apr 7, 2026
4cb1bd1
Large fix to avoid a closure
ufechner7 Apr 7, 2026
75fe2f0
Fix warning
ufechner7 Apr 7, 2026
ffd4ab1
Fix warning
ufechner7 Apr 7, 2026
50fb311
Fix warning
ufechner7 Apr 7, 2026
9783c57
Fix error
ufechner7 Apr 7, 2026
ca1c57d
Fix warnings
ufechner7 Apr 7, 2026
24bc519
Fix warnings
ufechner7 Apr 7, 2026
b076469
Fix warnings
ufechner7 Apr 7, 2026
74b5378
Fix warning
ufechner7 Apr 11, 2026
3ae1d50
Suppress one message
ufechner7 Apr 11, 2026
13d8f74
Update test/Project.toml
ufechner7 Apr 11, 2026
ceea7d6
Fix warning
ufechner7 Apr 11, 2026
611d177
Fix warning
ufechner7 Apr 11, 2026
b212b0b
Fix warnings
ufechner7 Apr 11, 2026
21ebe19
Fix tests
ufechner7 Apr 11, 2026
f7b041e
Fix warnings
ufechner7 Apr 11, 2026
2343460
Fix warnings
ufechner7 Apr 11, 2026
f8d3d55
Fix warnings
ufechner7 Apr 11, 2026
b941732
Fix warnings
ufechner7 Apr 11, 2026
9d86d40
Fix warning
ufechner7 Apr 11, 2026
9f67197
Fixed multi-wing bug
ufechner7 Apr 11, 2026
15b1340
Fix set_va! with omega on multi-wing bod
ufechner7 Apr 11, 2026
bd7e854
Remove unused argument reference_point
ufechner7 Apr 11, 2026
f73eda8
Rename unused parameter to _p
ufechner7 Apr 11, 2026
d75cfa7
Fix Copilot remark
ufechner7 Apr 11, 2026
8a49e3d
Activate examples project in the examples
ufechner7 Apr 11, 2026
57b7de9
Add using SciMLBase
ufechner7 Apr 11, 2026
73814df
Do not export solve_base!
ufechner7 Apr 11, 2026
85bda52
Fix issue found by Copilot related to set_va!
ufechner7 Apr 11, 2026
801c411
Update test/solver/test_solver.jl
ufechner7 Apr 11, 2026
1c805c3
Fix docstring
ufechner7 Apr 11, 2026
8eedaa1
Fix allocations
ufechner7 Apr 11, 2026
f532fe7
Fix warnings
ufechner7 Apr 11, 2026
4d57ca5
Add package Pkg
ufechner7 Apr 11, 2026
831c7fc
Fix warnings
ufechner7 Apr 11, 2026
2ada45c
Fix warnings
ufechner7 Apr 11, 2026
cfe5a53
Fix warning
ufechner7 Apr 11, 2026
e49ad9b
Update default manifest
ufechner7 Apr 11, 2026
fd8829c
Update src/solver.jl
ufechner7 Apr 11, 2026
e944b82
Add file to .gitignore
ufechner7 Apr 11, 2026
e681da6
Update default manifest
ufechner7 Apr 11, 2026
f3c920e
Instantiate the environment
ufechner7 Apr 11, 2026
103a694
Next try
ufechner7 Apr 11, 2026
b3b7a57
Next try
ufechner7 Apr 11, 2026
9e8d381
Avoid closure
ufechner7 Apr 11, 2026
c405a7a
Increase timeout limit
ufechner7 Apr 11, 2026
b7d744f
Use workspaces
ufechner7 Apr 11, 2026
cbee7e8
Add jetls_examples
ufechner7 Apr 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .JETLSConfig.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,17 @@ formatter = "JuliaFormatter"
auto_instantiate = false # boolean, default: true

[diagnostic]
all_files = false # boolean, default: true
all_files = false # boolean, default: true

[[diagnostic.patterns]]
pattern = "no matching method found `copy!\\(::Random\\.TaskLocalRNG, ::Nothing\\)`"
match_by = "message"
match_type = "regex"
severity = "off"

[[diagnostic.patterns]]
pattern = "IncorrectCallArgs"
match_by = "code"
match_type = "literal"
severity = "off"
path = "src/solver.jl"
Comment thread
ufechner7 marked this conversation as resolved.
10 changes: 10 additions & 0 deletions bin/jetls
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
# SPDX-FileCopyrightText: 2025 Uwe Fechner
# SPDX-License-Identifier: MIT

cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
if [[ $(basename $(pwd)) == "bin" ]]; then
cd ..
fi

jetls check --root=. src/
42 changes: 21 additions & 21 deletions src/VortexStepMethod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,38 @@ using DefaultApplication
using Measures
using LaTeXStrings
using NonlinearSolve
import NonlinearSolve: solve!, solve
import NonlinearSolve: solve, solve!
using Interpolations
import Interpolations: Extrapolation
using Parameters
using Serialization
using Timers
using PreallocationTools
using PrecompileTools
using Pkg
using DifferentiationInterface
import SciMLBase: successful_retcode
import YAML
using StructMapping
using Xfoil

# Export public interface
export VSMSettings, WingSettings, SolverSettings
export Wing, Section, ObjWing, reinit!, refine!
export SolverSettings, VSMSettings, WingSettings
export ObjWing, Section, Wing, refine!, reinit!
export BodyAerodynamics
export Solver, solve, solve_base!, solve!, VSMSolution, linearize
export Solver, VSMSolution, linearize, solve, solve!, solve_base!
Comment thread
ufechner7 marked this conversation as resolved.
export calculate_results
export add_section!, set_va!
export calculate_span, calculate_projected_area
export calculate_projected_area, calculate_span
export MVec3
export Model, VSM, LLT
export AeroModel, LEI_AIRFOIL_BREUKELS, POLAR_VECTORS, POLAR_MATRICES, INVISCID
export PanelDistribution, LINEAR, COSINE, SPLIT_PROVIDED, UNCHANGED
export InitialGammaDistribution, ELLIPTIC, ZEROS
export SolverStatus, FEASIBLE, INFEASIBLE, FAILURE
export SolverType, LOOP, NONLIN
export LLT, Model, VSM
export AeroModel, INVISCID, LEI_AIRFOIL_BREUKELS, POLAR_MATRICES, POLAR_VECTORS
export COSINE, LINEAR, PanelDistribution, SPLIT_PROVIDED, UNCHANGED
export ELLIPTIC, InitialGammaDistribution, ZEROS
export FAILURE, FEASIBLE, INFEASIBLE, SolverStatus
export LOOP, NONLIN, SolverType
export load_polar_data

export plot_geometry, plot_distribution, plot_circulation_distribution, plot_polars,
save_plot, show_plot, plot_polar_data, plot_combined_analysis
export plot_circulation_distribution, plot_combined_analysis, plot_distribution, plot_geometry,
plot_polar_data, plot_polars, save_plot, show_plot

# the following functions are defined in ext/VortexStepMethodExt.jl
function plot_geometry end
Expand All @@ -61,7 +59,7 @@ function plot_combined_analysis end
Basic 3-dimensional vector, stack allocated, mutable.
"""
const MVec3 = MVector{3, Float64}
const MMat3 = MMatrix{3, 3, Float64}
const MMat3 = MMatrix{3, 3, Float64, 9}

"""
const PosVector=Union{MVec3, Vector}
Expand Down Expand Up @@ -202,9 +200,11 @@ const AeroData = Union{
Tuple{Vector{Float64}, Vector{Float64}, Matrix{Float64}, Matrix{Float64}, Matrix{Float64}}
}

const PACKAGE_ROOT = normpath(joinpath(@__DIR__, ".."))

function menu()
# Load the examples menu using a portable path
ex = joinpath(dirname(pathof(@__MODULE__)), "..", "examples", "menu.jl")
ex = joinpath(PACKAGE_ROOT, "examples", "menu.jl")
Base.include(Main, normpath(ex))
end

Expand All @@ -219,13 +219,13 @@ function copy_examples()
if ! isdir(PATH)
mkdir(PATH)
end
src_path = joinpath(dirname(pathof(@__MODULE__)), "..", PATH)
src_path = joinpath(PACKAGE_ROOT, PATH)
copy_files(PATH, readdir(src_path))
end

function install_examples(add_packages=true)
copy_examples()
pkg_root = joinpath(dirname(pathof(@__MODULE__)), "..")
pkg_root = PACKAGE_ROOT
src = joinpath(pkg_root, "data")
isdir(src) && cp(src, "data"; force=true)
if add_packages
Expand All @@ -241,7 +241,7 @@ function copy_files(relpath, files)
if ! isdir(relpath)
mkdir(relpath)
end
src_path = joinpath(dirname(pathof(@__MODULE__)), "..", relpath)
src_path = joinpath(PACKAGE_ROOT, relpath)
for file in files
cp(joinpath(src_path, file), joinpath(relpath, file), force=true)
chmod(joinpath(relpath, file), 0o774)
Expand All @@ -254,7 +254,7 @@ function help(url)
io = IOBuffer()
run(pipeline(`xdg-open $url`, stderr = io))
# ignore any error messages
out_data = String(take!(io))
_ = take!(io)
else
DefaultApplication.open(url)
end
Expand Down
174 changes: 89 additions & 85 deletions src/body_aerodynamics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ Main structure for calculating aerodynamic properties of bodies. Use the constru
- `y::MVector{P, Float64}` = MVector{P,Float64}(zeros(P))
- `cache::Vector{PreallocationTools.LazyBufferCache{typeof(identity), typeof(identity)}}` = [LazyBufferCache() for _ in 1:15]
"""
@with_kw mutable struct BodyAerodynamics{P}
@with_kw mutable struct BodyAerodynamics{P,W<:AbstractWing}
panels::Vector{Panel}
wings::Vector{Wing}
wings::Vector{W}
_va::MVec3 = zeros(MVec3)
Comment thread
ufechner7 marked this conversation as resolved.
has_distributed_va::Bool = false
omega::MVec3 = zeros(MVec3)
Expand Down Expand Up @@ -110,7 +110,7 @@ function BodyAerodynamics(
end
end

body_aero = BodyAerodynamics{length(panels)}(; panels, wings)
body_aero = BodyAerodynamics{length(panels),T}(; panels, wings)
reinit!(body_aero; va, omega)
return body_aero
end
Expand Down Expand Up @@ -159,6 +159,67 @@ end
return true
end

"""
calculate_stall_angle_list(panels::Vector{Panel};
begin_aoa=9.0,
end_aoa=22.0,
step_aoa=1.0,
stall_angle_if_none_detected=50.0,
cl_initial=-10.0)

Calculate stall angles for each panel.

Returns:
Vector{Float64}: Stall angles in radians
"""
function calculate_stall_angle_list(panels::Vector{Panel};
begin_aoa=9.0,
end_aoa=22.0,
step_aoa=1.0,
stall_angle_if_none_detected=50.0,
cl_initial=-10.0)
stall_angles = Vector{Float64}(undef, length(panels))
calculate_stall_angle_list!(stall_angles, panels;
begin_aoa, end_aoa, step_aoa,
stall_angle_if_none_detected, cl_initial)
return stall_angles
end

function calculate_stall_angle_list!(stall_angles::AbstractVector{Float64},
panels::Vector{Panel};
begin_aoa=9.0,
end_aoa=22.0,
step_aoa=1.0,
stall_angle_if_none_detected=50.0,
cl_initial=-10.0)

# Pre-compute range values to avoid allocation
n_steps = Int(floor((end_aoa - begin_aoa) / step_aoa)) + 1

for (idx, panel) in enumerate(panels)
# Default stall angle if none found
panel_stall = stall_angle_if_none_detected

# Start with minimum cl
cl_old = cl_initial

# Find stall angle
for i in 0:(n_steps-1)
aoa = deg2rad(begin_aoa + i * step_aoa)
cl = calculate_cl(panel, aoa)
if cl < cl_old
panel_stall = aoa
break
end
cl_old = cl
end

stall_angles[idx] = panel_stall
end

return nothing
end

"""
reinit!(body_aero::BodyAerodynamics; init_aero, va, omega, refine_mesh, recompute_mapping, sort_sections)

Expand Down Expand Up @@ -381,67 +442,6 @@ function calculate_circulation_distribution_elliptical_wing(gamma_i, body_aero::
nothing
end

"""
calculate_stall_angle_list(panels::Vector{Panel};
begin_aoa=9.0,
end_aoa=22.0,
step_aoa=1.0,
stall_angle_if_none_detected=50.0,
cl_initial=-10.0)

Calculate stall angles for each panel.

Returns:
Vector{Float64}: Stall angles in radians
"""
function calculate_stall_angle_list(panels::Vector{Panel};
begin_aoa=9.0,
end_aoa=22.0,
step_aoa=1.0,
stall_angle_if_none_detected=50.0,
cl_initial=-10.0)
stall_angles = Vector{Float64}(undef, length(panels))
calculate_stall_angle_list!(stall_angles, panels;
begin_aoa, end_aoa, step_aoa,
stall_angle_if_none_detected, cl_initial)
return stall_angles
end

function calculate_stall_angle_list!(stall_angles::AbstractVector{Float64},
panels::Vector{Panel};
begin_aoa=9.0,
end_aoa=22.0,
step_aoa=1.0,
stall_angle_if_none_detected=50.0,
cl_initial=-10.0)

# Pre-compute range values to avoid allocation
n_steps = Int(floor((end_aoa - begin_aoa) / step_aoa)) + 1

for (idx, panel) in enumerate(panels)
# Default stall angle if none found
panel_stall = stall_angle_if_none_detected

# Start with minimum cl
cl_old = cl_initial

# Find stall angle
for i in 0:(n_steps-1)
aoa = deg2rad(begin_aoa + i * step_aoa)
cl = calculate_cl(panel, aoa)
if cl < cl_old
panel_stall = aoa
break
end
cl_old = cl
end

stall_angles[idx] = panel_stall
end

return nothing
end

"""
update_effective_angle_of_attack_if_VSM(body_aero::BodyAerodynamics, gamma,
core_radius_fraction,
Expand Down Expand Up @@ -694,11 +694,11 @@ end

"""
calculate_results(body_aero::BodyAerodynamics, gamma_new,
density, aerodynamic_model_type::Model,
density,
core_radius_fraction, mu,
alpha_dist, v_a_dist,
chord_array, x_airf_array,
y_airf_array, z_airf_array,
z_airf_array,
va_array, va_norm_array,
va_unit_array, panels::Vector{Panel},
is_only_f_and_gamma_output::Bool)
Expand All @@ -713,14 +713,12 @@ function calculate_results(
gamma_new,
reference_point,
density,
aerodynamic_model_type::Model,
core_radius_fraction,
mu,
alpha_dist,
v_a_dist,
chord_array,
x_airf_array,
y_airf_array,
z_airf_array,
va_array,
va_norm_array,
Expand Down Expand Up @@ -1041,23 +1039,23 @@ Set velocity array and update wake filaments.
- `omega::VelVector`: Turn rate vector around x y and z axis [rad/s]
"""
function set_va!(body_aero::BodyAerodynamics, va::AbstractVector, omega=zeros(MVec3))
# Calculate va_distribution based on input type
va_distribution = if all(omega .== 0.0)
repeat(reshape(va, 1, 3), length(body_aero.panels))
elseif !all(omega .== 0.0)
va_dist = zeros(length(body_aero.panels), 3)

n_panels = length(body_aero.panels)
va_distribution = zeros(n_panels, 3)

if all(iszero, omega)
va_distribution .= repeat(reshape(va, 1, 3), n_panels)
Comment thread
ufechner7 marked this conversation as resolved.
Outdated
Comment thread
ufechner7 marked this conversation as resolved.
Outdated
else
idx = 1
for wing in body_aero.wings
# Get spanwise positions
spanwise_positions = [panel.control_point for panel in body_aero.panels]

# Calculate velocities for each panel
for i in 1:wing.n_panels
omega_va = -omega × spanwise_positions[i]
va_dist[i, :] .= omega_va .+ va
panel_end = idx + wing.n_panels - 1

# Calculate velocities for each panel in this wing slice
for j in idx:panel_end
omega_va = -omega × body_aero.panels[j].control_point
va_distribution[j, :] .= omega_va .+ va
end
Comment thread
ufechner7 marked this conversation as resolved.
idx = panel_end + 1
end
va_dist
end

# Update panel velocities
Expand All @@ -1067,12 +1065,18 @@ function set_va!(body_aero::BodyAerodynamics, va::AbstractVector, omega=zeros(MV

# Update wake elements
frozen_wake!(body_aero, va_distribution)
body_aero._va .= va
body_aero.has_distributed_va = false
if all(iszero, omega)
body_aero._va .= va
body_aero.has_distributed_va = false
else
body_aero._va .= _compute_reference_velocity_from_distribution(
va_distribution, n_panels)
body_aero.has_distributed_va = true
end
return nothing
Comment thread
ufechner7 marked this conversation as resolved.
end

function set_va!(body_aero::BodyAerodynamics, va_distribution::AbstractMatrix, omega=zeros(MVec3))
function set_va!(body_aero::BodyAerodynamics, va_distribution::AbstractMatrix)
size(va_distribution, 1) != length(body_aero.panels) &&
throw(ArgumentError("Number of rows in va distribution should be equal to number of panels."))

Expand Down
Loading
Loading