pycontrails 0.54.5__cp311-cp311-win_amd64.whl → 0.54.7__cp311-cp311-win_amd64.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 (42) hide show
  1. pycontrails/__init__.py +1 -1
  2. pycontrails/_version.py +2 -2
  3. pycontrails/core/aircraft_performance.py +46 -46
  4. pycontrails/core/airports.py +7 -5
  5. pycontrails/core/flight.py +6 -8
  6. pycontrails/core/flightplan.py +11 -11
  7. pycontrails/core/met.py +41 -33
  8. pycontrails/core/met_var.py +80 -0
  9. pycontrails/core/models.py +80 -3
  10. pycontrails/core/rgi_cython.cp311-win_amd64.pyd +0 -0
  11. pycontrails/core/vector.py +66 -0
  12. pycontrails/datalib/_met_utils/metsource.py +1 -1
  13. pycontrails/datalib/ecmwf/era5.py +5 -6
  14. pycontrails/datalib/ecmwf/era5_model_level.py +4 -5
  15. pycontrails/datalib/ecmwf/ifs.py +1 -3
  16. pycontrails/datalib/gfs/gfs.py +1 -3
  17. pycontrails/datalib/spire/__init__.py +5 -0
  18. pycontrails/datalib/spire/exceptions.py +62 -0
  19. pycontrails/datalib/spire/spire.py +606 -0
  20. pycontrails/models/accf.py +4 -4
  21. pycontrails/models/cocip/cocip.py +116 -19
  22. pycontrails/models/cocip/cocip_params.py +10 -1
  23. pycontrails/models/cocip/output_formats.py +1 -0
  24. pycontrails/models/cocip/unterstrasser_wake_vortex.py +132 -30
  25. pycontrails/models/cocipgrid/cocip_grid.py +3 -0
  26. pycontrails/models/dry_advection.py +51 -19
  27. pycontrails/models/emissions/black_carbon.py +19 -14
  28. pycontrails/models/emissions/emissions.py +8 -8
  29. pycontrails/models/humidity_scaling/humidity_scaling.py +1 -1
  30. pycontrails/models/pcc.py +1 -2
  31. pycontrails/models/ps_model/ps_model.py +3 -31
  32. pycontrails/models/ps_model/ps_operational_limits.py +2 -6
  33. pycontrails/models/tau_cirrus.py +13 -6
  34. pycontrails/physics/constants.py +2 -1
  35. pycontrails/physics/geo.py +3 -3
  36. {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/METADATA +5 -6
  37. {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/NOTICE +1 -1
  38. {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/RECORD +41 -39
  39. {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/WHEEL +1 -1
  40. pycontrails/datalib/spire.py +0 -739
  41. {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/LICENSE +0 -0
  42. {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/top_level.txt +0 -0
@@ -507,6 +507,9 @@ class VectorDataset:
507
507
  >>> vector.get_data_or_attr("c", default=5)
508
508
  5
509
509
 
510
+ See Also
511
+ --------
512
+ get_constant
510
513
  """
511
514
  marker = self.__marker
512
515
 
@@ -1013,6 +1016,69 @@ class VectorDataset:
1013
1016
  )
1014
1017
  self.broadcast_attrs(numeric_attrs, overwrite)
1015
1018
 
1019
+ def get_constant(self, key: str, default: Any = __marker) -> Any:
1020
+ """Get a constant value from :attr:`attrs` or :attr:`data`.
1021
+
1022
+ - If ``key`` is found in :attr:`attrs`, the value is returned.
1023
+ - If ``key`` is found in :attr:`data`, the common value is returned if all
1024
+ values are equal.
1025
+ - If ``key`` is not found in :attr:`attrs` or :attr:`data` and a ``default`` is provided,
1026
+ the ``default`` is returned.
1027
+ - Otherwise, a KeyError is raised.
1028
+
1029
+ Parameters
1030
+ ----------
1031
+ key : str
1032
+ Key to look for.
1033
+ default : Any, optional
1034
+ Default value to return if ``key`` is not found in :attr:`attrs` or :attr:`data`.
1035
+
1036
+ Returns
1037
+ -------
1038
+ Any
1039
+ The constant value for ``key``.
1040
+
1041
+ Raises
1042
+ ------
1043
+ KeyError
1044
+ If ``key`` is not found in :attr:`attrs` or the values in :attr:`data` are not equal
1045
+ and ``default`` is not provided.
1046
+
1047
+ Examples
1048
+ --------
1049
+ >>> vector = VectorDataset({"a": [1, 1, 1], "b": [2, 2, 3]})
1050
+ >>> vector.get_constant("a")
1051
+ np.int64(1)
1052
+ >>> vector.get_constant("b")
1053
+ Traceback (most recent call last):
1054
+ ...
1055
+ KeyError: "A constant key 'b' not found in attrs or data"
1056
+ >>> vector.get_constant("b", 3)
1057
+ 3
1058
+
1059
+ See Also
1060
+ --------
1061
+ get_data_or_attr
1062
+ GeoVectorDataset.constants
1063
+ """
1064
+ marker = self.__marker
1065
+
1066
+ out = self.attrs.get(key, marker)
1067
+ if out is not marker:
1068
+ return out
1069
+
1070
+ out = self.data.get(key, marker)
1071
+ if out is not marker:
1072
+ vals = np.unique(out)
1073
+ if len(vals) == 1:
1074
+ return vals[0]
1075
+
1076
+ if default is not marker:
1077
+ return default
1078
+
1079
+ msg = f"A constant key '{key}' not found in attrs or data"
1080
+ raise KeyError(msg)
1081
+
1016
1082
  # ------------
1017
1083
  # I / O
1018
1084
  # ------------
@@ -265,7 +265,7 @@ def _find_match(
265
265
 
266
266
  # list of MetVariable options
267
267
  # here we extract the first MetVariable in var that is supported
268
- elif isinstance(var, list | tuple):
268
+ if isinstance(var, list | tuple):
269
269
  for v in var:
270
270
  # sanity check since we don't support other types as lists
271
271
  if not isinstance(v, MetVariable):
@@ -88,9 +88,8 @@ class ERA5(ECMWFAPI):
88
88
  If None, cache is turned off.
89
89
  url : str | None
90
90
  Override the default `cdsapi <https://github.com/ecmwf/cdsapi>`_ url.
91
- As of August 2024, the url for the `CDS-Beta <https://cds-beta.climate.copernicus.eu>`_
92
- is "https://cds-beta.climate.copernicus.eu/api", and the url for the legacy server is
93
- "https://cds.climate.copernicus.eu/api/v2". If None, the url is set
91
+ As of January 2025, the url for the `CDS Server <https://cds.climate.copernicus.eu>`_
92
+ is "https://cds.climate.copernicus.eu/api". If None, the url is set
94
93
  by the ``CDSAPI_URL`` environment variable. If this is not defined, the
95
94
  ``cdsapi`` package will determine the url.
96
95
  key : str | None
@@ -539,12 +538,12 @@ class ERA5(ECMWFAPI):
539
538
  LOG.debug("Input dataset processed with pycontrails > 0.29")
540
539
  return ds
541
540
 
542
- # For "reanalysis-era5-single-levels"
543
- # then the netcdf file does not contain the dimension "level"
541
+ # For "reanalysis-era5-single-levels",
542
+ # the netcdf file does not contain the dimension "level"
544
543
  if self.is_single_level:
545
544
  ds = ds.expand_dims(level=self.pressure_levels)
546
545
 
547
- # New CDS-Beta gives "valid_time" instead of "time"
546
+ # New CDS (Aug 2024) gives "valid_time" instead of "time"
548
547
  # and "pressure_level" instead of "level"
549
548
  if "valid_time" in ds:
550
549
  ds = ds.rename(valid_time="time")
@@ -119,9 +119,8 @@ class ERA5ModelLevel(ECMWFAPI):
119
119
  By default, False.
120
120
  url : str | None
121
121
  Override the default `cdsapi <https://github.com/ecmwf/cdsapi>`_ url.
122
- As of August 2024, the url for the `CDS-Beta <https://cds-beta.climate.copernicus.eu>`_
123
- is "https://cds-beta.climate.copernicus.eu/api", and the url for the legacy server is
124
- "https://cds.climate.copernicus.eu/api/v2". If None, the url is set
122
+ As of January 2025, the url for the `CDS Server <https://cds.climate.copernicus.eu>`_
123
+ is "https://cds.climate.copernicus.eu/api". If None, the url is set
125
124
  by the ``CDSAPI_URL`` environment variable. If this is not defined, the
126
125
  ``cdsapi`` package will determine the url.
127
126
  key : str | None
@@ -465,13 +464,13 @@ class ERA5ModelLevel(ECMWFAPI):
465
464
  ds_ml = xr.open_dataset(ml_target)
466
465
  lnsp = xr.open_dataarray(lnsp_target)
467
466
 
468
- # New CDS-Beta gives "valid_time" instead of "time"
467
+ # New CDS (Aug 2024) gives "valid_time" instead of "time"
469
468
  if "valid_time" in ds_ml:
470
469
  ds_ml = ds_ml.rename(valid_time="time")
471
470
  if "valid_time" in lnsp.dims:
472
471
  lnsp = lnsp.rename(valid_time="time")
473
472
 
474
- # The legacy CDS gives "level" instead of "model_level"
473
+ # Legacy CDS (prior to Aug 2024) gives "level" instead of "model_level"
475
474
  if "level" in ds_ml.dims:
476
475
  ds_ml = ds_ml.rename(level="model_level")
477
476
 
@@ -247,9 +247,7 @@ class IFS(metsource.MetDataSource):
247
247
  ds_fl = ds_fl.drop_vars(names=["hyai", "hybi", "hyam", "hybm"])
248
248
 
249
249
  # merge all datasets using the "ds_fl" dimensions as the join keys
250
- ds = xr.merge([ds_fl, ds_full, ds_surface, ds_rad], join="left") # order matters!
251
-
252
- return ds
250
+ return xr.merge([ds_fl, ds_full, ds_surface, ds_rad], join="left") # order matters!
253
251
 
254
252
  def _calc_geopotential(self, ds: xr.Dataset) -> xr.DataArray:
255
253
  warnings.warn(
@@ -570,9 +570,7 @@ class GFSForecast(metsource.MetDataSource):
570
570
  ds = ds.expand_dims("time")
571
571
 
572
572
  # drop step/number
573
- ds = ds.drop_vars(["step", "nominalTop", "surface"], errors="ignore")
574
-
575
- return ds
573
+ return ds.drop_vars(["step", "nominalTop", "surface"], errors="ignore")
576
574
 
577
575
  def _process_dataset(self, ds: xr.Dataset, **kwargs: Any) -> met.MetDataset:
578
576
  """Process the :class:`xr.Dataset` opened from cache or local files.
@@ -0,0 +1,5 @@
1
+ """`Spire Aviation <https://spire.com/aviation/>`_ ADS-B data support."""
2
+
3
+ from pycontrails.datalib.spire.spire import ValidateTrajectoryHandler
4
+
5
+ __all__ = ["ValidateTrajectoryHandler"]
@@ -0,0 +1,62 @@
1
+ """Custom exceptions used for spire data validation."""
2
+
3
+
4
+ class BaseSpireError(Exception):
5
+ """Base class for all spire exceptions."""
6
+
7
+
8
+ class BadTrajectoryException(BaseSpireError):
9
+ """A generic exception indicating a trajectory (flight instance) is invalid."""
10
+
11
+
12
+ class SchemaError(BaseSpireError):
13
+ """Data object is inconsistent with required schema."""
14
+
15
+
16
+ class OrderingError(BaseSpireError):
17
+ """Data object has incorrect ordering."""
18
+
19
+
20
+ class OriginAirportError(BaseSpireError):
21
+ """
22
+ Trajectory is not originating at expected location.
23
+
24
+ We do not assume that the departure airports are invariant in the dataframe,
25
+ thus we handle the case of multiple airports listed.
26
+ """
27
+
28
+
29
+ class DestinationAirportError(BaseSpireError):
30
+ """Trajectory is not terminating at expected location."""
31
+
32
+
33
+ class FlightTooShortError(BaseSpireError):
34
+ """Trajectory is unreasonably short in flight time."""
35
+
36
+
37
+ class FlightTooLongError(BaseSpireError):
38
+ """Trajectory is unreasonably long in flight time."""
39
+
40
+
41
+ class FlightTooSlowError(BaseSpireError):
42
+ """Trajectory has period(s) of unrealistically slow speed."""
43
+
44
+
45
+ class FlightTooFastError(BaseSpireError):
46
+ """Trajectory has period(s) of unrealistically high speed."""
47
+
48
+
49
+ class ROCDError(BaseSpireError):
50
+ """Trajectory has an unrealistic rate of climb or descent."""
51
+
52
+
53
+ class FlightAltitudeProfileError(BaseSpireError):
54
+ """Trajectory has an unrealistic rate of climb or descent."""
55
+
56
+
57
+ class FlightDuplicateTimestamps(BaseSpireError):
58
+ """Trajectory contains waypoints with the same timestamp."""
59
+
60
+
61
+ class FlightInvariantFieldViolation(BaseSpireError):
62
+ """Trajectory has multiple values for field(s) that should be invariant."""