pycontrails 0.54.2__cp312-cp312-macosx_11_0_arm64.whl → 0.54.4__cp312-cp312-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.

Files changed (68) hide show
  1. pycontrails/__init__.py +2 -2
  2. pycontrails/_version.py +2 -2
  3. pycontrails/core/__init__.py +1 -1
  4. pycontrails/core/aircraft_performance.py +75 -61
  5. pycontrails/core/cache.py +7 -7
  6. pycontrails/core/fleet.py +25 -21
  7. pycontrails/core/flight.py +215 -301
  8. pycontrails/core/interpolation.py +56 -56
  9. pycontrails/core/met.py +48 -39
  10. pycontrails/core/models.py +25 -11
  11. pycontrails/core/polygon.py +15 -15
  12. pycontrails/core/rgi_cython.cpython-312-darwin.so +0 -0
  13. pycontrails/core/vector.py +22 -22
  14. pycontrails/datalib/_met_utils/metsource.py +8 -5
  15. pycontrails/datalib/ecmwf/__init__.py +14 -14
  16. pycontrails/datalib/ecmwf/common.py +1 -1
  17. pycontrails/datalib/ecmwf/era5.py +7 -7
  18. pycontrails/datalib/ecmwf/hres.py +3 -3
  19. pycontrails/datalib/ecmwf/ifs.py +1 -1
  20. pycontrails/datalib/ecmwf/variables.py +1 -0
  21. pycontrails/datalib/gfs/__init__.py +6 -6
  22. pycontrails/datalib/gfs/gfs.py +2 -2
  23. pycontrails/datalib/goes.py +5 -5
  24. pycontrails/datalib/landsat.py +5 -8
  25. pycontrails/datalib/sentinel.py +7 -11
  26. pycontrails/ext/bada.py +3 -2
  27. pycontrails/ext/empirical_grid.py +1 -1
  28. pycontrails/ext/synthetic_flight.py +3 -2
  29. pycontrails/models/accf.py +40 -19
  30. pycontrails/models/apcemm/apcemm.py +5 -4
  31. pycontrails/models/cocip/__init__.py +2 -2
  32. pycontrails/models/cocip/cocip.py +16 -17
  33. pycontrails/models/cocip/cocip_params.py +2 -11
  34. pycontrails/models/cocip/cocip_uncertainty.py +24 -18
  35. pycontrails/models/cocip/contrail_properties.py +331 -316
  36. pycontrails/models/cocip/output_formats.py +53 -53
  37. pycontrails/models/cocip/radiative_forcing.py +135 -131
  38. pycontrails/models/cocip/radiative_heating.py +135 -135
  39. pycontrails/models/cocip/unterstrasser_wake_vortex.py +90 -87
  40. pycontrails/models/cocip/wake_vortex.py +92 -92
  41. pycontrails/models/cocip/wind_shear.py +8 -8
  42. pycontrails/models/cocipgrid/cocip_grid.py +118 -107
  43. pycontrails/models/dry_advection.py +59 -58
  44. pycontrails/models/emissions/__init__.py +2 -2
  45. pycontrails/models/emissions/black_carbon.py +108 -108
  46. pycontrails/models/emissions/emissions.py +85 -85
  47. pycontrails/models/emissions/ffm2.py +35 -35
  48. pycontrails/models/humidity_scaling/humidity_scaling.py +23 -23
  49. pycontrails/models/ps_model/__init__.py +3 -2
  50. pycontrails/models/ps_model/ps_aircraft_params.py +11 -6
  51. pycontrails/models/ps_model/ps_grid.py +256 -60
  52. pycontrails/models/ps_model/ps_model.py +18 -21
  53. pycontrails/models/ps_model/ps_operational_limits.py +58 -69
  54. pycontrails/models/tau_cirrus.py +8 -1
  55. pycontrails/physics/geo.py +216 -67
  56. pycontrails/physics/jet.py +220 -90
  57. pycontrails/physics/static/iata-cargo-load-factors-20241115.csv +71 -0
  58. pycontrails/physics/static/iata-passenger-load-factors-20241115.csv +71 -0
  59. pycontrails/physics/units.py +14 -14
  60. pycontrails/utils/json.py +1 -2
  61. pycontrails/utils/types.py +12 -7
  62. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/METADATA +10 -10
  63. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/NOTICE +1 -1
  64. pycontrails-0.54.4.dist-info/RECORD +111 -0
  65. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/WHEEL +1 -1
  66. pycontrails-0.54.2.dist-info/RECORD +0 -109
  67. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/LICENSE +0 -0
  68. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.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-2023 Breakthrough Energy
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
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.54.2'
16
- __version_tuple__ = version_tuple = (0, 54, 2)
15
+ __version__ = version = '0.54.4'
16
+ __version_tuple__ = version_tuple = (0, 54, 4)
@@ -20,8 +20,8 @@ __all__ = [
20
20
  "HydrogenFuel",
21
21
  "JetA",
22
22
  "MetDataArray",
23
- "MetDataset",
24
23
  "MetDataSource",
24
+ "MetDataset",
25
25
  "MetVariable",
26
26
  "Model",
27
27
  "ModelParams",
@@ -26,7 +26,9 @@ from pycontrails.physics import jet
26
26
  from pycontrails.utils.types import ArrayOrFloat
27
27
 
28
28
  #: Default load factor for aircraft performance models.
29
- DEFAULT_LOAD_FACTOR = 0.7
29
+ #: See :func:`pycontrails.physics.jet.aircraft_load_factor`
30
+ #: for a higher precision approach to estimating the load factor.
31
+ DEFAULT_LOAD_FACTOR = 0.83
30
32
 
31
33
 
32
34
  # --------------------------------------
@@ -35,7 +37,19 @@ DEFAULT_LOAD_FACTOR = 0.7
35
37
 
36
38
 
37
39
  @dataclasses.dataclass
38
- class AircraftPerformanceParams(ModelParams):
40
+ class CommonAircraftPerformanceParams:
41
+ """Params for :class:`AircraftPerformanceParams` and :class:`AircraftPerformanceGridParams`."""
42
+
43
+ #: Account for "in-service" engine deterioration between maintenance cycles.
44
+ #: Default value is set to +2.5% increase in fuel consumption.
45
+ #: Reference:
46
+ #: Gurrola Arrieta, M.D.J., Botez, R.M. and Lasne, A., 2024. An Engine Deterioration Model for
47
+ #: Predicting Fuel Consumption Impact in a Regional Aircraft. Aerospace, 11(6), p.426.
48
+ engine_deterioration_factor: float = 0.025
49
+
50
+
51
+ @dataclasses.dataclass
52
+ class AircraftPerformanceParams(ModelParams, CommonAircraftPerformanceParams):
39
53
  """Parameters for :class:`AircraftPerformance`."""
40
54
 
41
55
  #: Whether to correct fuel flow to ensure it remains within
@@ -149,14 +163,14 @@ class AircraftPerformance(Model):
149
163
  self,
150
164
  *,
151
165
  aircraft_type: str,
152
- altitude_ft: npt.NDArray[np.float64],
166
+ altitude_ft: npt.NDArray[np.floating],
153
167
  time: npt.NDArray[np.datetime64],
154
- true_airspeed: npt.NDArray[np.float64],
155
- air_temperature: npt.NDArray[np.float64],
156
- aircraft_mass: npt.NDArray[np.float64] | float | None,
157
- thrust: npt.NDArray[np.float64] | float | None,
158
- engine_efficiency: npt.NDArray[np.float64] | float | None,
159
- fuel_flow: npt.NDArray[np.float64] | float | None,
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,
160
174
  q_fuel: float,
161
175
  n_iter: int,
162
176
  amass_oew: float,
@@ -178,21 +192,21 @@ class AircraftPerformance(Model):
178
192
  ----------
179
193
  aircraft_type: str
180
194
  Aircraft type designator used to query the underlying model database.
181
- altitude_ft: npt.NDArray[np.float64]
195
+ altitude_ft: npt.NDArray[np.floating]
182
196
  Altitude at each waypoint, [:math:`ft`]
183
197
  time: npt.NDArray[np.datetime64]
184
198
  Waypoint time in ``np.datetime64`` format.
185
- true_airspeed: npt.NDArray[np.float64]
199
+ true_airspeed: npt.NDArray[np.floating]
186
200
  True airspeed for each waypoint, [:math:`m s^{-1}`]
187
- air_temperature : npt.NDArray[np.float64]
201
+ air_temperature : npt.NDArray[np.floating]
188
202
  Ambient temperature for each waypoint, [:math:`K`]
189
- aircraft_mass : npt.NDArray[np.float64] | float | None
203
+ aircraft_mass : npt.NDArray[np.floating] | float | None
190
204
  Override the aircraft_mass at each waypoint, [:math:`kg`].
191
- thrust : npt.NDArray[np.float64] | float | None
205
+ thrust : npt.NDArray[np.floating] | float | None
192
206
  Override the thrust setting at each waypoint, [:math: `N`].
193
- engine_efficiency : npt.NDArray[np.float64] | float | None
207
+ engine_efficiency : npt.NDArray[np.floating] | float | None
194
208
  Override the engine efficiency at each waypoint.
195
- fuel_flow : npt.NDArray[np.float64] | float | None
209
+ fuel_flow : npt.NDArray[np.floating] | float | None
196
210
  Override the fuel flow at each waypoint, [:math:`kg s^{-1}`].
197
211
  q_fuel : float
198
212
  Lower calorific value (LCV) of fuel, [:math:`J \ kg_{fuel}^{-1}`].
@@ -266,14 +280,14 @@ class AircraftPerformance(Model):
266
280
  self,
267
281
  *,
268
282
  aircraft_type: str,
269
- altitude_ft: npt.NDArray[np.float64],
283
+ altitude_ft: npt.NDArray[np.floating],
270
284
  time: npt.NDArray[np.datetime64],
271
- true_airspeed: npt.NDArray[np.float64],
272
- air_temperature: npt.NDArray[np.float64],
273
- aircraft_mass: npt.NDArray[np.float64] | float,
274
- thrust: npt.NDArray[np.float64] | float | None,
275
- engine_efficiency: npt.NDArray[np.float64] | float | None,
276
- fuel_flow: npt.NDArray[np.float64] | float | None,
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,
277
291
  q_fuel: float,
278
292
  **kwargs: Any,
279
293
  ) -> AircraftPerformanceData:
