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 withsolve_track(). Thekindproperty reports which of the two variants an instance is.- Parameters:
origin_icao (
strorAirportCoords) – ICAO code for the origin airport (e.g."KLAX"), or anAirportCoordsinstance.dest_icao (
strorAirportCoords) – ICAO code for the destination airport, or anAirportCoordsinstance.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 (
MetDatasetorxarray.DatasetorNone, defaultNone) – Gridded met data withair_temperature,eastward_wind, andnorthward_wind. If None, cruise performance uses ISA temperatures and zero wind.eef (
xarray.DataArrayorMetDataArrayorNone, defaultNone) – Optionaleef_per_mDataArray 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 overeef_per_minmetif both are present. Assumed to adhere to pycontrailsMetDataArrayconventions.dag (
HorizontalDAGorTrackorNone, defaultNone) – Pre-built graph. If None, aHorizontalDAGis generated via Poisson-disk sampling along the great circle. A suppliedHorizontalDAGmust have origin and destination nodes agreeing with the airport coordinates. ATrackis a fixed sequence of timed waypoints with mid-air endpoints, normally supplied byfrom_flight()rather than directly.cost_index (
float, default60.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, default0.0) – Carbon price in US dollars per tonne (1000kg) of CO2-equivalent. A value of 0.0 disables the carbon cost term. If positive, eithermetmust contain aeef_per_mvariable or theeefparameter must be provided.dollar_kg_fuel (
float, default1.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 ifdollar_tonne_co2eis 0.0.step_penalty_kg (
float, default0.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, default25_000.0) – Spacing in meters between met sample points along each edge.flight_hours (
intorNone, defaultNone) – 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 thesolve()method with a different aircraft type without re-initializing the optimizer.allow_cooling_credit (
bool, defaultFalse) – If True, negative EEF (cooling contrails) reduces cost whendollar_tonne_co2eis set. If False, negative EEF is clipped to zero in the cost function but still reported in the output flight. Only used ifdollar_tonne_co2eis set.avoidance_regions (
list[list[tuple[float,float]]]orNone, defaultNone) – Polygons to exclude from the search, defined as lists of(lon, lat)vertices. Edges intersecting any polygon are removed and theHorizontalDAGis re-pruned. Not supported whendagis aTrack.fl_choices (
numpy.ndarrayorNone, defaultNone) – Candidate cruise flight levels in feet. If None, the eastbound/westbound defaults fromcruise_flight_levels()are used.**kwargs – Additional parameters for
HorizontalDAGgeneration ifdagis None. Passed intoHorizontalDAG.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.Flighttrajectory.plot_met([altitude_ft, time, ax, ...])Plot met data on DAG nodes for a given flight level and time.
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.
Return the optimal trajectory as a
pycontrails.Flight.Attributes
Compute the kg-fuel-equivalent cost per J of effective energy forcing.
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.Flighttrajectory.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 carryingair_temperature,u_wind,v_wind, and optionallyeef_per_m, aligned waypoint-for-waypoint withflight.
- Parameters:
flight (
Flight) – Trajectory supplying the lateral path, schedule, and (foruse_flown_climb_descent) the flown altitude profile.met (
MetDatasetorxarray.DatasetorNone) – Gridded met to interpolate. Mutually exclusive withfl_profile.fl_profile (
xarray.DatasetorNone) – Pre-interpolated per-waypoint met columns. Mutually exclusive withmet.aircraft_type (
strorNone) – PS model key. If None, taken fromflight.attrs.origin_icao (
strorNone) – ICAO codes. If None, taken fromflight.attrs, else the nearest airport.dest_icao (
strorNone) – ICAO codes. If None, taken fromflight.attrs, else the nearest airport.eef (
xarray.DataArrayorMetDataArrayorNone) – Effective energy forcing per meter, if supplied separately frommet.altitude_ft (
numpy.ndarrayorNone) – Candidate flight levels in feet, used only withmet. If None, the eastbound/westbound defaults fromcruise_flight_levels()are used. Withfl_profilethe levels come from itsaltitude_ftcoordinate.cost_index (
float, default60.0) – Fuel-vs-time tradeoff in kg per minute.dollar_tonne_co2e (
float, default0.0) – Carbon price per tonne CO2-equivalent. If positive, the met source must carryeef_per_m.dollar_kg_fuel (
float, default1.0) – Fuel price per kg, converting carbon cost into fuel-equivalent units.allow_cooling_credit (
bool, defaultFalse) – If True, negative EEF reduces cost whendollar_tonne_co2eis set.use_flown_climb_descent (
bool, defaultFalse) – If True, the flown initial climb and final descent below the lowest candidate flight level are taken fromflightunchanged, 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 viafrom_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 MTOWSolve the dynamic program to find the optimal path and trip fuel
Update takeoff mass as
landing mass + trip fuel, capped at MTOWStop after the takeoff mass estimate converges or after
n_iteriterations
- Parameters:
n_iter (
int, default3) – Maximum number of mass-convergence iterations. Each iteration re-solves the full DP.cost_index (
floatorNone, defaultNone) – If provided, updatesself.cost_indexbefore solving. This parameter is safe to vary between calls without rebuilding intermediate artifacts.dollar_tonne_co2e (
floatorNone, defaultNone) – If provided, updatesself.dollar_tonne_co2ebefore solving. Safe to vary between calls without rebuilding intermediate artifacts.aircraft_type (
strorNone, defaultNone) – If provided, updatesself.aircraft_type,self.atyp, andself.mach_choicesbefore solving. Safe to vary between calls without rebuilding the DAG or met lookup provided the met lookup was built with a sufficiently longflight_hourswindow to accommodate the new aircraft’s speed.payload (
floatorNone, defaultNone) – Aircraft payload in kg if known. If None, this is estimated with pycontrails.allow_cooling_credit (
boolorNone, defaultNone) – If provided, updatesself.allow_cooling_creditbefore solving.
- Returns:
DP state, takeoff mass, trip fuel, payload, reserve fuel, and landing mass.
- Return type:
- 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]andself.dag.lat[path_h]. Flight levels areself.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 sentinelground_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 entrypath_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_mis available in themet_lookup, also draws a scatter plot colored by EEF.- Parameters:
altitude_ft (
floatorNone) – Flight level in feet (e.g.37000). Snaps to the nearest available level. If None, uses the first available level.time (
pandas.TimestamporNone) – Time to select. Snaps to the nearest available time step. If None, uses the first available time step.ax (
GeoAxesorNone) – Cartopy GeoAxes to plot on. If None, callsself.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 singlesolve_dag()pass with the convergedamass_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:
- Returns:
Wavefront animation with cost coloring and optimal path reveal.
- Return type: