pycontrails.core.fleet#

A single data structure encompassing a sequence of Flight instances.

Classes

Fleet([data, longitude, latitude, altitude, ...])

Data structure for holding a sequence of Flight instances.

class pycontrails.core.fleet.Fleet(data=None, *, longitude=None, latitude=None, altitude=None, altitude_ft=None, level=None, time=None, attrs=None, copy=True, fuel=None, fl_attrs=None, **attrs_kwargs)#

Bases: Flight

Data structure for holding a sequence of Flight instances.

Flight waypoints are merged into a single Flight-like object.

copy()#

Return a copy of this VectorDatasetType class.

Returns:

VectorDatasetType – Copy of class

final_waypoints#
fit_altitude(max_segments=30, pop=3, r2_target=0.999, max_cruise_rocd=10, sg_window=7, sg_polyorder=1)#

Use piecewise linear fitting to smooth a flight profile.

Fit a flight profile to a series of line segments. Segments that have a small rocd will be set to have a slope of zero and snapped to the nearest thousand foot level. A Savitzky-Golay filter will then be applied to the profile to smooth the climbs and descents. This filter works best for high frequency flight data, sampled at a 1-3 second sampling period.

Parameters:
  • max_segments (int, optional) – The maximum number of line segements to fit to the flight profile.

  • pop (int, optional) – Population parameter used for the stocastic optimization routine used to fit the flight profile.

  • r2_target (float, optional) – Target r^2 value for solver. Solver will continue to add line segments until the resulting r^2 value is greater than this.

  • max_cruise_rocd (float, optional) – The maximum ROCD for a segment that will be forced to a slope of zero, [\(ft s^{-1}\)]

  • sg_window (int, optional) – Parameter for scipy.signal.savgol_filter()

  • sg_polyorder (int, optional) – Parameter for scipy.signal.savgol_filter()

Returns:

Flight – Smoothed flight

fl_attrs#
classmethod from_seq(seq, broadcast_numeric=True, copy=True, attrs=None)#

Instantiate a Fleet instance from an iterable of Flight.

Parameters:
  • seq (Iterable[Flight]) – An iterable of Flight instances.

  • broadcast_numeric (bool, optional) – If True, broadcast numeric attributes to data variables.

  • copy (bool, optional) – If True, make copy of each flight instance in seq.

  • attrs (dict[str, Any] | None, optional) – Global attribute to attach to instance.

Returns:

Fleet – A Fleet instance made from concatenating the Flight instances in seq. The fuel type is taken from the first Flight in seq.

property max_distance_gap#

Return maximum distance gap between waypoints along flight trajectory.

Distance is calculated based on WGS84 geodesic.

Returns:

float – Maximum distance between waypoints, [\(m\)]

Raises:

NotImplementedError – Raises when attr:attrs[“crs”] is not EPSG:4326

Examples

>>> import numpy as np
>>> fl = Flight(
...     longitude=np.linspace(20, 30, 200),
...     latitude=np.linspace(40, 30, 200),
...     altitude=11000 * np.ones(200),
...     time=pd.date_range('2021-01-01T12', '2021-01-01T14', periods=200),
... )
>>> fl.max_distance_gap
7391.27...
property n_flights#

Return number of distinct flights.

Returns:

int – Number of flights

resample_and_fill(*args, **kwargs)#

Resample and fill flight trajectory with geodesics and linear interpolation.

Waypoints are resampled according to the frequency freq. Values for data columns longitude, latitude, and altitude are interpolated.

Parameters:
  • freq (str, optional) – Resampling frequency, by default “1T”

  • fill_method ({"geodesic", "linear"}, optional) – Choose between "geodesic" and "linear", by default "geodesic". In geodesic mode, large gaps between waypoints are filled with geodesic interpolation and small gaps are filled with linear interpolation. In linear mode, all gaps are filled with linear interpolation.

  • geodesic_threshold (float, optional) – Threshold for geodesic interpolation, [\(m\)]. If the distance between consecutive waypoints is under this threshold, values are interpolated linearly.

  • nominal_rocd (float | None, optional) – Nominal rate of climb / descent for aircraft type. Defaults to constants.nominal_rocd.

  • drop (bool, optional) – Drop any columns that are not resampled and filled. Defaults to True, dropping all keys outside of “time”, “latitude”, “longitude” and “altitude”. If set to False, the extra keys will be kept but filled with nan or None values, depending on the data type.

  • keep_original_index (bool, optional) – Keep the original index of the Flight in addition to the new resampled index. Defaults to False. .. versionadded:: 0.45.2

  • climb_or_descend_at_end (bool) – If true, the climb or descent will be placed at the end of each segment rather than the start. Default is false (climb or descent immediately).

Returns:

Flight – Filled Flight

Raises:

ValueError – Unknown fill_method

Examples