@@ -318,13 +332,13 @@ class AircraftPerformance(Model):
318
332
  self,
319
333
  *,
320
334
  aircraft_type: str,
321
- altitude_ft: npt.NDArray[np.float64],
335
+ altitude_ft: npt.NDArray[np.floating],
322
336
  time: npt.NDArray[np.datetime64],
323
- true_airspeed: npt.NDArray[np.float64],
324
- air_temperature: npt.NDArray[np.float64],
325
- thrust: npt.NDArray[np.float64] | float | None,
326
- engine_efficiency: npt.NDArray[np.float64] | float | None,
327
- fuel_flow: npt.NDArray[np.float64] | float | None,
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,
328
342
  q_fuel: float,
329
343
  n_iter: int,
330
344
  amass_oew: float,
@@ -337,7 +351,7 @@ class AircraftPerformance(Model):
337
351
  # Variable aircraft_mass will change dynamically after each iteration
338
352
  # Set the initial aircraft mass depending on a possible load factor
339
353
 
340
- aircraft_mass: npt.NDArray[np.float64] | float
354
+ aircraft_mass: npt.NDArray[np.floating] | float
341
355
  if takeoff_mass is not None:
342
356
  aircraft_mass = takeoff_mass
343
357
  else:
@@ -397,14 +411,14 @@ class AircraftPerformance(Model):
397
411
  self,
