InertiaFreeQSMPowerModel

The InertiaFreeQSMPowerModel wraps the inertiafree-qsm package. The underlying model is an Inertia-Free Quasi-Steady Model (QSM) that simulates the full pumping cycle with four flight phases (traction, retraction, transitionRIO, transitionRORI). It numerically optimises the cycle parameters per wind speed to maximise output power using SLSQP.

Wrapper

class awespa.power.inertiafree_qsm_power.InertiaFreeQSMPowerModel[source]

Bases: PowerEstimationModel

Wrapper for the Inertia-Free Quasi-Steady Model power curve constructor.

This wrapper adapts the vendored InertiaFree-QSM to the AWESPA modular architecture. Power curves are generated from optimized cycle parameters per wind speed. Single-wind-speed simulations can still be run either directly or with optimization.

The model requires three configuration files in awesIO format: - System configuration (kite, tether, ground station properties) - Wind resource (altitude profiles, profiles, probability matrix) - Simulation settings (cycle parameters, optimizer bounds, phase settings)

__init__()[source]

Initialize the Inertia-Free QSM power estimation model.

load_configuration(system_path: Path, simulation_settings_path: Path, wind_resource_path: Path | None = None, validate: bool = True) None[source]

Load power model configuration from YAML files.

Creates a PowerCurveConstructor instance from the vendored InertiaFree-QSM package using the provided configuration files.

Parameters:
  • system_path (Path) – Path to the system configuration YAML file (awesIO format with wing, tether, ground_station components).

  • simulation_settings_path (Path) – Path to simulation settings YAML file containing cycle, phase, optimizer, and solver parameters.

  • wind_resource_path (Path) – Path to wind resource YAML file containing altitude profiles, profiles, and probability matrix.

  • validate (bool) – If True, validate configuration files using the awesIO validator. Defaults to True.

Raises:
compute_power_curves(wind_speeds: ndarray | None = None, profile_ids: List[int] | None = None, output_path: Path | None = None, verbose: bool = True, showplot: bool = False, saveplot: bool = False, validate: bool = True) Dict[str, Any][source]

Compute power curves.

Parameters:
  • output_path (Path) – Path where power curve YAML will be written. If None, no export is performed. Defaults to None.

  • wind_speeds (np.ndarray) – Custom wind speeds to evaluate [m/s]. If None, uses wind speeds from simulation settings. Defaults to None.

  • profile_ids (list) – profile IDs (1-indexed) to calculate. If None, calculates all profiles. Defaults to None.

  • verbose (bool) – Whether to print progress output. Defaults to True.

  • showplot (bool) – Whether to display plots after generation. Defaults to False.

  • saveplot (bool) – Whether to save plots to file. Requires output_path. Defaults to False.

  • validate (bool) – If True, validate the output YAML file using the awesIO validator. Defaults to True.

Returns:

Power curve data in awesIO format.

Return type:

dict

Raises:

ValueError – If model is not initialized.

calculate_power_at_wind_speed(wind_speed: float, method: str = 'direct', profile_id: int = 1, output_path: Path | None = None, verbose: bool = True, showplot: bool = False, saveplot: bool = False, validate: bool = True) float[source]

Calculate power output at a single wind speed.

Simulates a single pumping cycle at the given wind speed and returns the average cycle power.

Parameters:
  • wind_speed (float) – Wind speed at reference height [m/s].

  • method (str) – Simulation method, either 'direct' or 'optimization'. Defaults to 'direct'.

  • profile_id (int) – profile ID (1-indexed) for wind profile selection. Defaults to 1.

  • output_path (Path) – Path where results YAML will be written. If None, no export is performed. Defaults to None.

  • verbose (bool) – Whether to print verbose output. Defaults to True.

  • showplot (bool) – Whether to display cycle detail plot. Defaults to False.

  • saveplot (bool) – Whether to save cycle detail plot. Requires output_path. Defaults to False.

  • validate (bool) – If True, validate the output YAML file using the awesIO validator. Defaults to True.

Returns:

Average cycle power output [W].

Return type:

float

Raises:

ValueError – If model is not initialized.

Configuration files

load_configuration expects three YAML files:

system_path

System configuration in awesIO format.

simulation_settings_path

QSM-specific settings — aerodynamics, cycle parameters, phase settings, optimizer bounds, and solver tolerances.

wind_resource_path

Output of the wind module.

Simulation settings

An annotated example is shown below (see config/example/inertiafree-qsm_settings.yml):

