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 builderr 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.

Documentation for the base Builder class is currently sparse, and the best reference to how to use these things is to look at the LegacyBuilder implementation. Actually using the trajectory builders is simple, but implementing a builder is more complicated!

Warning

Some of this code is definitely unfinished. There needs to be a way to incrementally extend trajectories instead of having to specify the length of the trajectory up-front, and there needs to be a smoother API for the builders to save trajectory data for different flight phases. At the moment, there are no helper methods to deal with the “extra” LTO flight phases at all.

class AEIC.trajectories.builders.base.Builder(options: Options = Options(optimize_traj=False, iterate_mass=True, use_weather=False, max_mass_iters=5, mass_iter_reltol=0.01), *args, **kwargs)

Abstract parent class for all AEIC trajectory builders. Contains overall fly logic.

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(**kwargs) float

Calculate the starting mass of the aircraft for the flight.

fly(ac_performance: PerformanceModel, mission: Mission, starting_mass: float | None = None, **kwargs) Trajectory

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 (PerformanceModel) – Performance model used for trajectory simulation.

  • mission (Mission) – Data dictating the mission to be flown (departure/arrival info, etc.).

  • startMass (float, optional) – Starting mass of the aircraft; leave as default to calculate starting mass during simulation.

Returns:

Trajectory object.

Return type:

trajectory (Trajectory)

property n_climb: int

Number of trajectory points in climb phase.

property n_cruise: int

Number of trajectory points in cruise phase.

property n_descent: int

Number of trajectory points in descent phase.

property n_total: int

Total number of trajectory points.

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 = Options(optimize_traj=False, iterate_mass=True, use_weather=False, max_mass_iters=5, mass_iter_reltol=0.01), legacy_options: LegacyOptions = LegacyOptions(pct_step_clm=0.01, pct_step_crz=0.01, pct_step_des=0.01, fuel_LHV=43800000.0), *args, **kwargs)

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(**kwargs) float

Calculates the starting mass using AEIC v2 methods. Sets both starting mass and non-reserve/hold/divert fuel mass.

fly_climb(traj: Trajectory, **kwargs) None

Simulate climb phase.

Computes state over the climb segment using AEIC v2 methods based on BADA-3 formulas.

fly_cruise(traj: Trajectory, **kwargs)

Simulate cruise phase.

Computes state over cruise segment using AEIC v2 methods based on BADA-3 formulas

fly_descent(traj: Trajectory, **kwargs)

Simulate descent phase.

Computes state over the descent segment using AEIC v2 methods based on BADA-3 formulas

class AEIC.trajectories.builders.legacy.LegacyContext(builder: LegacyBuilder, ac_performance: PerformanceModel, mission: Mission, starting_mass: float | None)

Context for legacy trajectory builder.

class AEIC.trajectories.builders.legacy.LegacyOptions(pct_step_clm: float = 0.01, pct_step_crz: float = 0.01, pct_step_des: float = 0.01, fuel_LHV: float = 43800000.0)

Additional options for the legacy trajectory builder.

fuel_LHV: float = 43800000.0

Lower heating value of the fuel used.

pct_step_clm: float = 0.01

Climb step size as percentage of total climb altitude change.

pct_step_crz: float = 0.01

Cruise step size as percentage of total cruise ground distance.

pct_step_des: float = 0.01

Descent step size as percentage of total descent altitude change.