398
412
  *,
399
413
  aircraft_type: str,
400
- altitude_ft: npt.NDArray[np.float64],
401
- air_temperature: npt.NDArray[np.float64],
414
+ altitude_ft: npt.NDArray[np.floating],
415
+ air_temperature: npt.NDArray[np.floating],
402
416
  time: npt.NDArray[np.datetime64] | None,
403
- true_airspeed: npt.NDArray[np.float64] | float | None,
404
- aircraft_mass: npt.NDArray[np.float64] | float,
405
- engine_efficiency: npt.NDArray[np.float64] | float | None,
406
- fuel_flow: npt.NDArray[np.float64] | float | None,
407
- thrust: npt.NDArray[np.float64] | float | None,
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,
408
422
  q_fuel: float,
409
423
  **kwargs: Any,
410
424
  ) -> AircraftPerformanceData:
@@ -427,24 +441,24 @@ class AircraftPerformance(Model):
427
441
  ----------
428
442
  aircraft_type : str
429
443
  Used to query the underlying model database for aircraft engine parameters.
430
- altitude_ft : npt.NDArray[np.float64]
444
+ altitude_ft : npt.NDArray[np.floating]
431
445
  Altitude at each waypoint, [:math:`ft`]
432
- air_temperature : npt.NDArray[np.float64]
446
+ air_temperature : npt.NDArray[np.floating]
433
447
  Ambient temperature for each waypoint, [:math:`K`]
