pycontrails 0.54.5__cp310-cp310-win_amd64.whl → 0.54.7__cp310-cp310-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.
- pycontrails/__init__.py +1 -1
- pycontrails/_version.py +2 -2
- pycontrails/core/aircraft_performance.py +46 -46
- pycontrails/core/airports.py +7 -5
- pycontrails/core/flight.py +6 -8
- pycontrails/core/flightplan.py +11 -11
- pycontrails/core/met.py +41 -33
- pycontrails/core/met_var.py +80 -0
- pycontrails/core/models.py +80 -3
- pycontrails/core/rgi_cython.cp310-win_amd64.pyd +0 -0
- pycontrails/core/vector.py +66 -0
- pycontrails/datalib/_met_utils/metsource.py +1 -1
- pycontrails/datalib/ecmwf/era5.py +5 -6
- pycontrails/datalib/ecmwf/era5_model_level.py +4 -5
- pycontrails/datalib/ecmwf/ifs.py +1 -3
- pycontrails/datalib/gfs/gfs.py +1 -3
- pycontrails/datalib/spire/__init__.py +5 -0
- pycontrails/datalib/spire/exceptions.py +62 -0
- pycontrails/datalib/spire/spire.py +606 -0
- pycontrails/models/accf.py +4 -4
- pycontrails/models/cocip/cocip.py +116 -19
- pycontrails/models/cocip/cocip_params.py +10 -1
- pycontrails/models/cocip/output_formats.py +1 -0
- pycontrails/models/cocip/unterstrasser_wake_vortex.py +132 -30
- pycontrails/models/cocipgrid/cocip_grid.py +3 -0
- pycontrails/models/dry_advection.py +51 -19
- pycontrails/models/emissions/black_carbon.py +19 -14
- pycontrails/models/emissions/emissions.py +8 -8
- pycontrails/models/humidity_scaling/humidity_scaling.py +1 -1
- pycontrails/models/pcc.py +1 -2
- pycontrails/models/ps_model/ps_model.py +3 -31
- pycontrails/models/ps_model/ps_operational_limits.py +2 -6
- pycontrails/models/tau_cirrus.py +13 -6
- pycontrails/physics/constants.py +2 -1
- pycontrails/physics/geo.py +3 -3
- {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/METADATA +5 -6
- {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/NOTICE +1 -1
- {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/RECORD +41 -39
- {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/WHEEL +1 -1
- pycontrails/datalib/spire.py +0 -739
- {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/LICENSE +0 -0
- {pycontrails-0.54.5.dist-info → pycontrails-0.54.7.dist-info}/top_level.txt +0 -0
pycontrails/core/vector.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
92
|
-
is "https://cds
|
|
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
|
-
#
|
|
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
|
|
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
|
|
123
|
-
is "https://cds
|
|
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
|
|
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
|
-
#
|
|
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
|
|
pycontrails/datalib/ecmwf/ifs.py
CHANGED
|
@@ -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
|
-
|
|
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(
|
pycontrails/datalib/gfs/gfs.py
CHANGED
|
@@ -570,9 +570,7 @@ class GFSForecast(metsource.MetDataSource):
|
|
|
570
570
|
ds = ds.expand_dims("time")
|
|
571
571
|
|
|
572
572
|
# drop step/number
|
|
573
|
-
|
|
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,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."""
|