>>> from datetime import datetime
>>> import pandas as pd
>>> df = pd.DataFrame()
>>> df['longitude'] = [0, 0, 50]
>>> df['latitude'] = 0
>>> df['altitude'] = 0
>>> df['time'] = [datetime(2020, 1, 1, h) for h in range(3)]
>>> fl = Flight(df)
>>> fl.dataframe
   longitude  latitude  altitude                time
           0        0.0       0.0       0.0 2020-01-01 00:00:00
           1        0.0       0.0       0.0 2020-01-01 01:00:00
           2       50.0       0.0       0.0 2020-01-01 02:00:00
>>> fl.resample_and_fill('10T').dataframe  # resample with 10 minute frequency
    longitude  latitude  altitude                time
0    0.000000       0.0       0.0 2020-01-01 00:00:00
1    0.000000       0.0       0.0 2020-01-01 00:10:00
2    0.000000       0.0       0.0 2020-01-01 00:20:00
3    0.000000       0.0       0.0 2020-01-01 00:30:00
4    0.000000       0.0       0.0 2020-01-01 00:40:00
5    0.000000       0.0       0.0 2020-01-01 00:50:00
6    0.000000       0.0       0.0 2020-01-01 01:00:00
7    8.333333       0.0       0.0 2020-01-01 01:10:00
8   16.666667       0.0       0.0 2020-01-01 01:20:00
9   25.000000       0.0       0.0 2020-01-01 01:30:00
10  33.333333       0.0       0.0 2020-01-01 01:40:00
11  41.666667       0.0       0.0 2020-01-01 01:50:00
12  50.000000       0.0       0.0 2020-01-01 02:00:00
segment_angle()#

Calculate sine and cosine for the angle between each segment and the longitudinal axis.

This is different from the usual navigational angle between two points known as bearing.

Bearing in 3D spherical coordinates is referred to as azimuth.

        (lon_2, lat_2)  X
                       /|
                      / |
                     /  |
                    /   |
                   /    |
                  /     |
                 /      |
(lon_1, lat_1)  X -------> longitude (x-axis)
Returns:

npt.NDArray[np.float_], npt.NDArray[np.float_] – Returns sin(a), cos(a), where a is the angle between the segment and the longitudinal axis. The final values are of both arrays are np.nan.

See also

geo.segment_angle(), units.heading_to_longitudinal_angle(), segment_azimuth(), geo.forward_azimuth()

Examples

>>> from pycontrails import Flight
>>> fl = Flight(
... longitude=np.array([1, 2, 3, 5, 8]),
... latitude=np.arange(5),
... altitude=np.full(shape=(5,), fill_value=11000),
... time=pd.date_range('2021-01-01T12', '2021-01-01T14', periods=5),
... )
>>> sin, cos = fl.segment_angle()
>>> sin
array([0.70716063, 0.70737598, 0.44819424, 0.31820671,        nan])
>>> cos
array([0.70705293, 0.70683748, 0.8939362 , 0.94802136,        nan])
segment_azimuth()#

Calculate (forward) azimuth at each waypoint.

Method calls pyproj.Geod.inv, which is slow. See geo.forward_azimuth for an outline of a faster implementation.

Changed in version 0.33.7: The dtype of the output now matches the dtype of self["longitude"].

Returns:

npt.NDArray[np.float_] – Array of azimuths.

See also

segment_angle(), geo.forward_azimuth()

segment_groundspeed(*args, **kwargs)#

Return groundspeed across segments.

Calculate by dividing the horizontal segment length by the difference in waypoint times.

Parameters:
Returns:

npt.NDArray[np.float_] – Groundspeed of the segment, [\(m s^{-1}\)]

segment_length()#

Compute spherical distance between flight waypoints.

Helper function used in length() and length_met(). np.nan appended so the length of the output is the same as number of waypoints.

Returns:

npt.NDArray[np.float_] – Array of distances in [\(m\)] between waypoints

Raises:

NotImplementedError – Raises when attr:attrs[“crs”] is not EPSG:4326

Examples

>>> from pycontrails import Flight
>>> fl = Flight(
... longitude=np.array([1, 2, 3, 5, 8]),
... latitude=np.arange(5),
... altitude=np.full(shape=(5,), fill_value=11000),
... time=pd.date_range('2021-01-01T12', '2021-01-01T14', periods=5),
... )
>>> fl.segment_length()
array([157255.03346286, 157231.08336815, 248456.48781503, 351047.44358851,
                   nan])

See also

segment_length()

segment_true_airspeed(u_wind=0.0, v_wind=0.0, smooth=True, window_length=7, polyorder=1)#

Calculate the true airspeed [\(m / s\)] from the ground speed and horizontal winds.

Because Flight.segment_true_airspeed uses a smoothing pattern, waypoints in data are not independent. Moreover, we expect the final waypoint of each flight to have a nan value associated to any segment property. Consequently, we need to define a custom method here to deal with these issues when applying this method on a fleet of flights.

See docstring for Flight.segment_true_airspeed().

Raises:

RuntimeError – Unexpected key __u_wind or __v_wind found in data.

to_flight_list(copy=True)#

De-concatenate merged waypoints into a list of Flight instances.

Any global attrs are lost.

Parameters:

copy (bool, optional) – If True, make copy of each flight instance in seq.

Returns:

list[Flight] – List of Flights in the same order as was passed into the Fleet instance.