434
448
  time: npt.NDArray[np.datetime64] | None
435
449
  Waypoint time in ``np.datetime64`` format. If None, only drag force
436
450
  will is used in thrust calculations (ie, no vertical change and constant
437
451
  horizontal change). In addition, aircraft is assumed to be in cruise.
438
- true_airspeed : npt.NDArray[np.float64] | float | None
452
+ true_airspeed : npt.NDArray[np.floating] | float | None
439
453
  True airspeed for each waypoint, [:math:`m s^{-1}`].
440
454
  If None, a nominal value is used.
441
- aircraft_mass : npt.NDArray[np.float64] | float
455
+ aircraft_mass : npt.NDArray[np.floating] | float
442
456
  Aircraft mass for each waypoint, [:math:`kg`].
443
- engine_efficiency : npt.NDArray[np.float64] | float | None
457
+ engine_efficiency : npt.NDArray[np.floating] | float | None
444
458
  Override the engine efficiency at each waypoint.
445
- fuel_flow : npt.NDArray[np.float64] | float | None
459
+ fuel_flow : npt.NDArray[np.floating] | float | None
446
460
  Override the fuel flow at each waypoint, [:math:`kg s^{-1}`].
447
- thrust : npt.NDArray[np.float64] | float | None
461
+ thrust : npt.NDArray[np.floating] | float | None
448
462
  Override the thrust setting at each waypoint, [:math: `N`].
449
463
  q_fuel : float
450
464
  Lower calorific value (LCV) of fuel, [:math:`J \ kg_{fuel}^{-1}`].
@@ -457,12 +471,12 @@ class AircraftPerformance(Model):
457
471
  Derived performance metrics at each waypoint.
458
472
  """
459
473
 
460
- def ensure_true_airspeed_on_source(self) -> npt.NDArray[np.float64]:
474
+ def ensure_true_airspeed_on_source(self) -> npt.NDArray[np.floating]:
461
475
  """Add ``true_airspeed`` field to :attr:`source` data if not already present.
462
476
 
463
477
  Returns
464
478
  -------
465
- npt.NDArray[np.float64]
479
+ npt.NDArray[np.floating]
466
480
  True airspeed, [:math:`m s^{-1}`]. If ``true_airspeed`` is already present
467
481
  on :attr:`source`, this is returned directly. Otherwise, it is calculated
468
482
  using :meth:`Flight.segment_true_airspeed`.
@@ -515,30 +529,30 @@ class AircraftPerformanceData:
515
529
 
516
530
  Parameters
517
531
  ----------
518
- fuel_flow : npt.NDArray[np.float64]
532
+ fuel_flow : npt.NDArray[np.floating]
519
533
  Fuel mass flow rate for each waypoint, [:math:`kg s^{-1}`]
520
- aircraft_mass : npt.NDArray[np.float64]
534
+ aircraft_mass : npt.NDArray[np.floating]
521
535
  Aircraft mass for each waypoint, [:math:`kg`]
522
- true_airspeed : npt.NDArray[np.float64]
536
+ true_airspeed : npt.NDArray[np.floating]
523
537
  True airspeed at each waypoint, [:math: `m s^{-1}`]
524
- fuel_burn: npt.NDArray[np.float64]
538
+ fuel_burn: npt.NDArray[np.floating]
525
539
  Fuel consumption for each waypoint, [:math:`kg`]. Set to an array of
526
540
  all nan values if it cannot be computed (ie, working with gridpoints).
527
- thrust: npt.NDArray[np.float64]
541
+ thrust: npt.NDArray[np.floating]
528
542
  Thrust force, [:math:`N`]
