Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
70 changes: 28 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
# Vortex Step Method
The Vortex Step Method (VSM) is an enhanced lifting line method that improves upon the classic approach by solving the circulation system at the three-quarter chord position. This adjustment allows for more accurate calculations of lift and drag forces, particularly addressing the shortcomings in induced drag prediction. VSM is further refined by coupling it with 2D viscous airfoil polars, making it well-suited for complex geometries, including low aspect ratio wings, as well as configurations with sweep, dihedral, and anhedral angles, typical for leading-edge inflatable (LEI) kites, that are used in airborne wind energy production, boat-towing and kite-surfing. An open-source example kite is the [TU Delft V3 Kite](https://awegroup.github.io/TUDELFT_V3_KITE/), of which a video is shown below, made using the internal plotting library.
The Vortex Step Method (VSM) is an enhanced lifting line method that improves upon the classic approach by solving the circulation system at the three-quarter chord position. This adjustment allows for more accurate calculations of lift and drag forces, particularly addressing the shortcomings in induced drag prediction. VSM is further refined by coupling it with 2D viscous airfoil polars, making it well-suited for complex geometries, including low aspect ratio wings, as well as configurations with sweep, dihedral, and anhedral angles, typical for leading-edge inflatable (LEI) kites, that are used in airborne wind energy production, boat-towing and kite-surfing.

![](docs/TUDELFT_V3_KITE_plotly.gif)
A Julia version of this project is available at [VortexStepMethod.jl](https://github.com/Albatross-Kite-Transport/VortexStepMethod.jl)

The software presented here includes examples for: a rectangular wing and a leading-edge inflatable kite.

A Julia version of this project is available at [VortexStepMethod.jl](https://github.com/Albatross-Kite-Transport/VortexStepMethod.jl)
## Reference Frame

The VSM uses a body-fixed reference frame with the following conventions:

**Coordinate Axes:**
- **x-axis**: Rearward (leading edge → trailing edge)
- **y-axis**: Right wing (when looking from behind the kite)
- **z-axis**: Upward (from wing tip to mid-span)

**Aerodynamic Angles:**
- **Angle of Attack (α)**: Positive for nose up
- **Sideslip (β)**: Positive for wind from the left/port side (positive Vy)

**Body Rotation Rates** (right-hand rule):
- **Roll rate (p)**: Positive for left wing down (counter-clockwise looking forward)
- **Pitch rate (q)**: Positive for nose up (clockwise looking from right wing)
- **Yaw rate (r)**: Positive for nose left (counter-clockwise looking down)

The reference frame is illustrated below for the open-source example kite, the [TU Delft V3 Kite](https://awegroup.github.io/TUDELFT_V3_KITE/).

<!-- ![](docs/TUDELFT_V3_KITE_plotly.gif) -->
![](docs/TUDELFT_V3_KITE_reference_frame.png)

**Aircraft Frame Transformation:** For stability derivatives in standard aircraft coordinates (x-forward, y-right, z-down), use `map_derivatives_to_aircraft_frame()` from the `VSM.stability_derivatives` module. See `examples/TUDELFT_V3_KITE/evaluate_stability_derivatives.py` for usage.


## Key Features

Expand Down Expand Up @@ -99,41 +122,6 @@ For detailed documentation, please refer to the following resources.
deactivate
```

## Quick Start

Here's a minimal example to get started:

```python
from pathlib import Path
from VSM.core.BodyAerodynamics import BodyAerodynamics
from VSM.core.Solver import Solver

# Load kite geometry from YAML configuration
config_path = "data/TUDELFT_V3_KITE/CAD_derived_geometry/config_kite_CAD_CFD_polars.yaml"
body_aero = BodyAerodynamics.instantiate(
n_panels=30,
file_path=config_path,
spanwise_panel_distribution="uniform"
)

# Set flow conditions
body_aero.va_initialize(
Umag=10.0, # Velocity magnitude [m/s]
angle_of_attack=6.0, # Angle of attack [deg]
side_slip=0.0, # Sideslip angle [deg]
)

# Solve and get results
solver = Solver()
results = solver.solve(body_aero)

print(f"CL = {results['cl']:.3f}")
print(f"CD = {results['cd']:.3f}")
print(f"L/D = {results['cl']/results['cd']:.2f}")
```

For more examples, see the `examples/` directory.

## Dependencies

- numpy - Numerical computing
Expand Down Expand Up @@ -182,9 +170,7 @@ See individual files for detailed documentation and usage instructions.
For large-scale parametric studies:

1. **Use fewer panels during exploration** (`n_panels=20-30`), then increase for final results
2. **Numba JIT compilation** automatically accelerates vortex calculations (first run slower)
3. **Parallel studies**: Run multiple configurations using `multiprocessing` or `joblib`
4. **Cache geometries**: Instantiate `BodyAerodynamics` once, reuse with different flow conditions
2. **Cache geometries**: Instantiate `BodyAerodynamics` once, reuse with different flow conditions

Example:
```python
Expand Down
9 changes: 9 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [2.0.1] - 21-10-2025

### Added
- `evaluate_stability_derivatives.py` example script demonstrating the use of the new
`compute_rigid_body_stability_derivatives()` function for calculating aerodynamic stability derivatives, prints results at trim conditions in the kite reference frame (x-backward LE to TE, y-right from kite's perspective, z-up) and in the aircraft convention (x-forward, y-right, z-down).

### Fixed
- Corrected a misplaced minus sign in the sideslip handling inside `BodyAerodynamics.va_initialize`, restoring the intended sign convention for moment predictions and β-related stability derivatives.

## [2.0.0] - 08-10-2025

### ⚠️ Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,129 +101,3 @@ wing_airfoils:
- [17, neuralfoil, {dat_file_path: "clark_y.dat", model_size: "xxxlarge", xtr_lower: 0.0, xtr_upper: 1.0, n_crit: 9.0}]
- [18, neuralfoil, {dat_file_path: "clark_y.dat", model_size: "xxxlarge", xtr_lower: 0.0, xtr_upper: 1.0, n_crit: 9.0}]
- [19, neuralfoil, {dat_file_path: "clark_y.dat", model_size: "xxxlarge", xtr_lower: 0.0, xtr_upper: 1.0, n_crit: 9.0}]



bridle_nodes:
# ---------------------------------------------------------------
# headers:
# - id: integer, unique identifier for the node
# - x: x-coordinate [m]
# - y: y-coordinate [m]
# - z: z-coordinate [m]
# - type: node type, either 'knot' or 'pulley'
# ---------------------------------------------------------------
headers: [id, x, y, z, type]
data:
- [21, -0.67653494, 2.10580567, 7.08413599, knot]
- [22, -0.79196791, 1.01882151, 7.57069579, knot]
- [23, -0.79196791, -1.01882151, 7.57069579, knot]
- [24, -0.67653494, -2.10580567, 7.08413599, knot]
- [25, -0.46444477, 0.77505128, 4.23316161, knot]
- [26, -0.46444477, -0.77505128, 4.23316161, knot]
- [27, 0.54344694, 1.57655435, 5.91086207, knot]
- [28, 0.62960591, 0.92728966, 6.64639402, knot]
- [29, 0.62960591, -0.92728966, 6.64639402, knot]
- [30, 0.54344694, -1.57655435, 5.91086207, knot]
- [31, 0.39092886, 0.71221536, 4.26118728, knot]
- [32, 0.39092886, -0.71221536, 4.26118728, knot]
- [33, 0.30679124, 0.49235914, 3.39885672, pulley]
- [34, 0.28625931, 0.0, 3.19030736, knot]
- [35, 0.30679124, -0.49235914, 3.39885672, pulley]
- [36, 0.13269336, 0.23394851, 1.48060245, knot]
- [37, 0.13269336, -0.23394851, 1.48060245, knot]

bridle_lines:
# ---------------------------------------------------------------
# headers:
# - name: string, line name
# - rest_length: measured rest length [m]
# - diameter: line diameter [m]
# - material: string, material type (e.g., dyneema)
# - density: material density [kg/m^3]
# ---------------------------------------------------------------
headers: [name, rest_length, diameter, material, density]
data:
# front lines
- [a6, 11.790, 0.002, dyneema,970]
- [A5, 2.870, 0.002, dyneema,970]
- [A3, 3.450, 0.002, dyneema,970]
- [A2, 3.500, 0.002, dyneema,970]
- [A1, 3.690, 0.002, dyneema,970]
- [AII, 3.250, 0.002, dyneema,970]
- [AI, 3.620, 0.002, dyneema,970]
- [amain, 3.910, 0.002, dyneema,970]
# rear lines
- [br1, 4.410, 0.002, dyneema,970]
- [br2, 4.170, 0.002, dyneema,970]
- [br3, 4.140, 0.002, dyneema,970]
- [br5, 3.580, 0.002, dyneema,970]
- [br6, 13.560, 0.002, dyneema,970]
- [BRI, 2.360, 0.002, dyneema,970]
- [BRII, 2.080, 0.002, dyneema,970]
- [BR-main-1, .700, 0.002, dyneema,970]
- [M-line, 2.410, 0.002, dyneema,970]
# - [S, 1.730, 0.002, dyneema,970] # measured
# - [Power Tape, 3.330, 0.002, polyester] # measured
- [Steering Tape, 1.530, 0.002, dyneema,970] # trying 0.2m smalller
- [Power Tape, 2.900, 0.002, dyneema,970] # trying 0.2m smaller

bridle_connections:
# ---------------------------------------------------------------
# headers:
# - name: string, line name
# - ci: integer, node id (start)
# - cj: integer, node id (end)
# - ck: integer, third node id (only for pulleys, else omitted or 0)
# ---------------------------------------------------------------
headers: [name, ci, cj, ck]
data:
# front lines
- [a6,1,25,33] #e.g. this is a pulley
- [A5,3,21]
- [A3,5,21]
- [A2,7,22]
- [A1,9,22]
- [A1,11,23]
- [A2,13,23]
- [A3,15,24]
- [A5,17,24]
- [a6,19,26,35]
- [AII,21,25]
- [AI,22,25]
- [AI,23,26]
- [AII,24,26]
- [amain,25,0]
- [amain,26,0]
# rear lines
- [a6,1,33,25]
- [br6,2,33,36]
- [br6,2,36,33]
- [br5,4,27]
- [br3,6,27]
- [br2,8,28]
- [br1,10,28]
- [br1,12,29]
- [br2,14,29]
- [br3,16,30]
- [br5,18,30]
- [a6,19,35,26]
- [br6,20,35,37]
- [br6,20,37,35]
- [BRII,27,31]
- [BRI,28,31]
- [BRI,29,32]
- [BRII,30,32]
- [BR-main-1,31,33]
- [BR-main-1,32,35]
- [M-line,33,36,34]
- [M-line,33,34,36]
- [M-line,35,34,37]
- [M-line,35,37,34]
- [Steering Tape,36,0]
- [Power Tape,34,0]
- [Steering Tape,37,0]




Original file line number Diff line number Diff line change
Expand Up @@ -104,123 +104,3 @@ wing_airfoils:
- [19,breukels_regression, {t: 0.07, eta: 0.02, kappa: 0.59, delta: -0.2, lambda: 0.29, phi: 0.07}]



bridle_nodes:
# ---------------------------------------------------------------
# headers:
# - id: integer, unique identifier for the node
# - x: x-coordinate [m]
# - y: y-coordinate [m]
# - z: z-coordinate [m]
# - type: node type, either 'knot' or 'pulley'
# ---------------------------------------------------------------
headers: [id, x, y, z, type]
data:
- [21, -0.67653494, 2.10580567, 7.08413599, knot]
- [22, -0.79196791, 1.01882151, 7.57069579, knot]
- [23, -0.79196791, -1.01882151, 7.57069579, knot]
- [24, -0.67653494, -2.10580567, 7.08413599, knot]
- [25, -0.46444477, 0.77505128, 4.23316161, knot]
- [26, -0.46444477, -0.77505128, 4.23316161, knot]
- [27, 0.54344694, 1.57655435, 5.91086207, knot]
- [28, 0.62960591, 0.92728966, 6.64639402, knot]
- [29, 0.62960591, -0.92728966, 6.64639402, knot]
- [30, 0.54344694, -1.57655435, 5.91086207, knot]
- [31, 0.39092886, 0.71221536, 4.26118728, knot]
- [32, 0.39092886, -0.71221536, 4.26118728, knot]
- [33, 0.30679124, 0.49235914, 3.39885672, pulley]
- [34, 0.28625931, 0.0, 3.19030736, knot]
- [35, 0.30679124, -0.49235914, 3.39885672, pulley]
- [36, 0.13269336, 0.23394851, 1.48060245, knot]
- [37, 0.13269336, -0.23394851, 1.48060245, knot]

bridle_lines:
# ---------------------------------------------------------------
# headers:
# - name: string, line name
# - rest_length: measured rest length [m]
# - diameter: line diameter [m]
# - material: string, material type (e.g., dyneema)
# - density: material density [kg/m^3]
# ---------------------------------------------------------------
headers: [name, rest_length, diameter, material, density]
data:
# front lines
- [a6, 11.790, 0.002, dyneema,970]
- [A5, 2.870, 0.002, dyneema,970]
- [A3, 3.450, 0.002, dyneema,970]
- [A2, 3.500, 0.002, dyneema,970]
- [A1, 3.690, 0.002, dyneema,970]
- [AII, 3.250, 0.002, dyneema,970]
- [AI, 3.620, 0.002, dyneema,970]
- [amain, 3.910, 0.002, dyneema,970]
# rear lines
- [br1, 4.410, 0.002, dyneema,970]
- [br2, 4.170, 0.002, dyneema,970]
- [br3, 4.140, 0.002, dyneema,970]
- [br5, 3.580, 0.002, dyneema,970]
- [br6, 13.560, 0.002, dyneema,970]
- [BRI, 2.360, 0.002, dyneema,970]
- [BRII, 2.080, 0.002, dyneema,970]
- [BR-main-1, .700, 0.002, dyneema,970]
- [M-line, 2.410, 0.002, dyneema,970]
# - [S, 1.730, 0.002, dyneema,970] # measured
# - [Power Tape, 3.330, 0.002, polyester] # measured
- [Steering Tape, 1.530, 0.002, dyneema,970] # trying 0.2m smalller
- [Power Tape, 2.900, 0.002, dyneema,970] # trying 0.2m smaller

bridle_connections:
# ---------------------------------------------------------------
# headers:
# - name: string, line name
# - ci: integer, node id (start)
# - cj: integer, node id (end)
# - ck: integer, third node id (only for pulleys, else omitted or 0)
# ---------------------------------------------------------------
headers: [name, ci, cj, ck]
data:
# front lines
- [a6,1,25,33] #e.g. this is a pulley
- [A5,3,21]
- [A3,5,21]
- [A2,7,22]
- [A1,9,22]
- [A1,11,23]
- [A2,13,23]
- [A3,15,24]
- [A5,17,24]
- [a6,19,26,35]
- [AII,21,25]
- [AI,22,25]
- [AI,23,26]
- [AII,24,26]
- [amain,25,0]
- [amain,26,0]
# rear lines
- [a6,1,33,25]
- [br6,2,33,36]
- [br6,2,36,33]
- [br5,4,27]
- [br3,6,27]
- [br2,8,28]
- [br1,10,28]
- [br1,12,29]
- [br2,14,29]
- [br3,16,30]
- [br5,18,30]
- [a6,19,35,26]
- [br6,20,35,37]
- [br6,20,37,35]
- [BRII,27,31]
- [BRI,28,31]
- [BRI,29,32]
- [BRII,30,32]
- [BR-main-1,31,33]
- [BR-main-1,32,35]
- [M-line,33,36,34]
- [M-line,33,34,36]
- [M-line,35,34,37]
- [M-line,35,37,34]
- [Steering Tape,36,0]
- [Power Tape,34,0]
- [Steering Tape,37,0]
Loading
Loading