contrailopt.Optimizer

class contrailopt.Optimizer(origin_icao: str | AirportCoords, dest_icao: str | AirportCoords, aircraft_type: str, takeoff_time: Timestamp, *, met: MetDataset | Dataset | None = None, eef: DataArray | MetDataArray | None = None, dag: HorizontalDAG | Track | None = None, cost_index: float = 60.0, dollar_tonne_co2e: float = 0.0, dollar_kg_fuel: float = 1.0, step_penalty_kg: float = 0.0, met_spacing_m: float = 25000.0, flight_hours: int | None = None, allow_cooling_credit: bool = False, avoidance_regions: list[list[tuple[float, float]]] | None = None, fl_choices: NDArray[float32] | None = None, **kwargs: Any)[source]

Trajectory optimizer based on the PS model with optional climate cost function.

The optimizer builds a horizontal directed acyclic graph between two airports, optionally interpolates met data onto edge sample points, and solves for the minimum-cost path across candidate flight levels and Mach numbers with solve_dag().

An instance built with from_flight() instead holds the lateral path fixed to a flown trajectory and optimizes only the vertical profile and Mach number with solve_track(). The kind property reports which of the two variants an instance is.

Parameters:
  • origin_icao (str or AirportCoords) – ICAO code for the origin airport (e.g. "KLAX"), or an AirportCoords instance.

  • dest_icao (str or AirportCoords) – ICAO code for the destination airport, or an AirportCoords instance.

  • aircraft_type (str) – Aircraft type key in the PS model parameter table (e.g. "A320").

  • takeoff_time (pandas.Timestamp) – Departure time, used for met interpolation.

  • met (MetDataset or xarray.Dataset or None, default None) – Gridded met data with air_temperature, eastward_wind, and northward_wind. If None, cruise performance uses ISA temperatures and zero wind.

  • eef (xarray.DataArray or MetDataArray or None, default None) – Optional eef_per_m DataArray on its own lon/lat grid. If provided, EEF is interpolated onto sample points independently from the weather grid, avoiding the need to pre-merge onto a common grid. Takes precedence over eef_per_m in met if both are present. Assumed to adhere to pycontrails MetDataArray conventions.

  • dag (HorizontalDAG or Track or None, default None) – Pre-built graph. If None, a HorizontalDAG is generated via Poisson-disk sampling along the great circle. A supplied HorizontalDAG must have origin and destination nodes agreeing with the airport coordinates. A Track is a fixed sequence of timed waypoints with mid-air endpoints, normally supplied by from_flight() rather than directly.

  • cost_index (float, default 60.0) – Fuel-vs-time tradeoff in kg per minute. Higher values penalize time more, favoring faster (and more fuel-intensive) routes.

  • dollar_tonne_co2e (float, default 0.0) – Carbon price in US dollars per tonne (1000kg) of CO2-equivalent. A value of 0.0 disables the carbon cost term. If positive, either met must contain a eef_per_m variable or the eef parameter must be provided.

  • dollar_kg_fuel (float, default 1.0) – Fuel price in US dollars per kg. Only used to convert the carbon cost into the fuel-equivalent units of the objective function. Ignored if dollar_tonne_co2e is 0.0.

  • step_penalty_kg (float, default 0.0) – Cost in kg of fuel charged for changing flight level, on top of the maneuver’s own fuel and time, to discourage marginally beneficial steps. The initial climb and final descent are exempt. The penalty enters the objective only, not the aircraft mass, so reported fuel burn stays physical.

  • met_spacing_m (float, default 25_000.0) – Spacing in meters between met sample points along each edge.

  • flight_hours (int or None, default None) – Upper-bound flight duration in hours for met time window. If None, estimated from the aircraft type. Providing an explicit value decouples the met lookup from the aircraft, allowing the user to call the solve() method with a different aircraft type without re-initializing the optimizer.

  • allow_cooling_credit (bool, default False) – If True, negative EEF (cooling contrails) reduces cost when dollar_tonne_co2e is set. If False, negative EEF is clipped to zero in the cost function but still reported in the output flight. Only used if dollar_tonne_co2e is set.

  • avoidance_regions (list[list[tuple[float, float]]] or None, default None) – Polygons to exclude from the search, defined as lists of (lon, lat) vertices. Edges intersecting any polygon are removed and the HorizontalDAG is re-pruned. Not supported when dag is a Track.

  • fl_choices (numpy.ndarray or None, default None) – Candidate cruise flight levels in feet. If None, the eastbound/westbound defaults from cruise_flight_levels() are used.

  • **kwargs – Additional parameters for HorizontalDAG generation if dag is None. Passed into HorizontalDAG.from_poisson().

