pycontrails 0.54.3__cp311-cp311-macosx_11_0_arm64.whl → 0.54.5__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pycontrails might be problematic. Click here for more details.
- pycontrails/__init__.py +2 -2
- pycontrails/_version.py +2 -2
- pycontrails/core/__init__.py +1 -1
- pycontrails/core/aircraft_performance.py +58 -58
- pycontrails/core/cache.py +7 -7
- pycontrails/core/fleet.py +54 -29
- pycontrails/core/flight.py +218 -301
- pycontrails/core/interpolation.py +63 -60
- pycontrails/core/met.py +193 -125
- pycontrails/core/models.py +27 -13
- pycontrails/core/polygon.py +15 -15
- pycontrails/core/rgi_cython.cpython-311-darwin.so +0 -0
- pycontrails/core/vector.py +119 -96
- pycontrails/datalib/_met_utils/metsource.py +8 -5
- pycontrails/datalib/ecmwf/__init__.py +14 -14
- pycontrails/datalib/ecmwf/common.py +1 -1
- pycontrails/datalib/ecmwf/era5.py +7 -7
- pycontrails/datalib/ecmwf/hres.py +3 -3
- pycontrails/datalib/ecmwf/ifs.py +1 -1
- pycontrails/datalib/gfs/__init__.py +6 -6
- pycontrails/datalib/gfs/gfs.py +2 -2
- pycontrails/datalib/goes.py +5 -5
- pycontrails/ext/empirical_grid.py +1 -1
- pycontrails/models/apcemm/apcemm.py +5 -5
- pycontrails/models/apcemm/utils.py +1 -1
- pycontrails/models/cocip/__init__.py +2 -2
- pycontrails/models/cocip/cocip.py +23 -24
- pycontrails/models/cocip/cocip_params.py +2 -11
- pycontrails/models/cocip/cocip_uncertainty.py +24 -18
- pycontrails/models/cocip/contrail_properties.py +331 -316
- pycontrails/models/cocip/output_formats.py +53 -53
- pycontrails/models/cocip/radiative_forcing.py +135 -131
- pycontrails/models/cocip/radiative_heating.py +135 -135
- pycontrails/models/cocip/unterstrasser_wake_vortex.py +90 -87
- pycontrails/models/cocip/wake_vortex.py +92 -92
- pycontrails/models/cocip/wind_shear.py +8 -8
- pycontrails/models/cocipgrid/cocip_grid.py +37 -96
- pycontrails/models/dry_advection.py +60 -19
- pycontrails/models/emissions/__init__.py +2 -2
- pycontrails/models/emissions/black_carbon.py +108 -108
- pycontrails/models/emissions/emissions.py +87 -87
- pycontrails/models/emissions/ffm2.py +35 -35
- pycontrails/models/humidity_scaling/humidity_scaling.py +23 -23
- pycontrails/models/issr.py +2 -2
- pycontrails/models/ps_model/__init__.py +1 -1
- pycontrails/models/ps_model/ps_aircraft_params.py +8 -4
- pycontrails/models/ps_model/ps_grid.py +76 -66
- pycontrails/models/ps_model/ps_model.py +16 -16
- pycontrails/models/ps_model/ps_operational_limits.py +20 -18
- pycontrails/models/tau_cirrus.py +8 -1
- pycontrails/physics/geo.py +67 -67
- pycontrails/physics/jet.py +79 -79
- pycontrails/physics/units.py +14 -14
- pycontrails/utils/json.py +1 -2
- pycontrails/utils/types.py +12 -7
- {pycontrails-0.54.3.dist-info → pycontrails-0.54.5.dist-info}/METADATA +2 -2
- {pycontrails-0.54.3.dist-info → pycontrails-0.54.5.dist-info}/NOTICE +1 -1
- pycontrails-0.54.5.dist-info/RECORD +111 -0
- pycontrails-0.54.3.dist-info/RECORD +0 -111
- {pycontrails-0.54.3.dist-info → pycontrails-0.54.5.dist-info}/LICENSE +0 -0
- {pycontrails-0.54.3.dist-info → pycontrails-0.54.5.dist-info}/WHEEL +0 -0
- {pycontrails-0.54.3.dist-info → pycontrails-0.54.5.dist-info}/top_level.txt +0 -0
pycontrails/__init__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
``pycontrails`` public API.
|
|
3
3
|
|
|
4
|
-
Copyright 2021-
|
|
4
|
+
Copyright 2021-present Breakthrough Energy
|
|
5
5
|
|
|
6
6
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
7
|
you may not use this file except in compliance with the License.
|
|
@@ -60,8 +60,8 @@ __all__ = [
|
|
|
60
60
|
"HydrogenFuel",
|
|
61
61
|
"JetA",
|
|
62
62
|
"MetDataArray",
|
|
63
|
-
"MetDataset",
|
|
64
63
|
"MetDataSource",
|
|
64
|
+
"MetDataset",
|
|
65
65
|
"MetVariable",
|
|
66
66
|
"Model",
|
|
67
67
|
"ModelParams",
|
pycontrails/_version.py
CHANGED
pycontrails/core/__init__.py
CHANGED
|
@@ -163,14 +163,14 @@ class AircraftPerformance(Model):
|
|
|
163
163
|
self,
|
|
164
164
|
*,
|
|
165
165
|
aircraft_type: str,
|
|
166
|
-
altitude_ft: npt.NDArray[np.
|
|
166
|
+
altitude_ft: npt.NDArray[np.floating],
|
|
167
167
|
time: npt.NDArray[np.datetime64],
|
|
168
|
-
true_airspeed: npt.NDArray[np.
|
|
169
|
-
air_temperature: npt.NDArray[np.
|
|
170
|
-
aircraft_mass: npt.NDArray[np.
|
|
171
|
-
thrust: npt.NDArray[np.
|
|
172
|
-
engine_efficiency: npt.NDArray[np.
|
|
173
|
-
fuel_flow: npt.NDArray[np.
|
|
168
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
169
|
+
air_temperature: npt.NDArray[np.floating],
|
|
170
|
+
aircraft_mass: npt.NDArray[np.floating] | float | None,
|
|
171
|
+
thrust: npt.NDArray[np.floating] | float | None,
|
|
172
|
+
engine_efficiency: npt.NDArray[np.floating] | float | None,
|
|
173
|
+
fuel_flow: npt.NDArray[np.floating] | float | None,
|
|
174
174
|
q_fuel: float,
|
|
175
175
|
n_iter: int,
|
|
176
176
|
amass_oew: float,
|
|
@@ -192,21 +192,21 @@ class AircraftPerformance(Model):
|
|
|
192
192
|
----------
|
|
193
193
|
aircraft_type: str
|
|
194
194
|
Aircraft type designator used to query the underlying model database.
|
|
195
|
-
altitude_ft: npt.NDArray[np.
|
|
195
|
+
altitude_ft: npt.NDArray[np.floating]
|
|
196
196
|
Altitude at each waypoint, [:math:`ft`]
|
|
197
197
|
time: npt.NDArray[np.datetime64]
|
|
198
198
|
Waypoint time in ``np.datetime64`` format.
|
|
199
|
-
true_airspeed: npt.NDArray[np.
|
|
199
|
+
true_airspeed: npt.NDArray[np.floating]
|
|
200
200
|
True airspeed for each waypoint, [:math:`m s^{-1}`]
|
|
201
|
-
air_temperature : npt.NDArray[np.
|
|
201
|
+
air_temperature : npt.NDArray[np.floating]
|
|
202
202
|
Ambient temperature for each waypoint, [:math:`K`]
|
|
203
|
-
aircraft_mass : npt.NDArray[np.
|
|
203
|
+
aircraft_mass : npt.NDArray[np.floating] | float | None
|
|
204
204
|
Override the aircraft_mass at each waypoint, [:math:`kg`].
|
|
205
|
-
thrust : npt.NDArray[np.
|
|
205
|
+
thrust : npt.NDArray[np.floating] | float | None
|
|
206
206
|
Override the thrust setting at each waypoint, [:math: `N`].
|
|
207
|
-
engine_efficiency : npt.NDArray[np.
|
|
207
|
+
engine_efficiency : npt.NDArray[np.floating] | float | None
|
|
208
208
|
Override the engine efficiency at each waypoint.
|
|
209
|
-
fuel_flow : npt.NDArray[np.
|
|
209
|
+
fuel_flow : npt.NDArray[np.floating] | float | None
|
|
210
210
|
Override the fuel flow at each waypoint, [:math:`kg s^{-1}`].
|
|
211
211
|
q_fuel : float
|
|
212
212
|
Lower calorific value (LCV) of fuel, [:math:`J \ kg_{fuel}^{-1}`].
|
|
@@ -280,14 +280,14 @@ class AircraftPerformance(Model):
|
|
|
280
280
|
self,
|
|
281
281
|
*,
|
|
282
282
|
aircraft_type: str,
|
|
283
|
-
altitude_ft: npt.NDArray[np.
|
|
283
|
+
altitude_ft: npt.NDArray[np.floating],
|
|
284
284
|
time: npt.NDArray[np.datetime64],
|
|
285
|
-
true_airspeed: npt.NDArray[np.
|
|
286
|
-
air_temperature: npt.NDArray[np.
|
|
287
|
-
aircraft_mass: npt.NDArray[np.
|
|
288
|
-
thrust: npt.NDArray[np.
|
|
289
|
-
engine_efficiency: npt.NDArray[np.
|
|
290
|
-
fuel_flow: npt.NDArray[np.
|
|
285
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
286
|
+
air_temperature: npt.NDArray[np.floating],
|
|
287
|
+
aircraft_mass: npt.NDArray[np.floating] | float,
|
|
288
|
+
thrust: npt.NDArray[np.floating] | float | None,
|
|
289
|
+
engine_efficiency: npt.NDArray[np.floating] | float | None,
|
|
290
|
+
fuel_flow: npt.NDArray[np.floating] | float | None,
|
|
291
291
|
q_fuel: float,
|
|
292
292
|
**kwargs: Any,
|
|
293
293
|
) -> AircraftPerformanceData:
|
|
@@ -332,13 +332,13 @@ class AircraftPerformance(Model):
|
|
|
332
332
|
self,
|
|
333
333
|
*,
|
|
334
334
|
aircraft_type: str,
|
|
335
|
-
altitude_ft: npt.NDArray[np.
|
|
335
|
+
altitude_ft: npt.NDArray[np.floating],
|
|
336
336
|
time: npt.NDArray[np.datetime64],
|
|
337
|
-
true_airspeed: npt.NDArray[np.
|
|
338
|
-
air_temperature: npt.NDArray[np.
|
|
339
|
-
thrust: npt.NDArray[np.
|
|
340
|
-
engine_efficiency: npt.NDArray[np.
|
|
341
|
-
fuel_flow: npt.NDArray[np.
|
|
337
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
338
|
+
air_temperature: npt.NDArray[np.floating],
|
|
339
|
+
thrust: npt.NDArray[np.floating] | float | None,
|
|
340
|
+
engine_efficiency: npt.NDArray[np.floating] | float | None,
|
|
341
|
+
fuel_flow: npt.NDArray[np.floating] | float | None,
|
|
342
342
|
q_fuel: float,
|
|
343
343
|
n_iter: int,
|
|
344
344
|
amass_oew: float,
|
|
@@ -351,7 +351,7 @@ class AircraftPerformance(Model):
|
|
|
351
351
|
# Variable aircraft_mass will change dynamically after each iteration
|
|
352
352
|
# Set the initial aircraft mass depending on a possible load factor
|
|
353
353
|
|
|
354
|
-
aircraft_mass: npt.NDArray[np.
|
|
354
|
+
aircraft_mass: npt.NDArray[np.floating] | float
|
|
355
355
|
if takeoff_mass is not None:
|
|
356
356
|
aircraft_mass = takeoff_mass
|
|
357
357
|
else:
|
|
@@ -411,14 +411,14 @@ class AircraftPerformance(Model):
|
|
|
411
411
|
self,
|
|
412
412
|
*,
|
|
413
413
|
aircraft_type: str,
|
|
414
|
-
altitude_ft: npt.NDArray[np.
|
|
415
|
-
air_temperature: npt.NDArray[np.
|
|
414
|
+
altitude_ft: npt.NDArray[np.floating],
|
|
415
|
+
air_temperature: npt.NDArray[np.floating],
|
|
416
416
|
time: npt.NDArray[np.datetime64] | None,
|
|
417
|
-
true_airspeed: npt.NDArray[np.
|
|
418
|
-
aircraft_mass: npt.NDArray[np.
|
|
419
|
-
engine_efficiency: npt.NDArray[np.
|
|
420
|
-
fuel_flow: npt.NDArray[np.
|
|
421
|
-
thrust: npt.NDArray[np.
|
|
417
|
+
true_airspeed: npt.NDArray[np.floating] | float | None,
|
|
418
|
+
aircraft_mass: npt.NDArray[np.floating] | float,
|
|
419
|
+
engine_efficiency: npt.NDArray[np.floating] | float | None,
|
|
420
|
+
fuel_flow: npt.NDArray[np.floating] | float | None,
|
|
421
|
+
thrust: npt.NDArray[np.floating] | float | None,
|
|
422
422
|
q_fuel: float,
|
|
423
423
|
**kwargs: Any,
|
|
424
424
|
) -> AircraftPerformanceData:
|
|
@@ -441,24 +441,24 @@ class AircraftPerformance(Model):
|
|
|
441
441
|
----------
|
|
442
442
|
aircraft_type : str
|
|
443
443
|
Used to query the underlying model database for aircraft engine parameters.
|
|
444
|
-
altitude_ft : npt.NDArray[np.
|
|
444
|
+
altitude_ft : npt.NDArray[np.floating]
|
|
445
445
|
Altitude at each waypoint, [:math:`ft`]
|
|
446
|
-
air_temperature : npt.NDArray[np.
|
|
446
|
+
air_temperature : npt.NDArray[np.floating]
|
|
447
447
|
Ambient temperature for each waypoint, [:math:`K`]
|
|
448
448
|
time: npt.NDArray[np.datetime64] | None
|
|
449
449
|
Waypoint time in ``np.datetime64`` format. If None, only drag force
|
|
450
450
|
will is used in thrust calculations (ie, no vertical change and constant
|
|
451
451
|
horizontal change). In addition, aircraft is assumed to be in cruise.
|
|
452
|
-
true_airspeed : npt.NDArray[np.
|
|
452
|
+
true_airspeed : npt.NDArray[np.floating] | float | None
|
|
453
453
|
True airspeed for each waypoint, [:math:`m s^{-1}`].
|
|
454
454
|
If None, a nominal value is used.
|
|
455
|
-
aircraft_mass : npt.NDArray[np.
|
|
455
|
+
aircraft_mass : npt.NDArray[np.floating] | float
|
|
456
456
|
Aircraft mass for each waypoint, [:math:`kg`].
|
|
457
|
-
engine_efficiency : npt.NDArray[np.
|
|
457
|
+
engine_efficiency : npt.NDArray[np.floating] | float | None
|
|
458
458
|
Override the engine efficiency at each waypoint.
|
|
459
|
-
fuel_flow : npt.NDArray[np.
|
|
459
|
+
fuel_flow : npt.NDArray[np.floating] | float | None
|
|
460
460
|
Override the fuel flow at each waypoint, [:math:`kg s^{-1}`].
|
|
461
|
-
thrust : npt.NDArray[np.
|
|
461
|
+
thrust : npt.NDArray[np.floating] | float | None
|
|
462
462
|
Override the thrust setting at each waypoint, [:math: `N`].
|
|
463
463
|
q_fuel : float
|
|
464
464
|
Lower calorific value (LCV) of fuel, [:math:`J \ kg_{fuel}^{-1}`].
|
|
@@ -471,12 +471,12 @@ class AircraftPerformance(Model):
|
|
|
471
471
|
Derived performance metrics at each waypoint.
|
|
472
472
|
"""
|
|
473
473
|
|
|
474
|
-
def ensure_true_airspeed_on_source(self) -> npt.NDArray[np.
|
|
474
|
+
def ensure_true_airspeed_on_source(self) -> npt.NDArray[np.floating]:
|
|
475
475
|
"""Add ``true_airspeed`` field to :attr:`source` data if not already present.
|
|
476
476
|
|
|
477
477
|
Returns
|
|
478
478
|
-------
|
|
479
|
-
npt.NDArray[np.
|
|
479
|
+
npt.NDArray[np.floating]
|
|
480
480
|
True airspeed, [:math:`m s^{-1}`]. If ``true_airspeed`` is already present
|
|
481
481
|
on :attr:`source`, this is returned directly. Otherwise, it is calculated
|
|
482
482
|
using :meth:`Flight.segment_true_airspeed`.
|
|
@@ -529,30 +529,30 @@ class AircraftPerformanceData:
|
|
|
529
529
|
|
|
530
530
|
Parameters
|
|
531
531
|
----------
|
|
532
|
-
fuel_flow : npt.NDArray[np.
|
|
532
|
+
fuel_flow : npt.NDArray[np.floating]
|
|
533
533
|
Fuel mass flow rate for each waypoint, [:math:`kg s^{-1}`]
|
|
534
|
-
aircraft_mass : npt.NDArray[np.
|
|
534
|
+
aircraft_mass : npt.NDArray[np.floating]
|
|
535
535
|
Aircraft mass for each waypoint, [:math:`kg`]
|
|
536
|
-
true_airspeed : npt.NDArray[np.
|
|
536
|
+
true_airspeed : npt.NDArray[np.floating]
|
|
537
537
|
True airspeed at each waypoint, [:math: `m s^{-1}`]
|
|
538
|
-
fuel_burn: npt.NDArray[np.
|
|
538
|
+
fuel_burn: npt.NDArray[np.floating]
|
|
539
539
|
Fuel consumption for each waypoint, [:math:`kg`]. Set to an array of
|
|
540
540
|
all nan values if it cannot be computed (ie, working with gridpoints).
|
|
541
|
-
thrust: npt.NDArray[np.
|
|
541
|
+
thrust: npt.NDArray[np.floating]
|
|
542
542
|
Thrust force, [:math:`N`]
|
|
543
|
-
engine_efficiency: npt.NDArray[np.
|
|
543
|
+
engine_efficiency: npt.NDArray[np.floating]
|
|
544
544
|
Overall propulsion efficiency for each waypoint
|
|
545
|
-
rocd : npt.NDArray[np.
|
|
545
|
+
rocd : npt.NDArray[np.floating]
|
|
546
546
|
Rate of climb and descent, [:math:`ft min^{-1}`]
|
|
547
547
|
"""
|
|
548
548
|
|
|
549
|
-
fuel_flow: npt.NDArray[np.
|
|
550
|
-
aircraft_mass: npt.NDArray[np.
|
|
551
|
-
true_airspeed: npt.NDArray[np.
|
|
552
|
-
fuel_burn: npt.NDArray[np.
|
|
553
|
-
thrust: npt.NDArray[np.
|
|
554
|
-
engine_efficiency: npt.NDArray[np.
|
|
555
|
-
rocd: npt.NDArray[np.
|
|
549
|
+
fuel_flow: npt.NDArray[np.floating]
|
|
550
|
+
aircraft_mass: npt.NDArray[np.floating]
|
|
551
|
+
true_airspeed: npt.NDArray[np.floating]
|
|
552
|
+
fuel_burn: npt.NDArray[np.floating]
|
|
553
|
+
thrust: npt.NDArray[np.floating]
|
|
554
|
+
engine_efficiency: npt.NDArray[np.floating]
|
|
555
|
+
rocd: npt.NDArray[np.floating]
|
|
556
556
|
|
|
557
557
|
|
|
558
558
|
# --------------------------------
|
pycontrails/core/cache.py
CHANGED
|
@@ -43,7 +43,7 @@ def _get_user_cache_dir() -> str:
|
|
|
43
43
|
class CacheStore(ABC):
|
|
44
44
|
"""Abstract cache storage class for storing staged and intermediate data."""
|
|
45
45
|
|
|
46
|
-
__slots__ = ("
|
|
46
|
+
__slots__ = ("allow_clear", "cache_dir")
|
|
47
47
|
cache_dir: str
|
|
48
48
|
allow_clear: bool
|
|
49
49
|
|
|
@@ -426,15 +426,15 @@ class GCPCacheStore(CacheStore):
|
|
|
426
426
|
"""
|
|
427
427
|
|
|
428
428
|
__slots__ = (
|
|
429
|
-
"
|
|
429
|
+
"_bucket",
|
|
430
|
+
"_client",
|
|
431
|
+
"_disk_cache",
|
|
430
432
|
"bucket",
|
|
433
|
+
"chunk_size",
|
|
434
|
+
"project",
|
|
431
435
|
"read_only",
|
|
432
|
-
"timeout",
|
|
433
436
|
"show_progress",
|
|
434
|
-
"
|
|
435
|
-
"_disk_cache",
|
|
436
|
-
"_client",
|
|
437
|
-
"_bucket",
|
|
437
|
+
"timeout",
|
|
438
438
|
)
|
|
439
439
|
project: str | None
|
|
440
440
|
bucket: str
|
pycontrails/core/fleet.py
CHANGED
|
@@ -32,7 +32,7 @@ class Fleet(Flight):
|
|
|
32
32
|
Flight waypoints are merged into a single :class:`Flight`-like object.
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
|
-
__slots__ = ("
|
|
35
|
+
__slots__ = ("final_waypoints", "fl_attrs")
|
|
36
36
|
|
|
37
37
|
def __init__(
|
|
38
38
|
self,
|
|
@@ -132,19 +132,20 @@ class Fleet(Flight):
|
|
|
132
132
|
return final_waypoints, fl_attrs
|
|
133
133
|
|
|
134
134
|
@override
|
|
135
|
-
def copy(self, **kwargs: Any) ->
|
|
136
|
-
kwargs.setdefault("fuel", self.fuel)
|
|
135
|
+
def copy(self, **kwargs: Any) -> Self:
|
|
137
136
|
kwargs.setdefault("fl_attrs", self.fl_attrs)
|
|
137
|
+
kwargs.setdefault("final_waypoints", self.final_waypoints)
|
|
138
138
|
return super().copy(**kwargs)
|
|
139
139
|
|
|
140
140
|
@override
|
|
141
|
-
def filter(self, mask: npt.NDArray[np.bool_], copy: bool = True, **kwargs: Any) ->
|
|
142
|
-
kwargs.setdefault("fuel", self.fuel)
|
|
143
|
-
|
|
141
|
+
def filter(self, mask: npt.NDArray[np.bool_], copy: bool = True, **kwargs: Any) -> Self:
|
|
144
142
|
flight_ids = set(np.unique(self["flight_id"][mask]))
|
|
145
143
|
fl_attrs = {k: v for k, v in self.fl_attrs.items() if k in flight_ids}
|
|
146
144
|
kwargs.setdefault("fl_attrs", fl_attrs)
|
|
147
145
|
|
|
146
|
+
final_waypoints = np.array(self.final_waypoints[mask], copy=copy)
|
|
147
|
+
kwargs.setdefault("final_waypoints", final_waypoints)
|
|
148
|
+
|
|
148
149
|
return super().filter(mask, copy=copy, **kwargs)
|
|
149
150
|
|
|
150
151
|
@override
|
|
@@ -162,7 +163,6 @@ class Fleet(Flight):
|
|
|
162
163
|
cls,
|
|
163
164
|
seq: Iterable[Flight],
|
|
164
165
|
broadcast_numeric: bool = True,
|
|
165
|
-
copy: bool = True,
|
|
166
166
|
attrs: dict[str, Any] | None = None,
|
|
167
167
|
) -> Self:
|
|
168
168
|
"""Instantiate a :class:`Fleet` instance from an iterable of :class:`Flight`.
|
|
@@ -177,8 +177,6 @@ class Fleet(Flight):
|
|
|
177
177
|
An iterable of :class:`Flight` instances.
|
|
178
178
|
broadcast_numeric : bool, optional
|
|
179
179
|
If True, broadcast numeric attributes to data variables.
|
|
180
|
-
copy : bool, optional
|
|
181
|
-
If True, make copy of each flight instance in ``seq``.
|
|
182
180
|
attrs : dict[str, Any] | None, optional
|
|
183
181
|
Global attribute to attach to instance.
|
|
184
182
|
|
|
@@ -190,15 +188,16 @@ class Fleet(Flight):
|
|
|
190
188
|
in ``seq``.
|
|
191
189
|
"""
|
|
192
190
|
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
# Create a shallow copy because we add additional keys in _validate_fl
|
|
192
|
+
def _shallow_copy(fl: Flight) -> Flight:
|
|
193
|
+
return Flight._from_fastpath(fl.data, fl.attrs, fuel=fl.fuel)
|
|
195
194
|
|
|
196
195
|
def _maybe_warn(fl: Flight) -> Flight:
|
|
197
196
|
if not fl:
|
|
198
197
|
warnings.warn("Empty flight found in sequence. It will be filtered out.")
|
|
199
198
|
return fl
|
|
200
199
|
|
|
201
|
-
seq = tuple(
|
|
200
|
+
seq = tuple(_shallow_copy(fl) for fl in seq if _maybe_warn(fl))
|
|
202
201
|
|
|
203
202
|
if not seq:
|
|
204
203
|
msg = "Cannot create Fleet from empty sequence."
|
|
@@ -220,7 +219,18 @@ class Fleet(Flight):
|
|
|
220
219
|
)
|
|
221
220
|
|
|
222
221
|
data = {var: np.concatenate([fl[var] for fl in seq]) for var in seq[0]}
|
|
223
|
-
|
|
222
|
+
|
|
223
|
+
final_waypoints = np.zeros(data["time"].size, dtype=bool)
|
|
224
|
+
final_waypoint_indices = np.cumsum([fl.size for fl in seq]) - 1
|
|
225
|
+
final_waypoints[final_waypoint_indices] = True
|
|
226
|
+
|
|
227
|
+
return cls._from_fastpath(
|
|
228
|
+
data,
|
|
229
|
+
attrs,
|
|
230
|
+
fuel=fuel,
|
|
231
|
+
fl_attrs=fl_attrs,
|
|
232
|
+
final_waypoints=final_waypoints,
|
|
233
|
+
)
|
|
224
234
|
|
|
225
235
|
@property
|
|
226
236
|
def n_flights(self) -> int:
|
|
@@ -249,11 +259,19 @@ class Fleet(Flight):
|
|
|
249
259
|
List of Flights in the same order as was passed into the ``Fleet`` instance.
|
|
250
260
|
"""
|
|
251
261
|
indices = self.dataframe.groupby("flight_id", sort=False).indices
|
|
262
|
+
if copy:
|
|
263
|
+
return [
|
|
264
|
+
Flight._from_fastpath(
|
|
265
|
+
{k: v[idx] for k, v in self.data.items()},
|
|
266
|
+
self.fl_attrs[flight_id],
|
|
267
|
+
fuel=self.fuel,
|
|
268
|
+
).copy()
|
|
269
|
+
for flight_id, idx in indices.items()
|
|
270
|
+
]
|
|
252
271
|
return [
|
|
253
|
-
Flight(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
copy=copy,
|
|
272
|
+
Flight._from_fastpath(
|
|
273
|
+
{k: v[idx] for k, v in self.data.items()},
|
|
274
|
+
self.fl_attrs[flight_id],
|
|
257
275
|
fuel=self.fuel,
|
|
258
276
|
)
|
|
259
277
|
for flight_id, idx in indices.items()
|
|
@@ -265,12 +283,12 @@ class Fleet(Flight):
|
|
|
265
283
|
|
|
266
284
|
def segment_true_airspeed(
|
|
267
285
|
self,
|
|
268
|
-
u_wind: npt.NDArray[np.
|
|
269
|
-
v_wind: npt.NDArray[np.
|
|
286
|
+
u_wind: npt.NDArray[np.floating] | float = 0.0,
|
|
287
|
+
v_wind: npt.NDArray[np.floating] | float = 0.0,
|
|
270
288
|
smooth: bool = True,
|
|
271
289
|
window_length: int = 7,
|
|
272
290
|
polyorder: int = 1,
|
|
273
|
-
) -> npt.NDArray[np.
|
|
291
|
+
) -> npt.NDArray[np.floating]:
|
|
274
292
|
"""Calculate the true airspeed [:math:`m / s`] from the ground speed and horizontal winds.
|
|
275
293
|
|
|
276
294
|
Because Flight.segment_true_airspeed uses a smoothing pattern, waypoints in :attr:`data`
|
|
@@ -302,7 +320,7 @@ class Fleet(Flight):
|
|
|
302
320
|
self[key] = v_wind
|
|
303
321
|
|
|
304
322
|
# Calculate TAS on each flight individually
|
|
305
|
-
def calc_tas(fl: Flight) -> npt.NDArray[np.
|
|
323
|
+
def calc_tas(fl: Flight) -> npt.NDArray[np.floating]:
|
|
306
324
|
u = fl.get("__u_wind", u_wind)
|
|
307
325
|
v = fl.get("__v_wind", v_wind)
|
|
308
326
|
|
|
@@ -325,19 +343,27 @@ class Fleet(Flight):
|
|
|
325
343
|
return np.concatenate(tas)
|
|
326
344
|
|
|
327
345
|
@override
|
|
328
|
-
def segment_groundspeed(self, *args: Any, **kwargs: Any) -> npt.NDArray[np.
|
|
346
|
+
def segment_groundspeed(self, *args: Any, **kwargs: Any) -> npt.NDArray[np.floating]:
|
|
329
347
|
fls = self.to_flight_list(copy=False)
|
|
330
348
|
gs = [fl.segment_groundspeed(*args, **kwargs) for fl in fls]
|
|
331
349
|
return np.concatenate(gs)
|
|
332
350
|
|
|
333
351
|
@override
|
|
334
|
-
def resample_and_fill(self, *args: Any, **kwargs: Any) ->
|
|
352
|
+
def resample_and_fill(self, *args: Any, **kwargs: Any) -> Self:
|
|
335
353
|
flights = self.to_flight_list(copy=False)
|
|
354
|
+
|
|
355
|
+
# We need to ensure that each flight has an flight_id attrs field
|
|
356
|
+
# When we call fl.resample_and_fill, any flight_id data field
|
|
357
|
+
# will be lost, so the call to Fleet.from_seq will fail.
|
|
358
|
+
for fl in flights:
|
|
359
|
+
if "flight_id" not in fl.attrs:
|
|
360
|
+
fl.attrs["flight_id"] = _extract_flight_id(fl)
|
|
361
|
+
|
|
336
362
|
flights = [fl.resample_and_fill(*args, **kwargs) for fl in flights]
|
|
337
|
-
return type(self).from_seq(flights,
|
|
363
|
+
return type(self).from_seq(flights, broadcast_numeric=False, attrs=self.attrs)
|
|
338
364
|
|
|
339
365
|
@override
|
|
340
|
-
def segment_length(self) -> npt.NDArray[np.
|
|
366
|
+
def segment_length(self) -> npt.NDArray[np.floating]:
|
|
341
367
|
return np.where(self.final_waypoints, np.nan, super().segment_length())
|
|
342
368
|
|
|
343
369
|
@property
|
|
@@ -346,11 +372,11 @@ class Fleet(Flight):
|
|
|
346
372
|
return np.nanmax(self.segment_length()).item()
|
|
347
373
|
|
|
348
374
|
@override
|
|
349
|
-
def segment_azimuth(self) -> npt.NDArray[np.
|
|
375
|
+
def segment_azimuth(self) -> npt.NDArray[np.floating]:
|
|
350
376
|
return np.where(self.final_waypoints, np.nan, super().segment_azimuth())
|
|
351
377
|
|
|
352
378
|
@override
|
|
353
|
-
def segment_angle(self) -> tuple[npt.NDArray[np.
|
|
379
|
+
def segment_angle(self) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]]:
|
|
354
380
|
sin_a, cos_a = super().segment_angle()
|
|
355
381
|
sin_a[self.final_waypoints] = np.nan
|
|
356
382
|
cos_a[self.final_waypoints] = np.nan
|
|
@@ -368,8 +394,7 @@ class Fleet(Flight):
|
|
|
368
394
|
force_filter: bool = False,
|
|
369
395
|
drop: bool = True,
|
|
370
396
|
keep_original_index: bool = False,
|
|
371
|
-
|
|
372
|
-
) -> Flight:
|
|
397
|
+
) -> NoReturn:
|
|
373
398
|
msg = "Only implemented for Flight instances"
|
|
374
399
|
raise NotImplementedError(msg)
|
|
375
400
|
|