Trajectory builders
This is a system of organization for the different classes that do trajectory simulation.
The basic idea here is to separate the logic of flying trajectories from the
data container representing a trajectory (the Trajectory class and the
associated idea of field sets), and to allow for easy swapping of different
trajectory building algorithms (the current AEIC v2 “legacy” one, and later
TASOPT-based, simulations based on ADS-B data, or whatever). The builder API
has a base abstract Builder class, plus a concrete class derived from that
for each type of trajectory builder. (The only one of these that’s fully
implemented so far is LegacyBuilder, which does AEIC v2 trajectories.) Each
builder class has an options class that wraps up any options that the builder
supports. The main method used to simulate a trajectory is called fly: you
pass a performance model and a mission and get back a trajectory.
The part of all this that probably requires some explanation is the Context
classes. Each of the trajectory builders will have state that it needs to keep
track of during the calculations that go on in the fly method and the
subsidiary methods that fly calls. Instead of either a). threading lots of
parameters through all the function calls; or b). having a bunch of instance
variables on the builder classes that have poorly defined lifecycles and
initialization states (lots of things being set to None in constructors, for
example), there is the idea of a “context”, which is a separate object which
maintains all of the required state in one place. Because there is a single
context object whose lifecycle is bounded by any particular call to the fly
method, managing the lifecycle is easy. To avoid saying
self.context.whatever all over the place, there is some more Python magic
using __getattr__ to route attribute accesses on the builder to the context
instead. It ends up being quite comfortable to program against. (One
disadvantage is that it isn’t thread-safe: if you share a trajectory builder
across threads, the context will get mixed up. But trajectory builders are
lightweight things, so it’s not a problem to create them in each thread where
you need one.)
You can see how all of this works together in the
tests/test_trajectory_simulation.py test file. There’s a test function there
that simulates a list of sample missions from an input file, saves them to a
NetCDF file and reloads them.
A trajectory builder class should have a fly_... method for each flight
phase that it implements, e.g. fly_climb, fly_cruise, fly_descent at a
minimum. These methods are passed the Trajectory being constructed, plus a
set of additional builder-specific keyword arguments passed through from
fly, used for any builder-specific specials.
The base Builder class, the shared Options dataclass, and the
Context dataclass are documented below. LegacyBuilder is the most
complete reference implementation and the recommended starting point for
anyone writing a new builder. Actually using the trajectory builders is
simple, but implementing one is more involved.
Warning
The builder API is still settling. There are no helper methods on the Trajectory or Builder classes for the “extra” LTO flight phases (taxi, take-off roll, etc.) — those still need to be handled in the concrete builder.
- class AEIC.trajectories.builders.base.Builder(options=Options(optimize_traj=False, iterate_mass=True, use_weather=False, max_mass_iters=5, mass_iter_reltol=0.01))
Abstract parent class for all AEIC trajectory builders. Contains overall fly logic.
- Parameters:
options (Options)
- options
Options for trajectory building.
- Type:
Options
- CONTEXT_CLASS: type | None = None
Class for trajectory building context. Should be derived from base Context class.
- abstractmethod calc_starting_mass()
Calculate the starting mass of the aircraft for the flight.
- Return type:
float
- fly(ac_performance, mission, starting_mass=None, **kwargs)
Top-level function that initiates and runs flights.
As well as the fixed arguments listed below, this can also take builder-specific additional keyword arguments.
- Parameters:
ac_performance (BasePerformanceModel) – Performance model used for trajectory simulation.
mission (Mission) – Data dictating the mission to be flown (departure/arrival info, etc.).
starting_mass (float, optional) – Starting mass of the aircraft; leave as default to calculate starting mass during simulation.
- Returns:
Trajectory object.
- Return type:
trajectory (Trajectory)
Legacy trajectory builder
The legacy trajectory relies on BADA-3-like performane data in the AEIC performance data format. Specifically, it requires data that has prescribed climb and descent profiles, as well as cruise data at a single altitude (\(7000\,\text{ft}\) below operating ceiling).
- class AEIC.trajectories.builders.legacy.LegacyBuilder(options=Options(optimize_traj=False, iterate_mass=True, use_weather=False, max_mass_iters=5, mass_iter_reltol=0.01), legacy_options=LegacyOptions(altitude_step=304.8, cruise_step=231500, fuel_LHV=43800000.0))
Model for determining flight trajectories using the legacy method from AEIC v2.
- Parameters:
options (Options) – Base options for trajectory building.
legacy_options (LegactyOptions) – Builder-specific options for legacy trajectory builder.
- CONTEXT_CLASS
alias of
LegacyContext
- calc_starting_mass()
Calculates the starting mass using AEIC v2 methods. Sets both starting mass and non-reserve/hold/divert fuel mass.
- Return type:
float
- fly_climb(traj)
Simulate the climb phase of a trajectory.
Delegates to
_fly_level_changewith climb flight rules, integrating from the end of the previous phase up to the cruise-start altitude.- Parameters:
traj (Trajectory)
- Return type:
None
- fly_cruise(traj)
Simulate cruise phase.
Computes state over cruise segment using AEIC v2 methods based on BADA-3 formulas.
- Parameters:
traj (Trajectory)
- fly_descent(traj)
Simulate the descent phase of a trajectory.
Delegates to
_fly_level_changewith descent flight rules, integrating from the cruise altitude down to the descent-end altitude. The final per-phase point count is decremented by one to account for the shared boundary point with the next phase.- Parameters:
traj (Trajectory)
- Return type:
None
- class AEIC.trajectories.builders.legacy.LegacyContext(builder, ac_performance, mission, starting_mass)
Context for legacy trajectory builder.
- Parameters:
builder (Builder)
ac_performance (BasePerformanceModel)
mission (Mission)
starting_mass (float | None)
- class AEIC.trajectories.builders.legacy.LegacyOptions(altitude_step=304.8, cruise_step=231500, fuel_LHV=43800000.0)
Additional options for the legacy trajectory builder.
- Parameters:
altitude_step (float)
cruise_step (float)
fuel_LHV (float)
- altitude_step: float = 304.8
Altitude step to use in climb and descent phases (m).
- cruise_step: float = 231500
Ground distance step to use in cruise phase (m).
- fuel_LHV: float = 43800000.0
Lower heating value of the fuel used (J/kg).
Adjustable legacy trajectory builder
AdjustableLegacyBuilder is a variant of LegacyBuilder with the same
phase-integration logic and the same default behavior, but with additional
per-flight hooks for changing the assumptions that are normally hard-coded in
the legacy builder. It is intended for sensitivity studies, policy scenarios,
or workflows where the basic AEIC v2 trajectory model is still desired but
where cruise altitude, reserve policy, descent planning, or similar inputs need
to vary by mission.
With no adjustment arguments, AdjustableLegacyBuilder should produce the same
trajectory as LegacyBuilder for the same mission, performance model, and
builder options.
import AEIC.trajectories.builders as tb
builder = tb.AdjustableLegacyBuilder(
options=tb.Options(iterate_mass=False),
legacy_options=tb.LegacyOptions(),
)
traj = builder.fly(performance_model, mission)
Adjustment arguments
Adjustments are passed as keyword arguments to fly. Each adjustment may be:
None, which uses the standard legacy default;a
float, which is used directly; ora callable, which receives the current adjustable context, the mission, the performance model, and any adjustment-specific keyword arguments.
The supported adjustment keywords are:
Keyword |
Units |
Legacy default |
|---|---|---|
|
m |
departure airport altitude + \(3000\,\text{ft}\) |
|
m |
aircraft maximum altitude - \(7000\,\text{ft}\) |
|
m |
arrival airport altitude + \(3000\,\text{ft}\) |
|
m |
proportional to |
|
kg |
5% of nominal trip fuel |
|
m |
100 NM for flights up to 3 hours, otherwise 200 NM |
|
s |
45 minutes for flights up to 3 hours, otherwise 30 minutes |
For example, fixed values can be used to pin a scenario:
traj = builder.fly(
performance_model,
mission,
climb_start_altitude=1500.0,
cruise_altitude=9000.0,
descent_end_altitude=1200.0,
descent_distance=200_000.0,
reserve_fuel=1_500.0,
divert_distance=150_000.0,
hold_time=30 * 60.0,
)
Callable adjustments are useful when the value depends on mission or aircraft properties:
def cruise_altitude(context, mission, performance):
# Fly 1000 m below the aircraft ceiling, but never below the climb start.
return max(context.clm_start_altitude, performance.maximum_altitude - 1000.0)
def reserve_fuel(context, mission, performance, *, fuel_mass):
# Use a larger reserve fraction for this scenario.
return 0.10 * fuel_mass
traj = builder.fly(
performance_model,
mission,
cruise_altitude=cruise_altitude,
reserve_fuel=reserve_fuel,
)
The fuel-policy callables receive additional keyword-only inputs:
reserve_fuel(..., fuel_mass=...), wherefuel_massis the nominal trip fuel estimate used by the starting-mass calculation;divert_distance(..., approx_time=...), whereapprox_timeis the nominal flight time estimate;hold_time(..., approx_time=...), using the same nominal flight time estimate.
Validation and clamping
The adjustable builder preserves the legacy guardrails where possible:
a climb start altitude at or above the aircraft ceiling is reset to the departure airport altitude;
a cruise altitude below the climb start altitude is raised to the climb start altitude;
a cruise altitude above the aircraft ceiling is lowered to the ceiling;
a descent end altitude at or above the ceiling is lowered to the ceiling;
a descent end altitude above the descent start altitude raises a
ValueError;a negative descent distance raises a
ValueError.
- class AEIC.trajectories.builders.adjustable_legacy.AdjustableLegacyBuilder(options=Options(optimize_traj=False, iterate_mass=True, use_weather=False, max_mass_iters=5, mass_iter_reltol=0.01), legacy_options=LegacyOptions(altitude_step=304.8, cruise_step=231500, fuel_LHV=43800000.0))
Model for determining flight trajectories using the legacy method from AEIC v2.
- Parameters:
options (Options) – Base options for trajectory building.
legacy_options (LegacyOptions) – Builder-specific options for legacy trajectory builder.
- CONTEXT_CLASS
alias of
AdjustableLegacyContext
- calc_starting_mass()
Calculates the starting mass using AEIC v2 methods. Sets both starting mass and non-reserve/hold/divert fuel mass.
- Return type:
float
- fly_climb(traj)
Simulate the climb phase of a trajectory.
Delegates to
_fly_level_changewith climb flight rules, integrating from the end of the previous phase up to the cruise-start altitude.- Parameters:
traj (Trajectory)
- Return type:
None
- fly_cruise(traj)
Simulate cruise phase.
Computes state over cruise segment using AEIC v2 methods based on BADA-3 formulas.
- Parameters:
traj (Trajectory)
- fly_descent(traj)
Simulate the descent phase of a trajectory.
Delegates to
_fly_level_changewith descent flight rules, integrating from the cruise altitude down to the descent-end altitude. The final per-phase point count is decremented by one to account for the shared boundary point with the next phase.- Parameters:
traj (Trajectory)
- Return type:
None
- class AEIC.trajectories.builders.adjustable_legacy.AdjustableLegacyContext(builder, ac_performance, mission, starting_mass, climb_start_altitude=None, cruise_altitude=None, descent_end_altitude=None, descent_distance=None, reserve_fuel=None, divert_distance=None, hold_time=None)
Context for adjustable legacy trajectory builder.
- Parameters:
builder (Builder)
ac_performance (BasePerformanceModel)
mission (Mission)
starting_mass (float | None)
climb_start_altitude (ContextAdjustment)
cruise_altitude (ContextAdjustment)
descent_end_altitude (ContextAdjustment)
descent_distance (ContextAdjustment)
reserve_fuel (ContextAdjustment)
divert_distance (ContextAdjustment)
hold_time (ContextAdjustment)
- class AdjustmentFunction(*args, **kwargs)
Protocol for context adjustment functions.
An adjustment function takes in the context, mission, performance model possibly additional optional keyword arguments and returns a float value.
- apply_adjustment(adjustment, mission, performance, **kwargs)
Helper function to apply a context adjustment.
- Parameters:
adjustment (ContextAdjustment)
mission (Mission)
performance (LegacyPerformanceModel)
- Return type:
float
Work-in-progress builders
The following builders are re-exported from
AEIC.trajectories.builders but are not yet fully implemented.
They are listed here so that consumers who notice them in the public API are
aware of their status; expect signatures, behaviour, and option sets to
change as the implementations land.
Each WIP builder ships with a matching *Options dataclass that is also
re-exported from AEIC.trajectories.builders. These option
classes are placeholders; their fields and defaults will change as the
corresponding builder is implemented.
TASOPT builder
TASOPTBuilder
will drive trajectory simulation from TASOPT-based performance data.
Configured via
TASOPTOptions.
Warning
This builder and its options class are stubs and cannot yet fly trajectories end-to-end.
ADS-B builder
ADSBBuilder
will reconstruct trajectories from ADS-B track data. Configured via
ADSBOptions.
Warning
This builder and its options class are stubs and cannot yet fly trajectories end-to-end.
Dymos builder
DymosBuilder
will drive trajectory simulation using the Dymos optimal-control library.
Configured via
DymosOptions.
Warning
This builder and its options class are stubs and cannot yet fly trajectories end-to-end.