__init__(origin_icao: str | AirportCoords, dest_icao: str | AirportCoords, aircraft_type: str, takeoff_time: Timestamp, *, met: MetDataset | Dataset | None = None, eef: DataArray | MetDataArray | None = None, dag: HorizontalDAG | Track | None = None, cost_index: float = 60.0, dollar_tonne_co2e: float = 0.0, dollar_kg_fuel: float = 1.0, step_penalty_kg: float = 0.0, met_spacing_m: float = 25000.0, flight_hours: int | None = None, allow_cooling_credit: bool = False, avoidance_regions: list[list[tuple[float, float]]] | None = None, fl_choices: NDArray[float32] | None = None, **kwargs: Any) → None[source]

Methods

__init__(origin_icao, dest_icao, ...[, met, ...])

animate_solve([display_fl_idx, ax])

Re-run the DP with converged mass and return a wavefront animation.

from_flight(flight, *[, met, fl_profile, ...])

Build a vertical-profile optimizer from a pycontrails.Flight trajectory.

plot_met([altitude_ft, time, ax, ...])

Plot met data on DAG nodes for a given flight level and time.

reconstruct_path()

Trace backpointers from destination to origin to recover the optimal path.

solve([n_iter, cost_index, ...])

Solve the trajectory optimization via shortest-path dynamic programming on the DAG.

to_flight()

Return the optimal trajectory as a pycontrails.Flight.

Attributes

eef_cost_factor

Compute the kg-fuel-equivalent cost per J of effective energy forcing.

kind

Return the optimization variant.

classmethod from_flight(flight: Flight, *, met: MetDataset | Dataset | None = None, fl_profile: Dataset | None = None, aircraft_type: str | None = None, origin_icao: str | None = None, dest_icao: str | None = None, eef: DataArray | MetDataArray | None = None, altitude_ft: NDArray[floating] | None = None, cost_index: float = 60.0, dollar_tonne_co2e: float = 0.0, dollar_kg_fuel: float = 1.0, allow_cooling_credit: bool = False, use_flown_climb_descent: bool = False) → Self[source]

Build a vertical-profile optimizer from a pycontrails.Flight trajectory.

The optimized flight follows the flight’s lateral path exactly, choosing flight level and Mach number along it via solve_track(). Weather comes from one of two sources:

  • met: raw gridded 4D met, used to interpolate the flight’s waypoints at each candidate flight level.

  • fl_profile: an already-interpolated (waypoint, altitude_ft) dataset carrying air_temperature, u_wind, v_wind, and optionally eef_per_m, aligned waypoint-for-waypoint with flight.

Parameters:
  • flight (Flight) – Trajectory supplying the lateral path, schedule, and (for use_flown_climb_descent) the flown altitude profile.

  • met (MetDataset or xarray.Dataset or None) – Gridded met to interpolate. Mutually exclusive with fl_profile.

  • fl_profile (xarray.Dataset or None) – Pre-interpolated per-waypoint met columns. Mutually exclusive with met.

  • aircraft_type (str or None) – PS model key. If None, taken from flight.attrs.

  • origin_icao (str or None) – ICAO codes. If None, taken from flight.attrs, else the nearest airport.

  • dest_icao (str or None) – ICAO codes. If None, taken from flight.attrs, else the nearest airport.

  • eef (xarray.DataArray or MetDataArray or None) – Effective energy forcing per meter, if supplied separately from met.

  • altitude_ft (numpy.ndarray or None) – Candidate flight levels in feet, used only with met. If None, the eastbound/westbound defaults from cruise_flight_levels() are used. With fl_profile the levels come from its altitude_ft coordinate.

  • cost_index (float, default 60.0) – Fuel-vs-time tradeoff in kg per minute.

  • dollar_tonne_co2e (float, default 0.0) – Carbon price per tonne CO2-equivalent. If positive, the met source must carry eef_per_m.

  • dollar_kg_fuel (float, default 1.0) – Fuel price per kg, converting carbon cost into fuel-equivalent units.

  • allow_cooling_credit (bool, default False) – If True, negative EEF reduces cost when dollar_tonne_co2e is set.

  • use_flown_climb_descent (bool, default False) – If True, the flown initial climb and final descent below the lowest candidate flight level are taken from flight unchanged, and only the cruise phase above it is optimized.

property eef_cost_factor: float

Compute the kg-fuel-equivalent cost per J of effective energy forcing.

property kind: str

Return the optimization variant.

Returns "track" for a fixed-path vertical-profile 2d optimizer (built via from_flight()), or "dag" for the full 4d lateral-plus-vertical DAG optimizer.

