Ptera Software

repository·main·Indexed 42 days ago

https://github.com/camurban/pterasoftware

An open-source Python package for analyzing flapping-wing flight using Vortex Lattice Methods (VLM). It supports steady and unsteady aerodynamics, aeroelasticity, and free-flight simulations, featuring solvers for Steady Horseshoe VLM, Steady Ring VLM, Unsteady Ring VLM (UVLM), and MuJoCo-coupled rigid body dynamics.

Tokens
32.6K
Snippets
52
Records
132
Agent score
55%

What's inside Ptera Software

  1. Understand Ptera Software performance benchmarks

    main

    Ptera Software provides performance measurements for its solvers using two primary metrics: solver wall time and solver peak memory delta.

    Benchmarks are conducted using a frozen software stack (exact Python patch and pinned dependencies via uv --require-hashes) to ensure results reflect release-day resolution. The benchmarks compare each version against the immediately-preceding PyPI version.

    When viewing the interactive charts, you can toggle between:

    • Absolute units: Shown on a log y-axis.
    • Normalized view: Shown on a linear y-axis using "Speedup vs. baseline" (for time) or "Ratio vs. baseline" (for memory).
  2. Overview of Ptera Software solvers

    main

    Ptera Software provides several aerodynamic simulation methods for flapping-wing analysis:

    • Steady Horseshoe VLM: Standard steady horseshoe vortex lattice method.
    • Steady Ring VLM: Steady ring vortex lattice method.
    • Unsteady Ring VLM (UVLM): Unsteady simulations supporting fixed or free wakes, vortex aging, and two different load calculation methods (Kutta-Joukowski or pressure integration).
    • Aeroelastic Unsteady Ring VLM (Beta): Co-simulation of structural wing deformation (currently using a torsional spring model) with UVLM.
    • Free Flight Unsteady Ring VLM (Beta): Couples UVLM with six-degree-of-freedom rigid body dynamics using the MuJoCo physics engine for two-way coupling between flight dynamics and unsteady aerodynamics.
  3. Understand the Aitken relaxation factor and $\lambda_{\text{init}}$

    main

    The solver uses Aitken $\Delta^2$ acceleration to dynamically compute relaxation factors during sub-iterations. The parameter $\lambda_{\text{init}}$ is used only for the very first sub-iteration update ($k=0$):

    $$\mathbf{x}^{(1)}{n+1} = \mathbf{x}^{(0)}{n+1} + \lambda_{\text{init}},\mathbf{r}^{(0)}_{n+1}$$

    Usage Guidance

    • Purpose: $\lambda_{\text{init}}$ provides a safe 'warm start' for the iteration. It does not change the final fixed point, only the path taken to get there.
    • Stability: Under-relaxation ($\lambda < 1$) is used to stabilize the solver against added-mass feedback. For light vehicles with high added-mass ratios ($m_a/m$), a conservative value is necessary.
    • Recommended Value: 0.5. This is more conservative than tools like SHARPy (which uses 0.8) to accommodate the lighter vehicles targeted by this solver.
  4. Understand the Body axis system

    main

    Body axes are attached to the Airplane and follow the convention from Stevens, Lewis, and Johnson (2016). It is a right-handed coordinate system with the following basis directions:

    • +x: Towards the front of the Airplane
    • +y: Towards the right of the Airplane
    • +z: Towards the bottom of the Airplane

    Naming Conventions:

    • Local reference (on the airplane): ..._B (e.g., force_B)
    • Non-local reference (referencing a specific airplane): ..._BP1 (e.g., force_BP1 for the first airplane).
  5. Use the hat convention for interval loads

    main

    In the mathematical framework, a 'hat' notation is used to distinguish between trial values used during sub-iterations and the final accepted values for a snapshot.

    • $\hat{\mathbf{l}}_{n+1}$: The interval load used during sub-iterations to advance the body in the structural propagator $S$. This is the load the body is advanced under during the search for convergence.
    • $\mathbf{l}_{n+1}$: The official snapshot load finalized at the accepted state once convergence is reached.

    At convergence, $\hat{\mathbf{l}}{n+1}$ matches the official $\mathbf{l}{n+1}$ within the specified tolerance.

  6. Understand Wing and Airfoil axes

    main

    The project defines several hierarchical axis systems for aerodynamic components:

    Wing axes

    Owned by Wing. Basis directions:

    • +x: Towards the back of the Wing at its root.
    • +y: From the Wing root towards the next WingCrossSection's plane.
    • +z: Towards the top surface of the Wing.
    • Note: Right-handed for non-symmetric/symmetric-continuous wings; Left-handed for mirror-only wings.
    • Code suffix: ..._Wn (e.g., force_Wn).

    Wing cross section axes

    Owned by WingCrossSection. Basis directions:

    • +x: Towards the trailing edge in the WingCrossSection's plane.
    • +y: Normal to the plane, towards the next WingCrossSection.
    • +z: Towards the top surface of the Wing.
    • Code suffix: ..._Wcs (e.g., force_Wcs).

    Airfoil axes

    Owned by Airfoil. A 2D coordinate system with basis directions:

    • +x: Chordwise towards the Airfoil's trailing point.
    • +y: Normal to the chord towards the Airfoil's upper line.
    • Code suffix: ..._A (e.g., pressure_A).
  7. How the strongly coupled sub-iteration algorithm works

    main

    The Strongly Coupled Free-Flight UVLM-MuJoCo solver uses a sub-iteration algorithm to find a fixed point between the aerodynamic loads and the MuJoCo rigid-body dynamics. This ensures that the state $\mathbf{x}{n+1}$ and the aerodynamic load $\mathbf{l}{n+1}$ are consistent with the physics of the Unsteady Vortex Lattice Method (UVLM).

    Sub-iteration Lifecycle

    1. Freeze: The MuJoCo state $\mathbf{x}_n$, bound geometry $\mathbf{B}_n$, strengths $\boldsymbol{\Gamma}_n$, and wake $W_n$ are frozen. The expensive Biot-Savart transport part of the wake propagator $P$ is precomputed once per step.
    2. Seed: The iteration starts (at $k=0$) using the snapshot-$n$ load as a warm start: $\mathbf{x}^{(0)}_{n+1} = S(\mathbf{x}_n, \mathbf{l}_n)$.
    3. Loop: For each iteration $k$ up to $k_{\max}$:
      • Build trial geometry $\mathbf{B}^{(k)}{n+1}$ and wake $W^{(k)}{n+1}$.
      • Evaluate trial load $\mathbf{l}^{(k)}{n+1}$ and internal circulation strengths $\boldsymbol{\Gamma}^{(k)}{n+1}$.
      • Compute a trial dynamics state $\tilde{\mathbf{x}}^{(k)}_{n+1}$ by applying the trial load to the frozen state $\mathbf{x}_n$.
      • Calculate the residual $\mathbf{r}^{(k)}{n+1} = \tilde{\mathbf{x}}^{(k)}{n+1} - \mathbf{x}^{(k)}_{n+1}$.
      • Convergence Test: The iteration stops if the weighted residual satisfies: $$| \mathbf{D} , \mathbf{r}^{(k)}{n+1} | \le \varepsilon{\text{rel}} | \mathbf{D} , \Delta \mathbf{x}^{(k)}{n+1} | + \varepsilon{\text{abs}}$$
      • Update: If not converged, update the state using an Aitken $\Delta^2$ relaxation factor $\lambda^{(k)}{n+1}$: $$\mathbf{x}^{(k+1)}{n+1} = \mathbf{x}^{(k)}{n+1} + \lambda^{(k)}{n+1} , \mathbf{r}^{(k)}_{n+1}$$
    4. Acceptance: Once converged (or $k_{\max}$ is reached), the official state $\mathbf{x}{n+1}$ and load $\mathbf{l}{n+1}$ are computed at the accepted state to ensure a genuine MuJoCo trajectory.

    Handling Non-Convergence

    If the solver reaches the $k_{\max}$ limit without meeting the convergence criteria, it does not abort. Instead:

    • The step is accepted using the final iterate's values.
    • The state remains a valid MuJoCo trajectory, though aero-structural consistency is imperfect.
    • The solver emits a warning.
    • Note: Sustained $k_{\max}$ hits (frequent warnings) indicate potential instability, especially in added-mass-dominated regimes, and suggest that $k_{\max}$ should be increased.
  8. Understand the `CoreUnsteadyProblem` and `UnsteadyProblem` attribute structure

    main

    The CoreUnsteadyProblem and UnsteadyProblem classes (found in _core.py and problems.py) use a strict attribute classification system to manage simulation data. Understanding these categories is essential for interacting with solver results.

    Immutable Attributes

    These are set during __init__ and never modified. They define the simulation parameters and constraints.

    • movement (Movement): The movement definition (only on UnsteadyProblem).
    • only_final_results (bool): Flag for result reporting.
    • num_steps (int): Total number of steps (copied from Movement).
    • delta_time (float): Time step size (copied from Movement).
    • first_averaging_step (int): The step index where averaging begins.
    • first_results_step (int): The step index where results are first recorded.
    • max_wake_rows (int | None): Maximum wake rows (copied from Movement).
    • steady_problems (tuple[SteadyProblem, ...]): A collection of steady problems (only on UnsteadyProblem).

    Mutable Attributes (Solver Results)

    These are initialized as empty lists and populated by the solver during the simulation. They contain the raw data for each Airplane in the simulation. The G and Cg IDs refer to the entry's own geometry axes and CG respectively.

    Force and Moment Lists:

    • finalForces_W, finalForceCoefficients_W, finalMoments_W_CgP1, finalMomentCoefficients_W_CgP1 (Wind axes)
    • finalForces_G, finalForceCoefficients_G, finalMoments_G_Cg, finalMomentCoefficients_G_Cg (Geometry axes)
    • finalMoments_W_Cg, finalMomentCoefficients_W_Cg (Wind axes, own-CG)
    • finalMean... and finalRms... variants for cycle-averaged and RMS counterparts of the above.

    Derived Read-Only Properties

    These properties do not store data; they are recomputed on every access to ensure they reflect the current state of the mutable lists. They provide named aerodynamic components (e.g., Lift, Drag, Rolling Moment) extracted from the raw force/moment lists.

  9. Understand the Movement class hierarchy and attributes

    main

    The Movement class hierarchy is designed around immutability and pre-generation of geometry. Movement extends CoreMovement and adds cycle/chord counting, wake sizing, and batch pre-generation of Airplanes and OperatingPoints.

    CoreMovement Attributes (Immutable)

    • airplane_movements: tuple[AirplaneMovement, ...]
    • operating_point_movement: OperatingPointMovement
    • delta_time: float (Time step)
    • num_steps: int (Total time steps)
    • max_wake_rows: int | None (Max wake rows per Wing)

    CoreMovement Derived Properties (Lazy Cached)

    • lcm_period: Depends on airplane_movements and operating_point_movement.
    • max_period: Depends on airplane_movements and operating_point_movement.
    • min_period: Depends on airplane_movements and operating_point_movement.
    • static: Depends on max_period.

    Movement Specific Attributes (Immutable)

    • num_cycles: int | None (Number of cycles)
    • num_chords: int | None (Number of chord lengths)
    • max_wake_chords: int | None (Max wake in chord lengths)
    • max_wake_cycles: int | None (Max wake in motion cycles)
    • airplanes: tuple[tuple[Airplane, ...], ...] (Generated Airplanes)
    • operating_points: tuple[OperatingPoint, ...] (Generated OperatingPoints)
  10. Access specific Angle Vector components

    main

    To access a single scalar component (or a stack of components) from an angle vector, append the component letter (X, Y, or Z) to the end of the camelCase portion of the variable name.

    • Singular component: angleY_E_to_B_izyx (holds only the y component of angles_E_to_B_izyx).
    • Stack of components: deformationAnglesYRad_Wcsp_to_Wcs_ixyz (holds one y component per WingCrossSection).

    This follows the same convention used for all vector-valued quantities in Ptera Software.

  11. Understand the Strongly Coupled UVLM-MuJoCo Solver Framework

    main

    The solver implements a strong (implicit) coupling between free-flight Unsteady Vortex Lattice Method (UVLM) aerodynamics and MuJoCo rigid-body dynamics.

    Unlike explicit (loose) coupling, which uses lagged data from the previous step, strong coupling drives the aerodynamic and structural subsystems to mutual consistency within a single time step. This is achieved through a fixed-point iteration accelerated by Aitken's method.

    Mathematical Abstractions (Maps)

    The framework uses several time-generic maps to compute the physics:

    • G (Bound geometry map): Maps body state and time to bound ring vortex positions.
    • S (Structural propagator map): Propagates the rigid-body state.
    • P (Wake propagator map): Spans the time interval to handle induced transport and shed strengths.
    • C (Circulation solve): Computes bound ring vortex strengths.
    • L (Load evaluation): Computes aerodynamic loads.
    • A (Composite aerodynamic evaluation): A combined map for aerodynamic evaluation.
  12. Reference Points and Variable Naming Conventions

    main

    PteraSoftware uses a hierarchical naming convention for reference points to allow for local, airplane-local, and non-local referencing. When specifying a point, the variable name suffix indicates the level of ownership and the path through the object hierarchy.

    Common Reference Points

    Point NameOwnershipVariable Suffix (Local)Description
    Earth originNone_EoGlobal spatial origin
    CGAirplane_CgPosition of the Airplane's Center of Gravity
    CG (Symmetry)Wing_CgsCG after accounting for symmetry (reflected for mirror wings)
    Leading edge root pointWing_LerRoot point of the Wing's leading edge
    Leading pointWingCrossSection_LpThe leading point of a specific cross section
    Leading point parentWingCrossSection_LppThe _Ler for the first section, or the previous section's _Lp
    Panel pointsPanel_Frpp (etc.)Front right, front left, back left, back right, and collocation points
    Strip leading edge point (SLEP)Wing_SlepLeading edge point of a spanwise strip (aeroelastic simulations only)

    Hierarchical Naming Patterns

    To reference points across different objects, append identifiers to the base suffix:

    • Local: _Suffix (e.g., _Cg)
    • Wing-local: _SuffixN (e.g., _Ler1 for the first wing)
    • Airplane-local: _SuffixN + WnN (e.g., _Lp1Wn2 for the 1st cross section of the 2nd wing)
    • Non-local: _SuffixN + WnN + P1 (e.g., _Lp1Wn2P1 for the 1st cross section of the 2nd wing of the 1st airplane)