529
- engine_efficiency: npt.NDArray[np.float64]
543
+ engine_efficiency: npt.NDArray[np.floating]
530
544
  Overall propulsion efficiency for each waypoint
531
- rocd : npt.NDArray[np.float64]
545
+ rocd : npt.NDArray[np.floating]
532
546
  Rate of climb and descent, [:math:`ft min^{-1}`]
533
547
  """
534
548
 
535
- fuel_flow: npt.NDArray[np.float64]
536
- aircraft_mass: npt.NDArray[np.float64]
537
- true_airspeed: npt.NDArray[np.float64]
538
- fuel_burn: npt.NDArray[np.float64]
539
- thrust: npt.NDArray[np.float64]
540
- engine_efficiency: npt.NDArray[np.float64]
541
- rocd: npt.NDArray[np.float64]
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]
542
556
 
543
557
 
544
558
  # --------------------------------
@@ -547,7 +561,7 @@ class AircraftPerformanceData:
547
561
 
548
562
 
549
563
  @dataclasses.dataclass
550
- class AircraftPerformanceGridParams(ModelParams):
564
+ class AircraftPerformanceGridParams(ModelParams, CommonAircraftPerformanceParams):
551
565
  """Parameters for :class:`AircraftPerformanceGrid`."""
552
566
 
553
567
  #: Fuel type
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__ = ("cache_dir", "allow_clear")
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
- "project",
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
- "chunk_size",
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__ = ("fl_attrs", "final_waypoints")
35
+ __slots__ = ("final_waypoints", "fl_attrs")
36
36
 
37
37
  def __init__(
38
38
  self,
@@ -132,13 +132,13 @@ class Fleet(Flight):
132
132
  return final_waypoints, fl_attrs
133
133
 
134
134
  @override
135
- def copy(self, **kwargs: Any) -> Fleet:
135
+ def copy(self, **kwargs: Any) -> Self:
136
136
  kwargs.setdefault("fuel", self.fuel)
137
137
  kwargs.setdefault("fl_attrs", self.fl_attrs)
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) -> Fleet:
141
+ def filter(self, mask: npt.NDArray[np.bool_], copy: bool = True, **kwargs: Any) -> Self:
142
142
  kwargs.setdefault("fuel", self.fuel)
143
143
 
144
144
  flight_ids = set(np.unique(self["flight_id"][mask]))
@@ -162,7 +162,6 @@ class Fleet(Flight):
162
162
  cls,
163
163
  seq: Iterable[Flight],
164
164
  broadcast_numeric: bool = True,
165
- copy: bool = True,
166
165
  attrs: dict[str, Any] | None = None,
167
166
  ) -> Self:
168
167
  """Instantiate a :class:`Fleet` instance from an iterable of :class:`Flight`.
@@ -177,8 +176,6 @@ class Fleet(Flight):
177
176
  An iterable of :class:`Flight` instances.
178
177
  broadcast_numeric : bool, optional
179
178
  If True, broadcast numeric attributes to data variables.
180
- copy : bool, optional
181
- If True, make copy of each flight instance in ``seq``.
182
179
  attrs : dict[str, Any] | None, optional
183
180
  Global attribute to attach to instance.
184
181
 
@@ -190,15 +187,15 @@ class Fleet(Flight):
190
187
  in ``seq``.
191
188
  """
192
189
 
193
- def _maybe_copy(fl: Flight) -> Flight:
194
- return fl.copy() if copy else fl
190
+ def _shallow_copy(fl: Flight) -> Flight:
191
+ return Flight(VectorDataDict(fl.data), attrs=fl.attrs, copy=False, fuel=fl.fuel)
195
192
 
196
193
  def _maybe_warn(fl: Flight) -> Flight:
197
194
  if not fl:
198
195
  warnings.warn("Empty flight found in sequence. It will be filtered out.")
199
196
  return fl
200
197
 
201
- seq = tuple(_maybe_copy(fl) for fl in seq if _maybe_warn(fl))
198
+ seq = tuple(_shallow_copy(fl) for fl in seq if _maybe_warn(fl))
202
199
 
203
200
  if not seq:
204
201
  msg = "Cannot create Fleet from empty sequence."
@@ -265,12 +262,12 @@ class Fleet(Flight):
265
262
 
266
263
  def segment_true_airspeed(
267
264
  self,
268
- u_wind: npt.NDArray[np.float64] | float = 0.0,
269
- v_wind: npt.NDArray[np.float64] | float = 0.0,
265
+ u_wind: npt.NDArray[np.floating] | float = 0.0,
266
+ v_wind: npt.NDArray[np.floating] | float = 0.0,
270
267
  smooth: bool = True,
271
268
  window_length: int = 7,
272
269
  polyorder: int = 1,
273
- ) -> npt.NDArray[np.float64]:
270
+ ) -> npt.NDArray[np.floating]:
274
271
  """Calculate the true airspeed [:math:`m / s`] from the ground speed and horizontal winds.