solve(n_iter: int = 3, cost_index: float | None = None, dollar_tonne_co2e: float | None = None, aircraft_type: str | None = None, payload: float | None = None, allow_cooling_credit: bool | None = None, step_penalty_kg: float | None = None) → DAGResult[source]

Solve the trajectory optimization via shortest-path dynamic programming on the DAG.

This method iteratively re-solves the DAG to converge on takeoff mass.

  • Estimate trip fuel from great-circle distance and set initial takeoff mass as landing mass + estimated trip fuel, capped at MTOW

  • Solve the dynamic program to find the optimal path and trip fuel

  • Update takeoff mass as landing mass + trip fuel, capped at MTOW

  • Stop after the takeoff mass estimate converges or after n_iter iterations

Parameters:
  • n_iter (int, default 3) – Maximum number of mass-convergence iterations. Each iteration re-solves the full DP.

  • cost_index (float or None, default None) – If provided, updates self.cost_index before solving. This parameter is safe to vary between calls without rebuilding intermediate artifacts.

  • dollar_tonne_co2e (float or None, default None) – If provided, updates self.dollar_tonne_co2e before solving. Safe to vary between calls without rebuilding intermediate artifacts.

  • aircraft_type (str or None, default None) – If provided, updates self.aircraft_type, self.atyp, and self.mach_choices before solving. Safe to vary between calls without rebuilding the DAG or met lookup provided the met lookup was built with a sufficiently long flight_hours window to accommodate the new aircraft’s speed.

  • payload (float or None, default None) – Aircraft payload in kg if known. If None, this is estimated with pycontrails.

  • allow_cooling_credit (bool or None, default None) – If provided, updates self.allow_cooling_credit before solving.

Returns:

DP state, takeoff mass, trip fuel, payload, reserve fuel, and landing mass.

Return type:

DAGResult

reconstruct_path() → tuple[NDArray[int64], NDArray[int64], NDArray[float32]][source]

Trace backpointers from destination to origin to recover the optimal path.

The returned arrays are ordered origin-first.

Geographic coordinates for each waypoint are available via self.dag.lon[path_h] and self.dag.lat[path_h]. Flight levels are self.fl_choices[path_fl_idx] for interior waypoints; the origin uses a sentinel index (len(fl_choices)) representing ground level.

Returns:

  • path_h (numpy.ndarray) – Horizontal node indices along the path. The first and last entries are origin and destination.

  • path_fl_idx (numpy.ndarray) – Flight level index at each node. The origin uses a sentinel ground_fl_idx = len(fl_choices); the destination uses the actual cruise FL from which the final descent begins.

  • path_mach (numpy.ndarray) – Cruise Mach number on each incoming leg. The first entry path_mach[0] is NaN (no incoming leg at the origin).

to_flight() → Flight[source]

Return the optimal trajectory as a pycontrails.Flight.

When met data is available, waypoints are emitted at each edge sample point (~20 km spacing) with proper climb/descent altitude profiles and per-sample eef_per_m. Without met, falls back to one waypoint per DAG node.

The solve() method must be called first.

plot_met(altitude_ft: float | None = None, time: Timestamp | None = None, ax: GeoAxes | None = None, show_wind_quiver: bool = True, show_eef: bool = True, **kwargs) → GeoAxes[source]

Plot met data on DAG nodes for a given flight level and time.

Draws a wind quiver overlay. When eef_per_m is available in the met_lookup, also draws a scatter plot colored by EEF.

Parameters:
  • altitude_ft (float or None) – Flight level in feet (e.g. 37000). Snaps to the nearest available level. If None, uses the first available level.

  • time (pandas.Timestamp or None) – Time to select. Snaps to the nearest available time step. If None, uses the first available time step.

  • ax (GeoAxes or None) – Cartopy GeoAxes to plot on. If None, calls self.dag.plot() to create one.

  • **kwargs – Passed to ax.quiver.

Returns:

The axes with the met overlay.

Return type:

GeoAxes

animate_solve(display_fl_idx: int | None = None, ax: GeoAxes | None = None) → FuncAnimation[source]

Re-run the DP with converged mass and return a wavefront animation.

solve() must be called first. This re-runs a single solve_dag() pass with the converged amass_init, capturing wavefront snapshots.

Nodes are colored by best_cost[:, display_fl_idx] for a single FL. Edges whose source node has been processed are shown in blue; remaining edges are shown muted. The optimal path is then revealed dest to origin, matching the backpointer reconstruction order.

Parameters:
  • display_fl_idx (int or None) – FL index into fl_choices to display costs for. If None, uses the FL the optimal path spends the most legs at.

  • ax (GeoAxes or None) – Cartopy GeoAxes to draw on. If None, a new figure is created.

Returns:

Wavefront animation with cost coloring and optimal path reveal.

Return type:

FuncAnimation