# ===== AERODYNAMIC SETTINGS =====
aerodynamics:
  kite_lift_coefficient_reel_out: 0.63
  kite_drag_coefficient_reel_out: 0.14
  kite_lift_coefficient_reel_in: 0.4
  kite_drag_coefficient_reel_in: 0.12
  tether_drag_coefficient: 1.1

# ===== OPTIMIZATION =====
optimization:
  wind_speeds:
    cut_in: 3.0
    cut_out: 25.0
    n_points: 23

  optimizer:
    optimize_variables:
      reeling_speed_traction: true
      reeling_speed_retraction: true
      fraction_tether_length_traction_end: true
      fraction_tether_length_retraction_end: true
      elevation_angle_traction: true
      elevation_angle_end_trans_rori: true
    opt_phase_timestep:
      retraction: 1.5
      transition_riro: 0.05
      traction: 2.5
      transition_rori: 0.05
    max_iterations: 40
    ftol: 0.005
    eps: 1.0e-2
    finite_difference_steps:
      reeling_speed: 0.03
      tether_fraction: 0.005
      elevation_angle: 0.25
    x0: [2, -2, 0.65, 0.9, 30.0, 50.0]
    scaling: [1, 1, 1, 1, 30, 30]

  bounds:
    reeling_speed_traction_min: 0.01
    reeling_speed_traction_max: 15.0
    reeling_speed_retraction_min: -15.0
    reeling_speed_retraction_max: -0.01
    fraction_tether_length_traction_end_min: 0.8
    fraction_tether_length_traction_end_max: 0.95
    fraction_tether_length_retraction_end_min: 0.2
    fraction_tether_length_retraction_end_max: 0.8
    elevation_angle_traction_min: 30.0
    elevation_angle_traction_max: 60.0
    elevation_angle_end_trans_rori_min: 30.0
    elevation_angle_end_trans_rori_max: 80.0

  constraints:
    min_tether_length_fraction_difference: 0.1
    max_difference_elevation_angle_steps: 10.0

# ===== CYCLE CONFIGURATION =====
cycle:
  minimum_tether_force: 750.0
  minimum_height: 100.0
  elevation_angle_traction: [30.0, 30.0, 30.0, 30.0, 30.0]
  tether_length_end_traction: 0.95
  tether_length_end_retraction: 0.6
  include_transition_energy: true
  elevation_angle_end_trans_rori: 50.0

# ===== PHASE SETTINGS =====
retraction:
  control: ['reeling_speed', -2.0]
  time_step: 0.25
  azimuth_angle: 0.0
  course_angle: 180.0

transition_riro:
  control: ['reeling_speed', 0]
  time_step: 0.05
  azimuth_angle: 0.0
  course_angle: 0.0

transition_rori:
  control: ['reeling_speed', 0]
  time_step: 0.05
  azimuth_angle: 0.0
  course_angle: 180.0

traction:
  control: ['reeling_speed', 2.0]
  time_step: 0.25
  azimuth_angle: 11.5
  course_angle: 93.0

# ===== STEADY STATE SOLVER =====
steady_state:
  max_iterations: 250
  convergence_tolerance: 1.0e-3

# ===== PHASE SOLVER =====
phase_solver:
  max_time_points: 5000

Usage example

from pathlib import Path
from awespa.power.inertiafree_qsm_power import InertiaFreeQSMPowerModel

model = InertiaFreeQSMPowerModel()
model.load_configuration(
    system_path=Path("config/example/tudelft V3_25.yml"),
    simulation_settings_path=Path("config/example/inertiafree-qsm_settings.yml"),
    wind_resource_path=Path("config/example/wind_resource.yml"),
)

# Compute power curves
model.compute_power_curves(
    output_path=Path("results/example/power_curves_qsm.yml"),
    verbose=True,
    showplot=True,
    saveplot=True,
)

# Single operating point with a direct simulation, meaning that the parameters are not optimized but taken directly from the settings file. This is much faster than the default method, which runs an optimization loop to find the optimal parameters at each wind speed.
# Useful for testing
power_w = model.calculate_power_at_wind_speed(
    wind_speed=10.0,
    method="direct",
    profile_id=1,
    verbose=True,
)
print(f"Power at 10 m/s: {power_w / 1000:.1f} kW - DIRECT")

# Single operating point with an optimization-based simulation, meaning that the parameters are optimized to find the optimal settings for each wind speed.
power_w = model.calculate_power_at_wind_speed(
    wind_speed=10.0,
    method="optimization",
    profile_id=1,
    verbose=True,
)
print(f"Power at 10 m/s: {power_w / 1000:.1f} kW - OPTIMIZATION")

Or use the ready-made script:

python scripts/run_inertiafree_qsm.py