275
272
 
276
273
  Because Flight.segment_true_airspeed uses a smoothing pattern, waypoints in :attr:`data`
@@ -302,7 +299,7 @@ class Fleet(Flight):
302
299
  self[key] = v_wind
303
300
 
304
301
  # Calculate TAS on each flight individually
305
- def calc_tas(fl: Flight) -> npt.NDArray[np.float64]:
302
+ def calc_tas(fl: Flight) -> npt.NDArray[np.floating]:
306
303
  u = fl.get("__u_wind", u_wind)
307
304
  v = fl.get("__v_wind", v_wind)
308
305
 
@@ -325,19 +322,27 @@ class Fleet(Flight):
325
322
  return np.concatenate(tas)
326
323
 
327
324
  @override
328
- def segment_groundspeed(self, *args: Any, **kwargs: Any) -> npt.NDArray[np.float64]:
325
+ def segment_groundspeed(self, *args: Any, **kwargs: Any) -> npt.NDArray[np.floating]:
329
326
  fls = self.to_flight_list(copy=False)
330
327
  gs = [fl.segment_groundspeed(*args, **kwargs) for fl in fls]
331
328
  return np.concatenate(gs)
332
329
 
333
330
  @override
334
- def resample_and_fill(self, *args: Any, **kwargs: Any) -> Fleet:
331
+ def resample_and_fill(self, *args: Any, **kwargs: Any) -> Self:
335
332
  flights = self.to_flight_list(copy=False)
333
+
334
+ # We need to ensure that each flight has an flight_id attrs field
335
+ # When we call fl.resample_and_fill, any flight_id data field
336
+ # will be lost, so the call to Fleet.from_seq will fail.
337
+ for fl in flights:
338
+ if "flight_id" not in fl.attrs:
339
+ fl.attrs["flight_id"] = _extract_flight_id(fl)
340
+
336
341
  flights = [fl.resample_and_fill(*args, **kwargs) for fl in flights]
337
- return type(self).from_seq(flights, copy=False, broadcast_numeric=False, attrs=self.attrs)
342
+ return type(self).from_seq(flights, broadcast_numeric=False, attrs=self.attrs)
338
343
 
339
344
  @override
340
- def segment_length(self) -> npt.NDArray[np.float64]:
345
+ def segment_length(self) -> npt.NDArray[np.floating]:
341
346
  return np.where(self.final_waypoints, np.nan, super().segment_length())
342
347
 
343
348
  @property
@@ -346,11 +351,11 @@ class Fleet(Flight):
346
351
  return np.nanmax(self.segment_length()).item()
347
352
 
348
353
  @override
349
- def segment_azimuth(self) -> npt.NDArray[np.float64]:
354
+ def segment_azimuth(self) -> npt.NDArray[np.floating]:
350
355
  return np.where(self.final_waypoints, np.nan, super().segment_azimuth())
351
356
 
352
357
  @override
353
- def segment_angle(self) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
358
+ def segment_angle(self) -> tuple[npt.NDArray[np.floating], npt.NDArray[np.floating]]:
354
359
  sin_a, cos_a = super().segment_angle()
355
360
  sin_a[self.final_waypoints] = np.nan
356
361
  cos_a[self.final_waypoints] = np.nan
@@ -368,8 +373,7 @@ class Fleet(Flight):
368
373
  force_filter: bool = False,
369
374
  drop: bool = True,
370
375
  keep_original_index: bool = False,
371
- climb_descend_at_end: bool = False,
372
- ) -> Flight:
376
+ ) -> NoReturn:
373
377
  msg = "Only implemented for Flight instances"
374
378
  raise NotImplementedError(msg)
375
379