def test_geometry() -> None: flight: Flight = get_sample(featured, "belevingsvlucht") xy_length = flight.project_shape().length / 1852 # in nm last_pos = flight.cumulative_distance().at() assert last_pos is not None cumdist = last_pos.cumdist assert abs(xy_length - cumdist) / xy_length < 1e-3 simplified = flight.simplify(1e3) assert len(simplified) < len(flight) xy_length_s = simplified.project_shape().length / 1852 assert xy_length_s < xy_length simplified_3d = flight.simplify(1e3, altitude="altitude") assert len(simplified) < len(simplified_3d) < len(flight) assert flight.intersects(eurofirs["EHAA"]) assert flight.intersects(eurofirs["EHAA"].flatten()) assert not flight.intersects(eurofirs["LFBB"]) assert flight.distance(eurofirs["EHAA"]).data.distance.mean() < 0 airbus_tree: Flight = get_sample(featured, "airbus_tree") clip_dk = airbus_tree.clip(eurofirs["EKDK"]) assert clip_dk is not None assert clip_dk.duration < flight.duration clip_gg = airbus_tree.clip(eurofirs["EDGG"]) assert clip_gg is not None assert clip_gg.duration < flight.duration clip_mm = airbus_tree.clip(eurofirs["EDMM"]) assert clip_mm is not None assert clip_mm.duration < flight.duration
def test_landing_runway() -> None: # TODO refactor/rethink the returned type flight: Flight = get_sample(featured, "belevingsvlucht") assert flight.guess_landing_runway().name == "06" airbus_tree: Flight = get_sample(featured, "airbus_tree") assert airbus_tree.guess_landing_runway().name == "23"
def test_landing_airport() -> None: # TODO refactor/rethink the returned type flight: Flight = get_sample(featured, "belevingsvlucht") assert flight.guess_landing_airport().airport.icao == "EHAM" airbus_tree: Flight = get_sample(featured, "airbus_tree") assert airbus_tree.guess_landing_airport().airport.icao == "EDHI"
def test_decode(): opensky.cache_dir = Path(__file__).parent.parent / "data" / "opensky_cache" # with zipfile.ZipFile(opensky.cache_dir / "opensky_cache.zip") as zfile: # zfile.extractall(path=opensky.cache_dir) switzerland: Traffic = get_sample(collections, "switzerland") tap_switzerland = ( switzerland.query('callsign.str.startswith("TAP127")').filter_if( long_enough).query_opensky().resample("1s").query_ehs().filter( selected_mcp=23).filter( altitude=53, selected_mcp=53, roll=53, heading=53).resample("1s").eval(desc="")) # BDS 4,0 for f in tap_switzerland: # This is only safe en route. Even if the selected MCP altitude # changes, altitude should be between min/max (modulo data errors) assert all((f.min("selected_mcp") - 100 <= f.data.altitude) & (f.data.altitude <= f.max("selected_mcp") + 100)) # BDS 5,0 and BDS 6,0 for f in tap_switzerland: # An aircraft should turn to the side it is rolling f = f.assign(diff_heading=lambda df: df.heading.diff() * df.roll) assert sum(f.data.diff_heading + 1 < 0) / len(f) < 1e-3
def test_cpa() -> None: switzerland = cast(Traffic, get_sample(collections, "switzerland")) smaller = ( switzerland.between("2018-08-01 12:00", "2018-08-01 14:00") .assign_id() .eval() ) assert smaller is not None cpa = smaller.closest_point_of_approach( lateral_separation=10 * 1852, vertical_separation=2000, projection=CH1903p(), round_t="10T", ) assert cpa is not None separation = dict(lateral_separation=5, vertical_separation=1000) res15 = cpa.aggregate(**separation)["0a0075"].query("aggregated < 1.5") assert res15 is not None res = res15.min("aggregated") callsigns = {*res.data.callsign_x, *res.data.callsign_y} assert callsigns == {"BAW2591", "BAW605", "DAH2062", "EZY54UC"} assert len(res.flight_ids()) == 4
def test_bearing() -> None: ajaccio: Flight = get_sample(calibration, "ajaccio") vor = navaids.extent(ajaccio)["AJO"] assert vor is not None gen = ajaccio.bearing(vor).query("bearing.diff().abs() < .01").split("1T") assert (sum(1 for chunk in gen if chunk.duration > pd.Timedelta("5 minutes")) == 7)
def test_bearing() -> None: ajaccio: Flight = get_sample(calibration, "ajaccio") ext_navaids = navaids.extent(ajaccio) assert ext_navaids is not None vor = ext_navaids["AJO"] assert vor is not None subset = ajaccio.bearing(vor).query("bearing.diff().abs() < .01") assert subset is not None assert (sum(1 for chunk in subset.split("1T") if chunk.duration > pd.Timedelta("5 minutes")) == 7)
def test_chaining() -> None: switzerland: Traffic = get_sample(collections, "switzerland") sw_filtered = (switzerland.assign_id().filter_if(high_altitude).resample( "10s").filter().filter(altitude=53).unwrap().airborne().eval( max_workers=4)) flight_id: str = sw_filtered.flight_ids.pop() handle = sw_filtered[flight_id] assert handle is not None assert handle.callsign == flight_id.split("_")[0] assert len(sw_filtered) == 784 assert sw_filtered.data.shape[0] == 86399 assert min(len(f) for f in sw_filtered) == 61 assert sw_filtered.data.altitude.max() == 47000.0
def test_properties() -> None: flight: Flight = get_sample(featured, "belevingsvlucht") assert len(flight) == 16005 assert flight.min("altitude") == -59 # Welcome to the Netherlands! assert flight.max("altitude") == 18025 assert f"{flight.start}" == "2018-05-30 15:21:38+00:00" assert f"{flight.stop}" == "2018-05-30 20:22:56+00:00" assert flight.callsign == "TRA051" assert flight.title == "TRA051" assert flight.icao24 == "484506" assert flight.registration == "PH-HZO" assert flight.typecode == "B738" assert flight.aircraft == "484506 / PH-HZO (B738)" assert flight.flight_id is None
def test_time_methods() -> None: flight: Flight = get_sample(featured, "belevingsvlucht") assert f"{flight.first(minutes=10).stop}" == "2018-05-30 15:31:37+00:00" assert f"{flight.last(minutes=10).start}" == "2018-05-30 20:12:57+00:00" # between is a combination of before and after before_after = flight.before("2018-05-30 19:00").after("2018-05-30 18:00") between = flight.between("2018-05-30 18:00", "2018-05-30 19:00") # flight comparison made by distance computation assert before_after.distance(between).lateral.sum() < 1e-6 assert between.distance(before_after).vertical.sum() < 1e-6 # test of at() method and equality on the positions t = "2018-05-30 18:30" assert (between.at(t) == before_after.at(t)).all() # type: ignore
def test_iterators() -> None: flight: Flight = get_sample(featured, "belevingsvlucht") assert min(flight.timestamp) == flight.start assert max(flight.timestamp) == flight.stop assert min(flight.coords)[0] == flight.min("longitude") assert max(flight.coords)[0] == flight.max("longitude") max_time = max(flight.coords4d()) last_point = flight.at() assert last_point is not None assert max_time[1] == last_point.longitude assert max_time[2] == last_point.latitude assert max_time[3] == last_point.altitude max_xy_time = list(flight.xy_time)[-1] assert max_xy_time[0] == last_point.longitude assert max_xy_time[1] == last_point.latitude assert max_xy_time[2] == last_point.timestamp.to_pydatetime().timestamp()
def test_properties() -> None: switzerland: Traffic = get_sample(collections, "switzerland") assert len(switzerland) == 1244 assert f"{switzerland.start_time}" == "2018-08-01 05:00:00+00:00" assert f"{switzerland.end_time}" == "2018-08-01 21:59:50+00:00" # TODO change @lru_cache on @property, rename Traffic.aircraft assert len(switzerland.callsigns) == 1243 # type: ignore assert len(switzerland.aircraft) == 842 # type: ignore handle = switzerland["DLH02A"] assert handle is not None assert handle.aircraft == "3c6645 / D-AIRE (A321)" handle = switzerland["4baa61"] assert handle is not None assert handle.callsign == "THY7WR" selected = max(switzerland, key=lambda flight: flight.min("altitude")) assert selected.flight_id is None assert selected.min("altitude") == 47000.0 assert selected.icao24 == "aab6c0"
def test_clustering() -> None: switzerland: Traffic = get_sample(collections, "switzerland") smaller = cast( Traffic, switzerland.between( "2018-08-01 12:00", "2018-08-01 14:00").assign_id().eval(max_workers=4), ) t_clustering = smaller.clustering( nb_samples=15, projection=CH1903p(), features=["x", "y"], clustering=StupidClustering(), ).fit_predict() v1, v2 = (t_clustering.groupby(["cluster"]).agg({ "flight_id": "nunique" }).flight_id) assert abs(v1 - v2) <= 1
def test_generation() -> None: switzerland = cast(Traffic, get_sample(collections, "switzerland")) def compute_timedelta(df: pd.DataFrame) -> pd.Series: return (df.timestamp - df.timestamp.min()).dt.total_seconds() smaller = ( switzerland.between("2018-08-01 12:00", "2018-08-01 14:00") .assign_id() .resample(10) .compute_xy(projection=EuroPP()) .assign(timedelta=compute_timedelta) .eval() ) assert isinstance(smaller, Traffic) g = smaller.generation( generation=NaiveGeneration(), features=["track", "groundspeed", "altitude", "timedelta"], ) t_gen = g.sample(5, coordinates={"latitude": 15, "longitude": 15}) assert isinstance(t_gen, Traffic) assert len(t_gen) == 5 assert isinstance(t_gen[0], Flight) g = smaller.generation( generation=NaiveGeneration(), features=["x", "y", "altitude", "timedelta"], ) t_gen = g.sample(6, projection=EuroPP()) assert isinstance(t_gen, Traffic) assert len(t_gen) == 6 assert isinstance(t_gen[0], Flight)
def test_decode() -> None: switzerland = cast(Traffic, get_sample(collections, "switzerland")) tap_switzerland = ( switzerland.query( # type: ignore 'callsign.str.startswith("TAP127")', engine="python").filter_if(long_enough).query_opensky().resample( "1s").query_ehs().filter(selected_mcp=23).filter( altitude=53, selected_mcp=53, roll=53, heading=53).resample("1s").eval(desc="")) # BDS 4,0 for f in tap_switzerland: # This is only safe en route. Even if the selected MCP altitude # changes, altitude should be between min/max (modulo data errors) assert all((f.min("selected_mcp") - 100 <= f.data.altitude) & (f.data.altitude <= f.max("selected_mcp") + 100)) # BDS 5,0 and BDS 6,0 for f in tap_switzerland: # An aircraft should turn to the side it is rolling f = f.assign(diff_heading=lambda df: df.heading.diff() * df.roll) assert sum(f.data.diff_heading + 1 < 0) / len(f) < 1e-3
def test_get_traffic() -> None: traffic: Traffic = get_sample(featured, "traffic") assert "belevingsvlucht" in traffic.flight_ids
def test_emptydata() -> None: airbus_tree: Flight = get_sample(featured, "airbus_tree") assert airbus_tree.registration == "F-WWAE" assert airbus_tree.typecode == "A388"