pycontrails 0.57.0__cp312-cp312-macosx_11_0_arm64.whl → 0.58.0__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.
- pycontrails/_version.py +3 -3
- pycontrails/core/aircraft_performance.py +1 -1
- pycontrails/core/cache.py +2 -2
- pycontrails/core/fleet.py +2 -7
- pycontrails/core/flight.py +2 -7
- pycontrails/core/interpolation.py +42 -64
- pycontrails/core/met.py +36 -16
- pycontrails/core/polygon.py +3 -3
- pycontrails/core/rgi_cython.cpython-312-darwin.so +0 -0
- pycontrails/core/vector.py +3 -8
- pycontrails/datalib/_met_utils/metsource.py +4 -7
- pycontrails/datalib/ecmwf/common.py +2 -2
- pycontrails/datalib/ecmwf/hres.py +2 -2
- pycontrails/datalib/ecmwf/ifs.py +1 -1
- pycontrails/datalib/gfs/gfs.py +1 -1
- pycontrails/datalib/himawari/header_struct.py +1 -1
- pycontrails/datalib/himawari/himawari.py +20 -7
- pycontrails/datalib/leo_utils/sentinel_metadata.py +9 -9
- pycontrails/ext/synthetic_flight.py +2 -2
- pycontrails/models/cocip/cocip_uncertainty.py +1 -1
- pycontrails/models/cocip/contrail_properties.py +1 -1
- pycontrails/models/cocip/output_formats.py +1 -1
- pycontrails/models/cocipgrid/cocip_grid.py +3 -3
- pycontrails/models/dry_advection.py +1 -1
- pycontrails/models/extended_k15.py +4 -4
- pycontrails/models/humidity_scaling/humidity_scaling.py +2 -2
- pycontrails/models/ps_model/ps_grid.py +2 -2
- pycontrails/models/sac.py +1 -1
- pycontrails/models/tau_cirrus.py +1 -1
- pycontrails/physics/thermo.py +1 -1
- pycontrails/utils/iteration.py +1 -1
- {pycontrails-0.57.0.dist-info → pycontrails-0.58.0.dist-info}/METADATA +5 -5
- {pycontrails-0.57.0.dist-info → pycontrails-0.58.0.dist-info}/RECORD +37 -37
- {pycontrails-0.57.0.dist-info → pycontrails-0.58.0.dist-info}/WHEEL +0 -0
- {pycontrails-0.57.0.dist-info → pycontrails-0.58.0.dist-info}/licenses/LICENSE +0 -0
- {pycontrails-0.57.0.dist-info → pycontrails-0.58.0.dist-info}/licenses/NOTICE +0 -0
- {pycontrails-0.57.0.dist-info → pycontrails-0.58.0.dist-info}/top_level.txt +0 -0
pycontrails/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.58.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 58, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g142ff7355'
|
|
@@ -550,7 +550,7 @@ class AircraftPerformance(Model):
|
|
|
550
550
|
if self.met is None:
|
|
551
551
|
cond = np.isnan(u) & np.isnan(v)
|
|
552
552
|
else:
|
|
553
|
-
met_level_max = self.met.data["level"][-1].item()
|
|
553
|
+
met_level_max = self.met.data["level"][-1].item()
|
|
554
554
|
cond = self.source.level > met_level_max
|
|
555
555
|
|
|
556
556
|
# We DON'T overwrite the original u and v arrays already attached to the source
|
pycontrails/core/cache.py
CHANGED
|
@@ -189,7 +189,7 @@ class DiskCacheStore(CacheStore):
|
|
|
189
189
|
self,
|
|
190
190
|
cache_dir: str | pathlib.Path | None = None,
|
|
191
191
|
allow_clear: bool = False,
|
|
192
|
-
):
|
|
192
|
+
) -> None:
|
|
193
193
|
if cache_dir is None:
|
|
194
194
|
# Avoid unnecessary import of platformdirs (called in _get_user_cache_dir)
|
|
195
195
|
cache_dir = os.getenv("PYCONTRAILS_CACHE_DIR") or _get_user_cache_dir()
|
|
@@ -461,7 +461,7 @@ class GCPCacheStore(CacheStore):
|
|
|
461
461
|
timeout: int = 300,
|
|
462
462
|
show_progress: bool = False,
|
|
463
463
|
chunk_size: int = 64 * 262144,
|
|
464
|
-
):
|
|
464
|
+
) -> None:
|
|
465
465
|
try:
|
|
466
466
|
from google.cloud import storage
|
|
467
467
|
except ModuleNotFoundError as e:
|
pycontrails/core/fleet.py
CHANGED
|
@@ -5,12 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import sys
|
|
6
6
|
import warnings
|
|
7
7
|
from collections.abc import Iterable
|
|
8
|
-
from typing import Any, NoReturn
|
|
9
|
-
|
|
10
|
-
if sys.version_info >= (3, 11):
|
|
11
|
-
from typing import Self
|
|
12
|
-
else:
|
|
13
|
-
from typing_extensions import Self
|
|
8
|
+
from typing import Any, NoReturn, Self
|
|
14
9
|
|
|
15
10
|
if sys.version_info >= (3, 12):
|
|
16
11
|
from typing import override
|
|
@@ -122,7 +117,7 @@ class Fleet(Flight):
|
|
|
122
117
|
# Set default fl_attrs if not provided
|
|
123
118
|
fl_attrs = fl_attrs or {}
|
|
124
119
|
for flight_id in groups.index:
|
|
125
|
-
fl_attrs.setdefault(flight_id, {})
|
|
120
|
+
fl_attrs.setdefault(flight_id, {})
|
|
126
121
|
|
|
127
122
|
extra = fl_attrs.keys() - groups.index
|
|
128
123
|
if extra:
|
pycontrails/core/flight.py
CHANGED
|
@@ -6,18 +6,13 @@ import enum
|
|
|
6
6
|
import logging
|
|
7
7
|
import sys
|
|
8
8
|
import warnings
|
|
9
|
-
from typing import TYPE_CHECKING, Any, NoReturn
|
|
9
|
+
from typing import TYPE_CHECKING, Any, NoReturn, Self
|
|
10
10
|
|
|
11
11
|
if sys.version_info >= (3, 12):
|
|
12
12
|
from typing import override
|
|
13
13
|
else:
|
|
14
14
|
from typing_extensions import override
|
|
15
15
|
|
|
16
|
-
if sys.version_info >= (3, 11):
|
|
17
|
-
from typing import Self
|
|
18
|
-
else:
|
|
19
|
-
from typing_extensions import Self
|
|
20
|
-
|
|
21
16
|
|
|
22
17
|
import numpy as np
|
|
23
18
|
import numpy.typing as npt
|
|
@@ -2138,7 +2133,7 @@ def segment_rocd(
|
|
|
2138
2133
|
T_correction[:-1] = (air_temperature[:-1] + air_temperature[1:]) / (T_isa[:-1] + T_isa[1:])
|
|
2139
2134
|
T_correction[-1] = np.nan
|
|
2140
2135
|
|
|
2141
|
-
return T_correction * out
|
|
2136
|
+
return T_correction * out
|
|
2142
2137
|
|
|
2143
2138
|
|
|
2144
2139
|
def _resample_to_freq_or_time(
|
|
@@ -26,57 +26,74 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
|
|
|
26
26
|
|
|
27
27
|
This class is a thin wrapper around the
|
|
28
28
|
:class:`scipy.interpolate.RegularGridInterpolator` in order to make typical
|
|
29
|
-
``pycontrails`` use-cases more
|
|
29
|
+
``pycontrails`` linear interpolation use-cases more performant:
|
|
30
30
|
|
|
31
|
-
#. Avoid ``RegularGridInterpolator`` constructor validation
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
#. Avoid ``RegularGridInterpolator`` constructor validation when `method="linear"`.
|
|
32
|
+
In :func:`interp`, parameters are carefully crafted to fit into the intended form,
|
|
33
|
+
thereby making validation unnecessary.
|
|
34
34
|
#. Override the :meth:`_evaluate_linear` method with a faster implementation. See
|
|
35
|
-
|
|
35
|
+
the :meth:`_evaluate_linear` docstring for more information.
|
|
36
36
|
|
|
37
|
-
This class should not be used directly. Instead, use the
|
|
37
|
+
**This class should not be used directly. Instead, use the ``interp`` function.**
|
|
38
38
|
|
|
39
39
|
.. versionchanged:: 0.40.0
|
|
40
40
|
|
|
41
41
|
The :meth:`_evaluate_linear` method now uses a Cython implementation. The dtype
|
|
42
42
|
of the output is now consistent with the dtype of the underlying :attr:`values`
|
|
43
43
|
|
|
44
|
+
.. versionchanged:: 0.58.0
|
|
45
|
+
|
|
46
|
+
Any ``method`` other than ``"linear"`` now uses the
|
|
47
|
+
:class:`scipy.interpolate.RegularGridInterpolator` implementation. This
|
|
48
|
+
allows for greater flexibility in the ``method`` parameter.
|
|
49
|
+
|
|
44
50
|
Parameters
|
|
45
51
|
----------
|
|
46
52
|
points : tuple[npt.NDArray[np.floating], ...]
|
|
47
53
|
Coordinates of the grid points.
|
|
48
54
|
values : npt.NDArray[np.floating]
|
|
49
55
|
Grid values. The shape of this array must be compatible with the
|
|
50
|
-
coordinates.
|
|
51
|
-
or ``np.float64``.
|
|
56
|
+
coordinates.
|
|
52
57
|
method : str
|
|
53
58
|
Passed into :class:`scipy.interpolate.RegularGridInterpolator`
|
|
54
59
|
bounds_error : bool
|
|
55
60
|
Passed into :class:`scipy.interpolate.RegularGridInterpolator`
|
|
56
61
|
fill_value : float | np.float64 | None
|
|
57
62
|
Passed into :class:`scipy.interpolate.RegularGridInterpolator`
|
|
63
|
+
|
|
64
|
+
See Also
|
|
65
|
+
--------
|
|
66
|
+
scipy.interpolate.RegularGridInterpolator
|
|
67
|
+
interp
|
|
58
68
|
"""
|
|
59
69
|
|
|
60
70
|
def __init__(
|
|
61
71
|
self,
|
|
62
72
|
points: tuple[npt.NDArray[np.floating], ...],
|
|
63
73
|
values: npt.NDArray[np.floating],
|
|
74
|
+
*,
|
|
64
75
|
method: str,
|
|
65
76
|
bounds_error: bool,
|
|
66
77
|
fill_value: float | np.float64 | None,
|
|
67
|
-
):
|
|
68
|
-
if values.dtype not in (np.float32, np.float64):
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
) -> None:
|
|
79
|
+
if method != "linear" or values.dtype not in (np.float32, np.float64):
|
|
80
|
+
# Slow path: use parent class
|
|
81
|
+
super().__init__(
|
|
82
|
+
points,
|
|
83
|
+
values,
|
|
84
|
+
method=method,
|
|
85
|
+
bounds_error=bounds_error,
|
|
86
|
+
fill_value=fill_value,
|
|
87
|
+
)
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
# Fast path: no validation
|
|
72
91
|
self.grid = points
|
|
73
92
|
self.values = values
|
|
74
|
-
|
|
75
|
-
# see https://github.com/scipy/scipy/releases/tag/v1.13.0
|
|
76
|
-
self.method = _pick_method(scipy.__version__, method)
|
|
93
|
+
self.method = method
|
|
77
94
|
self.bounds_error = bounds_error
|
|
78
95
|
self.fill_value = fill_value
|
|
79
|
-
self._spline = None
|
|
96
|
+
self._spline = None # XXX: setting private attribute on RGI
|
|
80
97
|
|
|
81
98
|
def _prepare_xi_simple(self, xi: npt.NDArray[np.floating]) -> npt.NDArray[np.bool_]:
|
|
82
99
|
"""Run looser version of :meth:`_prepare_xi`.
|
|
@@ -103,7 +120,7 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
|
|
|
103
120
|
|
|
104
121
|
return np.zeros(xi.shape[0], dtype=bool)
|
|
105
122
|
|
|
106
|
-
return self._find_out_of_bounds(xi.T)
|
|
123
|
+
return self._find_out_of_bounds(xi.T) # XXX: calling private method on RGI
|
|
107
124
|
|
|
108
125
|
def __call__(
|
|
109
126
|
self, xi: npt.NDArray[np.floating], method: str | None = None
|
|
@@ -130,7 +147,7 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
|
|
|
130
147
|
return super().__call__(xi, method)
|
|
131
148
|
|
|
132
149
|
out_of_bounds = self._prepare_xi_simple(xi)
|
|
133
|
-
xi_indices, norm_distances =
|
|
150
|
+
xi_indices, norm_distances = self._find_indices(xi.T) # XXX: calling private method on RGI
|
|
134
151
|
|
|
135
152
|
out = self._evaluate_linear(xi_indices, norm_distances)
|
|
136
153
|
return self._set_out_of_bounds(out, out_of_bounds)
|
|
@@ -223,45 +240,6 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
|
|
|
223
240
|
raise ValueError(msg)
|
|
224
241
|
|
|
225
242
|
|
|
226
|
-
def _pick_method(scipy_version: str, method: str) -> str:
|
|
227
|
-
"""Select an interpolation method.
|
|
228
|
-
|
|
229
|
-
For scipy versions 1.13.0 and later, fall back on legacy implementations
|
|
230
|
-
of tensor-product spline methods. The default implementations in 1.13.0
|
|
231
|
-
and later are incompatible with this class.
|
|
232
|
-
|
|
233
|
-
Parameters
|
|
234
|
-
----------
|
|
235
|
-
scipy_version : str
|
|
236
|
-
scipy version (major.minor.patch)
|
|
237
|
-
|
|
238
|
-
method : str
|
|
239
|
-
Interpolation method. Passed into :class:`scipy.interpolate.RegularGridInterpolator`
|
|
240
|
-
as-is unless ``scipy_version`` is 1.13.0 or later and ``method`` is ``"slinear"``,
|
|
241
|
-
``"cubic"``, or ``"quintic"``. In this case, ``"_legacy"`` is appended to ``method``.
|
|
242
|
-
|
|
243
|
-
Returns
|
|
244
|
-
-------
|
|
245
|
-
str
|
|
246
|
-
Interpolation method adjusted for compatibility with this class.
|
|
247
|
-
"""
|
|
248
|
-
if method == "linear":
|
|
249
|
-
return method
|
|
250
|
-
|
|
251
|
-
try:
|
|
252
|
-
version = scipy_version.split(".")
|
|
253
|
-
major = int(version[0])
|
|
254
|
-
minor = int(version[1])
|
|
255
|
-
except (IndexError, ValueError) as exc:
|
|
256
|
-
msg = f"Failed to parse major and minor version from {scipy_version}"
|
|
257
|
-
raise ValueError(msg) from exc
|
|
258
|
-
|
|
259
|
-
reimplemented_methods = ["slinear", "cubic", "quintic"]
|
|
260
|
-
if major > 1 or ((major == 1 and minor >= 13) and method in reimplemented_methods):
|
|
261
|
-
return method + "_legacy"
|
|
262
|
-
return method
|
|
263
|
-
|
|
264
|
-
|
|
265
243
|
def _floatize_time(
|
|
266
244
|
time: npt.NDArray[np.datetime64], offset: np.datetime64
|
|
267
245
|
) -> npt.NDArray[np.floating]:
|
|
@@ -431,7 +409,7 @@ def interp(
|
|
|
431
409
|
Include ``indices`` and ``return_indices`` experimental parameters.
|
|
432
410
|
Currently, nan values in ``longitude``, ``latitude``, ``level``, or ``time``
|
|
433
411
|
are always propagated through to the output, regardless of ``bounds_error``.
|
|
434
|
-
In other words, a ValueError for an out of bounds coordinate is only raised
|
|
412
|
+
In other words, a ``ValueError`` for an out of bounds coordinate is only raised
|
|
435
413
|
if a non-nan value is out of bounds.
|
|
436
414
|
|
|
437
415
|
.. versionchanged:: 0.40.0
|
|
@@ -480,9 +458,9 @@ def interp(
|
|
|
480
458
|
|
|
481
459
|
See Also
|
|
482
460
|
--------
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
461
|
+
pycontrails.MetDataArray.interpolate
|
|
462
|
+
scipy.interpolate.interpn
|
|
463
|
+
scipy.interpolate.RegularGridInterpolator
|
|
486
464
|
"""
|
|
487
465
|
if localize:
|
|
488
466
|
coords = {"longitude": longitude, "latitude": latitude, "level": level, "time": time}
|
|
@@ -579,7 +557,7 @@ def _linear_interp_with_indices(
|
|
|
579
557
|
if indices is None:
|
|
580
558
|
assert xi is not None, "xi must be provided if indices is None"
|
|
581
559
|
out_of_bounds = interp._prepare_xi_simple(xi)
|
|
582
|
-
xi_indices, norm_distances =
|
|
560
|
+
xi_indices, norm_distances = interp._find_indices(xi.T)
|
|
583
561
|
indices = RGIArtifacts(xi_indices, norm_distances, out_of_bounds)
|
|
584
562
|
|
|
585
563
|
out = interp._evaluate_linear(indices.xi_indices, indices.norm_distances)
|
|
@@ -606,7 +584,7 @@ class EmissionsProfileInterpolator:
|
|
|
606
584
|
|
|
607
585
|
This class simply wraps :func:`numpy.interp` with fixed values for the
|
|
608
586
|
``xp`` and ``fp`` arguments. Unlike :class:`xarray.DataArray` interpolation,
|
|
609
|
-
the
|
|
587
|
+
the :func:`numpy.interp` automatically clips values outside the range of the
|
|
610
588
|
``xp`` array.
|
|
611
589
|
|
|
612
590
|
Parameters
|
pycontrails/core/met.py
CHANGED
|
@@ -26,15 +26,11 @@ from typing import (
|
|
|
26
26
|
Any,
|
|
27
27
|
Generic,
|
|
28
28
|
Literal,
|
|
29
|
+
Self,
|
|
29
30
|
TypeVar,
|
|
30
31
|
overload,
|
|
31
32
|
)
|
|
32
33
|
|
|
33
|
-
if sys.version_info >= (3, 11):
|
|
34
|
-
from typing import Self
|
|
35
|
-
else:
|
|
36
|
-
from typing_extensions import Self
|
|
37
|
-
|
|
38
34
|
if sys.version_info >= (3, 12):
|
|
39
35
|
from typing import override
|
|
40
36
|
else:
|
|
@@ -211,14 +207,22 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
211
207
|
Raises
|
|
212
208
|
------
|
|
213
209
|
ValueError
|
|
214
|
-
If one of the coordinates is not sorted.
|
|
210
|
+
If one of the coordinates is not sorted or contains duplicate values.
|
|
215
211
|
"""
|
|
216
212
|
indexes = self.indexes
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
213
|
+
for coord in self.dim_order:
|
|
214
|
+
arr = indexes[coord]
|
|
215
|
+
d = np.diff(arr)
|
|
216
|
+
zero = np.zeros((), dtype=d.dtype) # ensure same dtype
|
|
217
|
+
|
|
218
|
+
if np.any(d <= zero):
|
|
219
|
+
if np.any(d == zero):
|
|
220
|
+
msg = f"Coordinate '{coord}' contains duplicate values."
|
|
221
|
+
else:
|
|
222
|
+
msg = f"Coordinate '{coord}' not sorted."
|
|
223
|
+
|
|
224
|
+
msg += " Instantiate with 'copy=True'."
|
|
225
|
+
raise ValueError(msg)
|
|
222
226
|
|
|
223
227
|
def _validate_transpose(self) -> None:
|
|
224
228
|
"""Check that data is transposed according to :attr:`dim_order`."""
|
|
@@ -271,6 +275,10 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
271
275
|
Auxiliary coordinates (altitude and air_pressure) are now cast to the same
|
|
272
276
|
dtype as the underlying grid data.
|
|
273
277
|
|
|
278
|
+
.. versionchanged:: 0.58.0
|
|
279
|
+
|
|
280
|
+
Duplicate dimension values are dropped, keeping the first occurrence.
|
|
281
|
+
|
|
274
282
|
|
|
275
283
|
Parameters
|
|
276
284
|
----------
|
|
@@ -297,6 +305,18 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
297
305
|
# sortby to ensure each coordinate has ascending order
|
|
298
306
|
self.data = self.data.sortby(list(self.dim_order), ascending=True)
|
|
299
307
|
|
|
308
|
+
# Drop any duplicated dimension values
|
|
309
|
+
indexes = self.indexes
|
|
310
|
+
for coord in self.dim_order:
|
|
311
|
+
arr = indexes[coord]
|
|
312
|
+
d = np.diff(arr)
|
|
313
|
+
zero = np.zeros((), dtype=d.dtype) # ensure same dtype
|
|
314
|
+
|
|
315
|
+
if np.any(d == zero):
|
|
316
|
+
# Remove duplicates
|
|
317
|
+
filt = np.r_[True, d > zero] # prepend True keeps the first occurrence
|
|
318
|
+
self.data = self.data.isel({coord: filt})
|
|
319
|
+
|
|
300
320
|
if not self.is_wrapped:
|
|
301
321
|
# Ensure longitude is contained in interval [-180, 180)
|
|
302
322
|
# If longitude has value at 180, we might not want to shift it?
|
|
@@ -1087,7 +1107,7 @@ class MetDataset(MetBase):
|
|
|
1087
1107
|
out[key] = da.values.ravel() # type: ignore[index]
|
|
1088
1108
|
|
|
1089
1109
|
if transfer_attrs:
|
|
1090
|
-
out.attrs.update(self.attrs)
|
|
1110
|
+
out.attrs.update(self.attrs)
|
|
1091
1111
|
|
|
1092
1112
|
return out
|
|
1093
1113
|
|
|
@@ -1300,7 +1320,7 @@ class MetDataset(MetBase):
|
|
|
1300
1320
|
coords: dict[str, np.ndarray] = {}
|
|
1301
1321
|
for key, val in input_data.items():
|
|
1302
1322
|
dtype = "datetime64[ns]" if key == "time" else COORD_DTYPE
|
|
1303
|
-
arr: np.ndarray = np.asarray(val, dtype=dtype)
|
|
1323
|
+
arr: np.ndarray = np.asarray(val, dtype=dtype)
|
|
1304
1324
|
|
|
1305
1325
|
if arr.ndim == 0:
|
|
1306
1326
|
arr = arr.reshape(1)
|
|
@@ -1889,7 +1909,7 @@ class MetDataArray(MetBase):
|
|
|
1889
1909
|
if not self.binary:
|
|
1890
1910
|
raise NotImplementedError("proportion method is only implemented for binary fields")
|
|
1891
1911
|
|
|
1892
|
-
return self.data.sum().values.item() / self.data.count().values.item()
|
|
1912
|
+
return self.data.sum().values.item() / self.data.count().values.item()
|
|
1893
1913
|
|
|
1894
1914
|
def find_edges(self) -> Self:
|
|
1895
1915
|
"""Find edges of regions.
|
|
@@ -2598,9 +2618,9 @@ def _extract_2d_arr_and_altitude(
|
|
|
2598
2618
|
except KeyError:
|
|
2599
2619
|
altitude = None
|
|
2600
2620
|
else:
|
|
2601
|
-
altitude = round(altitude)
|
|
2621
|
+
altitude = round(altitude)
|
|
2602
2622
|
|
|
2603
|
-
return arr, altitude
|
|
2623
|
+
return arr, altitude
|
|
2604
2624
|
|
|
2605
2625
|
|
|
2606
2626
|
def downselect(data: XArrayType, bbox: tuple[float, ...]) -> XArrayType:
|
pycontrails/core/polygon.py
CHANGED
|
@@ -238,7 +238,7 @@ def _contours_to_polygons(
|
|
|
238
238
|
latitude=latitude,
|
|
239
239
|
precision=precision,
|
|
240
240
|
buffer=buffer,
|
|
241
|
-
i=child_i,
|
|
241
|
+
i=child_i,
|
|
242
242
|
)
|
|
243
243
|
|
|
244
244
|
candidate = shapely.Polygon(polygon.exterior, [h.exterior for h in holes])
|
|
@@ -354,11 +354,11 @@ def find_multipolygon(
|
|
|
354
354
|
return shapely.MultiPolygon()
|
|
355
355
|
|
|
356
356
|
assert len(hierarchy) == 1
|
|
357
|
-
hierarchy = hierarchy[0]
|
|
357
|
+
hierarchy = hierarchy[0]
|
|
358
358
|
|
|
359
359
|
polygons = _contours_to_polygons(
|
|
360
360
|
contours, # type: ignore[arg-type]
|
|
361
|
-
hierarchy,
|
|
361
|
+
hierarchy,
|
|
362
362
|
min_area,
|
|
363
363
|
convex_hull,
|
|
364
364
|
epsilon,
|
|
Binary file
|
pycontrails/core/vector.py
CHANGED
|
@@ -8,12 +8,7 @@ import logging
|
|
|
8
8
|
import sys
|
|
9
9
|
import warnings
|
|
10
10
|
from collections.abc import Generator, Iterable, Iterator, Sequence
|
|
11
|
-
from typing import Any, overload
|
|
12
|
-
|
|
13
|
-
if sys.version_info >= (3, 11):
|
|
14
|
-
from typing import Self
|
|
15
|
-
else:
|
|
16
|
-
from typing_extensions import Self
|
|
11
|
+
from typing import Any, Self, overload
|
|
17
12
|
|
|
18
13
|
if sys.version_info >= (3, 12):
|
|
19
14
|
from typing import override
|
|
@@ -315,7 +310,7 @@ class VectorDataset: # noqa: PLW1641
|
|
|
315
310
|
# Set attributes: always shallow copy
|
|
316
311
|
# -----------------------------------
|
|
317
312
|
|
|
318
|
-
self.attrs = AttrDict(attrs or {})
|
|
313
|
+
self.attrs = AttrDict(attrs or {})
|
|
319
314
|
self.attrs.update(attrs_kwargs)
|
|
320
315
|
|
|
321
316
|
@classmethod
|
|
@@ -1389,7 +1384,7 @@ class GeoVectorDataset(VectorDataset):
|
|
|
1389
1384
|
):
|
|
1390
1385
|
keys = *self.required_keys, "altitude"
|
|
1391
1386
|
self.data = VectorDataDict(_empty_vector_dict(keys))
|
|
1392
|
-
self.attrs = AttrDict(attrs or {})
|
|
1387
|
+
self.attrs = AttrDict(attrs or {})
|
|
1393
1388
|
self.attrs.update(attrs_kwargs)
|
|
1394
1389
|
return
|
|
1395
1390
|
|
|
@@ -175,16 +175,13 @@ def parse_pressure_levels(
|
|
|
175
175
|
|
|
176
176
|
out = arr.tolist()
|
|
177
177
|
if supported is None:
|
|
178
|
-
return out
|
|
178
|
+
return out
|
|
179
179
|
|
|
180
|
-
if missing := set(out).difference(supported):
|
|
181
|
-
msg = (
|
|
182
|
-
f"Pressure levels {sorted(missing)} are not supported. " # type: ignore[type-var]
|
|
183
|
-
f"Supported levels: {supported}"
|
|
184
|
-
)
|
|
180
|
+
if missing := set(out).difference(supported):
|
|
181
|
+
msg = f"Pressure levels {sorted(missing)} are not supported. Supported levels: {supported}"
|
|
185
182
|
raise ValueError(msg)
|
|
186
183
|
|
|
187
|
-
return out
|
|
184
|
+
return out
|
|
188
185
|
|
|
189
186
|
|
|
190
187
|
def parse_variables(variables: VariableInput, supported: list[MetVariable]) -> list[MetVariable]:
|
|
@@ -61,14 +61,14 @@ class ECMWFAPI(metsource.MetDataSource):
|
|
|
61
61
|
|
|
62
62
|
# downselect times
|
|
63
63
|
if not self.timesteps:
|
|
64
|
-
self.timesteps = ds["time"].values.astype("datetime64[ns]").tolist()
|
|
64
|
+
self.timesteps = ds["time"].values.astype("datetime64[ns]").tolist()
|
|
65
65
|
else:
|
|
66
66
|
try:
|
|
67
67
|
ds = ds.sel(time=self.timesteps)
|
|
68
68
|
except KeyError as exc:
|
|
69
69
|
# this snippet shows the missing times for convenience
|
|
70
70
|
np_timesteps = {np.datetime64(t, "ns") for t in self.timesteps}
|
|
71
|
-
missing_times = sorted(np_timesteps.difference(ds["time"].values))
|
|
71
|
+
missing_times = sorted(np_timesteps.difference(ds["time"].values))
|
|
72
72
|
msg = f"Input dataset is missing time coordinates {[str(t) for t in missing_times]}"
|
|
73
73
|
raise KeyError(msg) from exc
|
|
74
74
|
|
|
@@ -708,7 +708,7 @@ class HRES(ECMWFAPI):
|
|
|
708
708
|
|
|
709
709
|
# set forecast time if it's not defined (this occurs when only the paths param is provided)
|
|
710
710
|
if not hasattr(self, "forecast_time"):
|
|
711
|
-
self.forecast_time = ds["time"].values.astype("datetime64[s]").tolist()
|
|
711
|
+
self.forecast_time = ds["time"].values.astype("datetime64[s]").tolist()
|
|
712
712
|
|
|
713
713
|
# check that forecast_time is correct if defined
|
|
714
714
|
# note the "time" coordinate here is the HRES forecast_time
|
|
@@ -723,7 +723,7 @@ class HRES(ECMWFAPI):
|
|
|
723
723
|
# set timesteps if not defined
|
|
724
724
|
# note that "time" is now the actual timestep coordinates
|
|
725
725
|
if not self.timesteps:
|
|
726
|
-
self.timesteps = ds["time"].values.astype("datetime64[s]").tolist()
|
|
726
|
+
self.timesteps = ds["time"].values.astype("datetime64[s]").tolist()
|
|
727
727
|
|
|
728
728
|
self.cache_dataset(ds)
|
|
729
729
|
|
pycontrails/datalib/ecmwf/ifs.py
CHANGED
|
@@ -149,7 +149,7 @@ class IFS(metsource.MetDataSource):
|
|
|
149
149
|
else:
|
|
150
150
|
# set timesteps from dataset "time" coordinates
|
|
151
151
|
# np.datetime64 doesn't covert to list[datetime] unless its unit is us
|
|
152
|
-
self.timesteps = ds["time"].values.astype("datetime64[us]").tolist()
|
|
152
|
+
self.timesteps = ds["time"].values.astype("datetime64[us]").tolist()
|
|
153
153
|
|
|
154
154
|
# downselect hyam/hybm coefficients by the "lev" coordinate
|
|
155
155
|
# (this is a 1-indexed verison of nhym)
|
pycontrails/datalib/gfs/gfs.py
CHANGED
|
@@ -595,7 +595,7 @@ class GFSForecast(metsource.MetDataSource):
|
|
|
595
595
|
else:
|
|
596
596
|
# set timesteps from dataset "time" coordinates
|
|
597
597
|
# np.datetime64 doesn't covert to list[datetime] unless its unit is us
|
|
598
|
-
self.timesteps = ds["time"].values.astype("datetime64[us]").tolist()
|
|
598
|
+
self.timesteps = ds["time"].values.astype("datetime64[us]").tolist()
|
|
599
599
|
|
|
600
600
|
# if "level" is not in dims and
|
|
601
601
|
# length of the requested pressure levels is 1
|
|
@@ -205,7 +205,7 @@ HEADER_STRUCT_SCHEMA: dict[int, _HeaderBlock] = {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
|
|
208
|
-
def parse_himawari_header(content: bytes) -> dict:
|
|
208
|
+
def parse_himawari_header(content: bytes) -> dict[str, dict[str, Any]]:
|
|
209
209
|
"""Parse the Himawari header data.
|
|
210
210
|
|
|
211
211
|
Skips variable-length fields and spares.
|
|
@@ -160,7 +160,10 @@ def _extract_band_from_rpath(rpath: str) -> str:
|
|
|
160
160
|
return f"B{suffix[:2]}" # B??
|
|
161
161
|
|
|
162
162
|
|
|
163
|
-
def _mask_invalid(
|
|
163
|
+
def _mask_invalid(
|
|
164
|
+
data: npt.NDArray[np.uint16],
|
|
165
|
+
calib_info: dict[str, Any],
|
|
166
|
+
) -> npt.NDArray[np.float32]:
|
|
164
167
|
"""Mask invalid data."""
|
|
165
168
|
error_pixel = calib_info["count_error_pixels"]
|
|
166
169
|
outside_pixel = calib_info["count_outside_scan_area"]
|
|
@@ -218,7 +221,9 @@ def _counts_to_radiance(
|
|
|
218
221
|
return counts * gain + const
|
|
219
222
|
|
|
220
223
|
|
|
221
|
-
def _load_image_data(
|
|
224
|
+
def _load_image_data(
|
|
225
|
+
content: bytes, metadata: dict[str, dict[str, Any]]
|
|
226
|
+
) -> npt.NDArray[np.float32]:
|
|
222
227
|
counts = _load_raw_counts(content, metadata)
|
|
223
228
|
|
|
224
229
|
calib_info = metadata["calibration_information"]
|
|
@@ -230,7 +235,10 @@ def _load_image_data(content: bytes, metadata: dict) -> npt.NDArray[np.float32]:
|
|
|
230
235
|
return _radiance_to_brightness_temperature(radiance, calib_info)
|
|
231
236
|
|
|
232
237
|
|
|
233
|
-
def _ahi_fixed_grid(
|
|
238
|
+
def _ahi_fixed_grid(
|
|
239
|
+
proj_info: dict[str, Any],
|
|
240
|
+
arr: np.ndarray,
|
|
241
|
+
) -> tuple[xr.DataArray, xr.DataArray]:
|
|
234
242
|
n_lines, n_columns = arr.shape
|
|
235
243
|
|
|
236
244
|
i = np.arange(n_columns, dtype=np.float32)
|
|
@@ -277,7 +285,11 @@ def _himawari_proj4_string(proj_info: dict[str, Any]) -> str:
|
|
|
277
285
|
return f"+proj=geos +h={h} +a={a} +b={b} +lon_0={lon} +sweep=x +units=m +no_defs"
|
|
278
286
|
|
|
279
287
|
|
|
280
|
-
def _earth_disk_mask(
|
|
288
|
+
def _earth_disk_mask(
|
|
289
|
+
proj_info: dict[str, Any],
|
|
290
|
+
x: xr.DataArray,
|
|
291
|
+
y: xr.DataArray,
|
|
292
|
+
) -> npt.NDArray[np.bool_]:
|
|
281
293
|
"""Return a boolean mask where True indicates pixels over the Earth disk."""
|
|
282
294
|
a = proj_info["equatorial_radius"] * 1000.0 # km -> m
|
|
283
295
|
b = proj_info["polar_radius"] * 1000.0 # km -> m
|
|
@@ -301,7 +313,7 @@ def _earth_disk_mask(proj_info: dict, x: xr.DataArray, y: xr.DataArray) -> npt.N
|
|
|
301
313
|
return discriminant >= 0.0
|
|
302
314
|
|
|
303
315
|
|
|
304
|
-
def _parse_start_time(metadata: dict) -> datetime.datetime:
|
|
316
|
+
def _parse_start_time(metadata: dict[str, dict[str, Any]]) -> datetime.datetime:
|
|
305
317
|
"""Parse the start time from the metadata."""
|
|
306
318
|
mjd_value = metadata["basic_information"]["obs_start_time"]
|
|
307
319
|
mjd_epoch = datetime.datetime(1858, 11, 17)
|
|
@@ -355,9 +367,10 @@ def _parse_s3_raw_data(raw_data: list[bytes]) -> xr.DataArray:
|
|
|
355
367
|
|
|
356
368
|
|
|
357
369
|
class Himawari:
|
|
358
|
-
"""Support for Himawari-8/9 satellite data
|
|
370
|
+
"""Support for Himawari-8/9 satellite data access via AWS S3.
|
|
359
371
|
|
|
360
|
-
This interface requires the ``s3fs`` package
|
|
372
|
+
This interface requires the ``s3fs`` package to download data from the
|
|
373
|
+
`AWS Public Dataset <https://registry.opendata.aws/himawari/>`_.
|
|
361
374
|
|
|
362
375
|
Parameters
|
|
363
376
|
----------
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""Download and parse Sentinel metadata."""
|
|
2
2
|
|
|
3
|
+
import datetime
|
|
3
4
|
import os
|
|
4
5
|
import re
|
|
5
6
|
import xml.etree.ElementTree as ET
|
|
6
7
|
from collections.abc import Collection
|
|
7
|
-
from datetime import datetime, timedelta, timezone
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
import numpy.typing as npt
|
|
@@ -464,10 +464,10 @@ def parse_ephemeris_sentinel(datatsrip_metadata_path: str) -> pd.DataFrame:
|
|
|
464
464
|
if position_elem is None or position_elem.text is None:
|
|
465
465
|
continue # skip if missing
|
|
466
466
|
|
|
467
|
-
gps_time = datetime.strptime(gps_time_elem.text, "%Y-%m-%dT%H:%M:%S")
|
|
467
|
+
gps_time = datetime.datetime.strptime(gps_time_elem.text, "%Y-%m-%dT%H:%M:%S")
|
|
468
468
|
|
|
469
469
|
# Convert GPS to UTC time as there is a few seconds between them
|
|
470
|
-
utc_time = gps_to_utc(gps_time).replace(tzinfo=
|
|
470
|
+
utc_time = gps_to_utc(gps_time).replace(tzinfo=datetime.UTC)
|
|
471
471
|
|
|
472
472
|
# Parse positions in ECEF coordinate system
|
|
473
473
|
x, y, z = map(float, position_elem.text.split())
|
|
@@ -643,30 +643,30 @@ def get_time_delay_detectors(
|
|
|
643
643
|
# Time helper functions
|
|
644
644
|
|
|
645
645
|
|
|
646
|
-
def gps_to_utc(gps_time: datetime) -> datetime:
|
|
646
|
+
def gps_to_utc(gps_time: datetime.datetime) -> datetime.datetime:
|
|
647
647
|
"""Convert GPS time (datetime object) to UTC time.
|
|
648
648
|
|
|
649
649
|
https://gssc.esa.int/navipedia/index.php/Transformations_between_Time_Systems
|
|
650
650
|
"""
|
|
651
651
|
|
|
652
|
-
gps_tai_offset = timedelta(seconds=19)
|
|
653
|
-
utc_tai_offset = timedelta(seconds=37)
|
|
652
|
+
gps_tai_offset = datetime.timedelta(seconds=19)
|
|
653
|
+
utc_tai_offset = datetime.timedelta(seconds=37)
|
|
654
654
|
|
|
655
655
|
# Convert GPS time to UTC
|
|
656
656
|
return gps_time + gps_tai_offset - utc_tai_offset
|
|
657
657
|
|
|
658
658
|
|
|
659
|
-
def _calculate_average_time(times: Collection[datetime]) -> datetime:
|
|
659
|
+
def _calculate_average_time(times: Collection[datetime.datetime]) -> datetime.datetime:
|
|
660
660
|
"""Return the average time from a list of times."""
|
|
661
661
|
# Compute the average time
|
|
662
662
|
avg_timestamp = sum(t.timestamp() for t in times) / len(times)
|
|
663
|
-
return datetime.fromtimestamp(avg_timestamp)
|
|
663
|
+
return datetime.datetime.fromtimestamp(avg_timestamp)
|
|
664
664
|
|
|
665
665
|
|
|
666
666
|
def _calculate_timedeltas(detector_times: dict[int, str]) -> dict[int, pd.Timedelta]:
|
|
667
667
|
"""Calculate the time difference between a detector and the average time."""
|
|
668
668
|
detector_times_dt = {
|
|
669
|
-
detector_id: datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%S.%f")
|
|
669
|
+
detector_id: datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%S.%f")
|
|
670
670
|
for detector_id, time_str in detector_times.items()
|
|
671
671
|
}
|
|
672
672
|
|
|
@@ -305,8 +305,8 @@ class SyntheticFlight:
|
|
|
305
305
|
*src,
|
|
306
306
|
az,
|
|
307
307
|
npts,
|
|
308
|
-
m_per_timestep,
|
|
309
|
-
return_back_azimuth=False,
|
|
308
|
+
m_per_timestep,
|
|
309
|
+
return_back_azimuth=False,
|
|
310
310
|
)
|
|
311
311
|
longitude = np.asarray(result.lons)
|
|
312
312
|
latitude = np.asarray(result.lats)
|
|
@@ -30,7 +30,7 @@ class habit_dirichlet(rv_frozen):
|
|
|
30
30
|
- Table 2 in :cite:`schumannEffectiveRadiusIce2011`
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
-
def __init__(self, C: float = 96.0):
|
|
33
|
+
def __init__(self, C: float = 96.0) -> None:
|
|
34
34
|
self.C = C
|
|
35
35
|
|
|
36
36
|
def rvs(self, *args: Any, **kwds: Any) -> npt.NDArray[np.float32]:
|
|
@@ -236,7 +236,7 @@ def initial_ice_particle_number(
|
|
|
236
236
|
phase, [:math:`# m^{-1}`]
|
|
237
237
|
"""
|
|
238
238
|
if min_aei is not None:
|
|
239
|
-
aei = np.clip(aei, min=min_aei) # type: ignore[
|
|
239
|
+
aei = np.clip(aei, min=min_aei) # type: ignore[call-overload]
|
|
240
240
|
return fuel_dist * aei
|
|
241
241
|
|
|
242
242
|
|
|
@@ -2228,7 +2228,7 @@ def compare_cocip_with_goes(
|
|
|
2228
2228
|
fig = plt.figure(figsize=(1.2 * x_dim, y_dim))
|
|
2229
2229
|
pc = ccrs.PlateCarree()
|
|
2230
2230
|
ax = fig.add_subplot(projection=pc, extent=bbox)
|
|
2231
|
-
ax.coastlines()
|
|
2231
|
+
ax.coastlines()
|
|
2232
2232
|
ax.imshow(rgb, extent=extent, transform=transform)
|
|
2233
2233
|
|
|
2234
2234
|
ax.set_xticks([spatial_bbox[0], spatial_bbox[2]], crs=ccrs.PlateCarree())
|
|
@@ -114,7 +114,7 @@ class CocipGrid(models.Model):
|
|
|
114
114
|
rad: MetDataset,
|
|
115
115
|
params: dict[str, Any] | None = None,
|
|
116
116
|
**params_kwargs: Any,
|
|
117
|
-
):
|
|
117
|
+
) -> None:
|
|
118
118
|
super().__init__(met, params=params, **params_kwargs)
|
|
119
119
|
|
|
120
120
|
compute_tau_cirrus = self.params["compute_tau_cirrus_in_model_init"]
|
|
@@ -386,7 +386,7 @@ class CocipGrid(models.Model):
|
|
|
386
386
|
"dt_integration": dt_integration_str,
|
|
387
387
|
"aircraft_type": self.get_source_param("aircraft_type"),
|
|
388
388
|
"pycontrails_version": pycontrails.__version__,
|
|
389
|
-
**self.source.attrs,
|
|
389
|
+
**self.source.attrs,
|
|
390
390
|
}
|
|
391
391
|
if ap_model := self.params["aircraft_performance"]:
|
|
392
392
|
attrs["ap_model"] = type(ap_model).__name__
|
|
@@ -2210,7 +2210,7 @@ def result_to_metdataset(
|
|
|
2210
2210
|
# Update source
|
|
2211
2211
|
for k, v in data_vars.items(): # type: ignore[assignment]
|
|
2212
2212
|
source[k] = v
|
|
2213
|
-
source.attrs.update(attrs)
|
|
2213
|
+
source.attrs.update(attrs)
|
|
2214
2214
|
|
|
2215
2215
|
# Return reference to source
|
|
2216
2216
|
return source
|
|
@@ -24,12 +24,12 @@ DEFAULT_EXHAUST_T = 600.0 # Exhaust temperature, [K]
|
|
|
24
24
|
EXPERIMENTAL_WARNING = True
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class ParticleType(enum.
|
|
27
|
+
class ParticleType(enum.StrEnum):
|
|
28
28
|
"""Enumeration of particle types."""
|
|
29
29
|
|
|
30
|
-
NVPM =
|
|
31
|
-
VPM =
|
|
32
|
-
AMBIENT =
|
|
30
|
+
NVPM = enum.auto()
|
|
31
|
+
VPM = enum.auto()
|
|
32
|
+
AMBIENT = enum.auto()
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -442,7 +442,7 @@ class ExponentialBoostLatitudeCorrectionHumidityScaling(HumidityScaling):
|
|
|
442
442
|
met: MetDataset | None = None,
|
|
443
443
|
params: dict[str, Any] | None = None,
|
|
444
444
|
**params_kwargs: Any,
|
|
445
|
-
):
|
|
445
|
+
) -> None:
|
|
446
446
|
if (params is None or "level_type" not in params) and ("level_type" not in params_kwargs):
|
|
447
447
|
msg = (
|
|
448
448
|
"The default level_type will change from 'pressure' to 'model' "
|
|
@@ -863,7 +863,7 @@ class HistogramMatching(HumidityScaling):
|
|
|
863
863
|
met: MetDataset | None = None,
|
|
864
864
|
params: dict[str, Any] | None = None,
|
|
865
865
|
**params_kwargs: Any,
|
|
866
|
-
):
|
|
866
|
+
) -> None:
|
|
867
867
|
if (params is None or "level_type" not in params) and (
|
|
868
868
|
params_kwargs is None or "level_type" not in params_kwargs
|
|
869
869
|
):
|
|
@@ -639,9 +639,9 @@ def ps_nominal_optimize_mach(
|
|
|
639
639
|
if sin_a is None or cos_a is None:
|
|
640
640
|
msg = "Segment angles must be provide if wind data is specified"
|
|
641
641
|
raise ValueError(msg)
|
|
642
|
-
headwind = -(northward_wind * cos_a + eastward_wind * sin_a)
|
|
642
|
+
headwind = -(northward_wind * cos_a + eastward_wind * sin_a)
|
|
643
643
|
else:
|
|
644
|
-
headwind = 0.0
|
|
644
|
+
headwind = 0.0
|
|
645
645
|
|
|
646
646
|
min_mach = ps_operational_limits.minimum_mach_num(
|
|
647
647
|
air_pressure=level * 100.0,
|
pycontrails/models/sac.py
CHANGED
|
@@ -133,7 +133,7 @@ class SAC(Model):
|
|
|
133
133
|
|
|
134
134
|
G = slope_mixing_line(specific_humidity, air_pressure, engine_efficiency, ei_h2o, q_fuel)
|
|
135
135
|
T_sat_liquid_ = T_sat_liquid(G)
|
|
136
|
-
rh_crit_sac = rh_critical_sac(air_temperature, T_sat_liquid_, G)
|
|
136
|
+
rh_crit_sac = rh_critical_sac(air_temperature, T_sat_liquid_, G)
|
|
137
137
|
rh = thermo.rh(specific_humidity, air_temperature, air_pressure) # type: ignore[type-var]
|
|
138
138
|
sac_ = sac(rh, rh_crit_sac)
|
|
139
139
|
|
pycontrails/models/tau_cirrus.py
CHANGED
|
@@ -91,7 +91,7 @@ def tau_cirrus(met: MetDataset) -> xr.DataArray:
|
|
|
91
91
|
# dask.array.gradient expects at least 2 elements in each chunk
|
|
92
92
|
level_axis = geopotential_height.get_axis_num("level")
|
|
93
93
|
if geopotential_height.chunks:
|
|
94
|
-
level_chunks = geopotential_height.chunks[level_axis]
|
|
94
|
+
level_chunks = geopotential_height.chunks[level_axis]
|
|
95
95
|
if any(chunk < 2 for chunk in level_chunks):
|
|
96
96
|
geopotential_height = geopotential_height.chunk(level=-1)
|
|
97
97
|
|
pycontrails/physics/thermo.py
CHANGED
|
@@ -269,7 +269,7 @@ def mk05_e_sat_liquid_prime(T: ArrayScalarLike) -> ArrayScalarLike:
|
|
|
269
269
|
Derivative of :func:`mk05_e_sat_liquid`
|
|
270
270
|
"""
|
|
271
271
|
tanh_term = np.tanh(0.0415 * (T - 218.8))
|
|
272
|
-
return mk05_e_sat_liquid(T) * (
|
|
272
|
+
return mk05_e_sat_liquid(T) * (
|
|
273
273
|
6763.22 / T**2
|
|
274
274
|
- 4.21 / T
|
|
275
275
|
+ 0.000367
|
pycontrails/utils/iteration.py
CHANGED
|
@@ -6,7 +6,7 @@ from collections.abc import Iterator
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def chunk_list(lst: list, n: int) -> Iterator[list[Any]]:
|
|
9
|
+
def chunk_list(lst: list[Any], n: int) -> Iterator[list[Any]]:
|
|
10
10
|
"""Yield successive n-sized chunks from list."""
|
|
11
11
|
|
|
12
12
|
for i in range(0, len(lst), n):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycontrails
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.58.0
|
|
4
4
|
Summary: Python library for modeling aviation climate impacts
|
|
5
5
|
Author-email: "Contrails.org" <py@contrails.org>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -13,23 +13,23 @@ Classifier: Development Status :: 4 - Beta
|
|
|
13
13
|
Classifier: Intended Audience :: Science/Research
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
23
23
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
24
24
|
Classifier: Typing :: Typed
|
|
25
|
-
Requires-Python: >=3.
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
License-File: LICENSE
|
|
28
28
|
License-File: NOTICE
|
|
29
29
|
Requires-Dist: dask>=2022.3
|
|
30
30
|
Requires-Dist: numpy>=1.22
|
|
31
31
|
Requires-Dist: pandas>=2.0
|
|
32
|
-
Requires-Dist: scipy>=1.
|
|
32
|
+
Requires-Dist: scipy>=1.12
|
|
33
33
|
Requires-Dist: typing-extensions>=4.5; python_version < "3.12"
|
|
34
34
|
Requires-Dist: xarray>=2022.3
|
|
35
35
|
Provides-Extra: complete
|
|
@@ -140,7 +140,7 @@ Documentation and examples available at [py.contrails.org](https://py.contrails.
|
|
|
140
140
|
|
|
141
141
|
### Install with pip
|
|
142
142
|
|
|
143
|
-
You can install pycontrails from PyPI with `pip` (Python 3.
|
|
143
|
+
You can install pycontrails from PyPI with `pip` (Python 3.11 or later required):
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
146
|
$ pip install pycontrails
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
pycontrails-0.
|
|
2
|
-
pycontrails-0.
|
|
3
|
-
pycontrails-0.
|
|
4
|
-
pycontrails-0.
|
|
5
|
-
pycontrails-0.
|
|
6
|
-
pycontrails-0.
|
|
7
|
-
pycontrails/_version.py,sha256=
|
|
1
|
+
pycontrails-0.58.0.dist-info/RECORD,,
|
|
2
|
+
pycontrails-0.58.0.dist-info/WHEEL,sha256=V1loQ6TpxABu1APUg0MoTRBOzSKT5xVc3skizX-ovCU,136
|
|
3
|
+
pycontrails-0.58.0.dist-info/top_level.txt,sha256=Z8J1R_AiBAyCVjNw6jYLdrA68PrQqTg0t3_Yek_IZ0Q,29
|
|
4
|
+
pycontrails-0.58.0.dist-info/METADATA,sha256=-pOZxATs-SGOiS7FppQtQYehP9MYFbQV2l_VnbptyJg,9129
|
|
5
|
+
pycontrails-0.58.0.dist-info/licenses/LICENSE,sha256=gJ-h7SFFD1mCfR6a7HILvEtodDT6Iig8bLXdgqR6ucA,10175
|
|
6
|
+
pycontrails-0.58.0.dist-info/licenses/NOTICE,sha256=fiBPdjYibMpDzf8hqcn7TvAQ-yeK10q_Nqq24DnskYg,1962
|
|
7
|
+
pycontrails/_version.py,sha256=ife3IDQF-DAoy1CwSUU90Z0xGG9P1GsYeBh-Ic3uecI,714
|
|
8
8
|
pycontrails/__init__.py,sha256=9ypSB2fKZlKghTvSrjWo6OHm5qfASwiTIvlMew3Olu4,2037
|
|
9
9
|
pycontrails/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
pycontrails/core/vector.py,sha256=
|
|
10
|
+
pycontrails/core/vector.py,sha256=hms3hea2Y86LOuZFfOqzGZToqpOVksgXikM_S5w355w,73498
|
|
11
11
|
pycontrails/core/models.py,sha256=3mDTqp1V5aae9akuYwbMGIUEkESKSYTjZeyu2IiMW7s,43915
|
|
12
|
-
pycontrails/core/interpolation.py,sha256=
|
|
13
|
-
pycontrails/core/fleet.py,sha256=
|
|
14
|
-
pycontrails/core/flight.py,sha256=
|
|
12
|
+
pycontrails/core/interpolation.py,sha256=TpLDfx-Bx2tGDjWJOyU4n9Dkz6Obl05dB7Ol5diYdsk,24816
|
|
13
|
+
pycontrails/core/fleet.py,sha256=a_vVwAjMbjkhszg7ejP3V0yly_wJ9Va_OQEATG-9UHw,16572
|
|
14
|
+
pycontrails/core/flight.py,sha256=dmqO1PxADMHIcK9U8XSnuXbP59ftQgeKvdI2xGP04ig,81460
|
|
15
15
|
pycontrails/core/fuel.py,sha256=kJZ3P1lPm1L6rdPREM55XQ-VfJ_pt35cP4sO2Nnvmjs,4332
|
|
16
|
-
pycontrails/core/polygon.py,sha256=
|
|
17
|
-
pycontrails/core/cache.py,sha256=
|
|
16
|
+
pycontrails/core/polygon.py,sha256=kXYwj1Xy-mo8GEWXFAO_OJEtZbGx11DE_sZw6iyNvN4,17995
|
|
17
|
+
pycontrails/core/cache.py,sha256=JQIy1sQf0Vil7wlEk9ZIvVacnOD4wM3X8-UkMFjR2wQ,28177
|
|
18
18
|
pycontrails/core/__init__.py,sha256=p0O09HxdeXU0X5Z3zrHMlTfXa92YumT3fJ8wJBI5ido,856
|
|
19
19
|
pycontrails/core/flightplan.py,sha256=0mvA3IO19Sap-7gwpmEIV35_mg6ChvajwhurvjZZt_U,7521
|
|
20
|
-
pycontrails/core/met.py,sha256=
|
|
21
|
-
pycontrails/core/aircraft_performance.py,sha256=
|
|
20
|
+
pycontrails/core/met.py,sha256=JosS0DXGEB4NBQ40WU1b4yG04h3DkT7Vs-P0jK-UkCY,104453
|
|
21
|
+
pycontrails/core/aircraft_performance.py,sha256=CPIgIi5nUuCHiNVLAvZcWECRfakmMd-wUWd3lMA6oGM,28204
|
|
22
22
|
pycontrails/core/airports.py,sha256=CzZrgJNZ7wtNv8vg9sJczMhFov7k0gmrGR4tRKCH8i8,6782
|
|
23
23
|
pycontrails/core/met_var.py,sha256=g69vqbxpJeXEQU8vrrcoUR1PX3zCo2-k3au1Lv2TiIw,12027
|
|
24
|
-
pycontrails/core/rgi_cython.cpython-312-darwin.so,sha256=
|
|
24
|
+
pycontrails/core/rgi_cython.cpython-312-darwin.so,sha256=uXrkb5I98yF39zb0Xy9o_F2AHN7q9Y1K_SxCpjWYT04,340192
|
|
25
25
|
pycontrails/core/coordinates.py,sha256=0ySsHtqTon7GMbuwmmxMbI92j3ueMteJZh4xxNm5zto,5391
|
|
26
26
|
pycontrails/datalib/goes.py,sha256=kZIhx1cKIcNtIxQ3IiuN45aCpwDzzTOxi0Y4fjyaOLs,27481
|
|
27
27
|
pycontrails/datalib/landsat.py,sha256=6ylDkAjnyX7b4ZbHn4bprO8HB8ADPFyMkwWehIs8FLg,20915
|
|
28
28
|
pycontrails/datalib/geo_utils.py,sha256=w6VYhJQeMpBXaBclqANv4Nn0yqPIxlQr6GTUpjArTj0,9070
|
|
29
29
|
pycontrails/datalib/__init__.py,sha256=hW9NWdFPC3y_2vHMteQ7GgQdop3917MkDaf5ZhU2RBY,369
|
|
30
30
|
pycontrails/datalib/sentinel.py,sha256=ed1l1avq8lBvQinY_vNSsWRcpqxUdAPY61AGyPcLawo,23532
|
|
31
|
-
pycontrails/datalib/himawari/himawari.py,sha256=
|
|
31
|
+
pycontrails/datalib/himawari/himawari.py,sha256=uJXhu1URdu3Hen9wMwkgxyPHdjd_xyIt9E7WblVy2xQ,23327
|
|
32
32
|
pycontrails/datalib/himawari/__init__.py,sha256=SWupVbeuyK07IPDCgiNjN6hoLB7hlceabJ3fixhDkl0,619
|
|
33
|
-
pycontrails/datalib/himawari/header_struct.py,sha256=
|
|
34
|
-
pycontrails/datalib/_met_utils/metsource.py,sha256=
|
|
33
|
+
pycontrails/datalib/himawari/header_struct.py,sha256=WbPkNBNUVm8tGKU8wpj4rldY17g5MHQ_OfbWicZSokc,9975
|
|
34
|
+
pycontrails/datalib/_met_utils/metsource.py,sha256=mlKcRko5ZKuYK5uwWn6AAgUSJLMQAYq1nFqskVMGgYo,23999
|
|
35
35
|
pycontrails/datalib/ecmwf/arco_era5.py,sha256=7HXQU5S02PzX9Ew2ZrDKSp0tDEG1eeVAvbP3decmm20,12437
|
|
36
36
|
pycontrails/datalib/ecmwf/era5.py,sha256=4ULNdDlUN0kP6Tbp8D_-Bc12nAsLf0iNfZaDoj_AoZU,18952
|
|
37
37
|
pycontrails/datalib/ecmwf/era5_model_level.py,sha256=AO7ePIGZtavx5nQSPYP4p07RNZeg3bbzmoZC7RUC4Gg,19354
|
|
38
|
-
pycontrails/datalib/ecmwf/hres.py,sha256=
|
|
38
|
+
pycontrails/datalib/ecmwf/hres.py,sha256=tvIXPJjXgijtVdsSyPGtvKf0h5GUczBSsovKEbCgBxg,29624
|
|
39
39
|
pycontrails/datalib/ecmwf/variables.py,sha256=lU3BNe265XVhCXvdMwZqfkWQwtsetZxVRLSfPqHFKAE,9913
|
|
40
40
|
pycontrails/datalib/ecmwf/hres_model_level.py,sha256=CcxMKiFJyLvM9njmBVywAXJxyWE7atsgHXBubKJQqHM,17779
|
|
41
41
|
pycontrails/datalib/ecmwf/__init__.py,sha256=wdfhplEaW2UKTItIoshTtVEjbPyfDYoprTJNxbKZuvA,2021
|
|
42
|
-
pycontrails/datalib/ecmwf/common.py,sha256=
|
|
42
|
+
pycontrails/datalib/ecmwf/common.py,sha256=axOxvdrey9YD34uk0Ocav08MxKvC2uVaiwvyQgFZMEw,3970
|
|
43
43
|
pycontrails/datalib/ecmwf/model_levels.py,sha256=_kgpnogaS6MlfvTX9dB5ASTHFUlZuQ_DRb-VADwEa0k,16996
|
|
44
|
-
pycontrails/datalib/ecmwf/ifs.py,sha256=
|
|
44
|
+
pycontrails/datalib/ecmwf/ifs.py,sha256=_1UarorPp9VlgFZc-NnZy8YnfEqBdp7GV1A-ye6JqS8,10733
|
|
45
45
|
pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv,sha256=PmvGLRzn6uuCKSwiasSuVcehvvmSaqP7cnLuN6hhCQQ,9788
|
|
46
|
-
pycontrails/datalib/gfs/gfs.py,sha256=
|
|
46
|
+
pycontrails/datalib/gfs/gfs.py,sha256=VqS0MRLawgzkBDpjDUYoswXByIy6XUqA9XP7lM1ueBk,22238
|
|
47
47
|
pycontrails/datalib/gfs/variables.py,sha256=4ALR4zhYW8tQVlNVHrd0CK8oRNSe_2OkW3ELeaImtAI,3135
|
|
48
48
|
pycontrails/datalib/gfs/__init__.py,sha256=pXNjb9cJC6ngpuCnoHnmVZ2RHzbHZ0AlsyGvgcdcl2E,684
|
|
49
49
|
pycontrails/datalib/spire/spire.py,sha256=h25BVgSr7E71Ox3-y9WgqFvp-54L08yzb2Ou-iMl7wM,24242
|
|
50
50
|
pycontrails/datalib/spire/__init__.py,sha256=3-My8yQItS6PL0DqXgNaltLqvN6T7nbnNnLD-sy7kt4,186
|
|
51
51
|
pycontrails/datalib/spire/exceptions.py,sha256=U0V_nZTLhxJwrzldvU9PdESx8-zLddRH3FmzkJyFyrI,1714
|
|
52
|
-
pycontrails/datalib/leo_utils/sentinel_metadata.py,sha256=
|
|
52
|
+
pycontrails/datalib/leo_utils/sentinel_metadata.py,sha256=UXpv0XPmtQezVfprcFYNlRpV7nherCDW4oKStBZTdT8,25552
|
|
53
53
|
pycontrails/datalib/leo_utils/landsat_metadata.py,sha256=B455-Yq6HTj0Se0dS4c_2F5ZjcATu2yNK1gyoIlgLMg,10628
|
|
54
54
|
pycontrails/datalib/leo_utils/__init__.py,sha256=-SEAc1f7zEbJHcKjgwLuhnIwte9W-ystFNLvfC4RE94,213
|
|
55
55
|
pycontrails/datalib/leo_utils/vis.py,sha256=-fLcm1D5cP6lThVHovV3MJSiadWyTUAvYDMvr4drMU4,1802
|
|
56
56
|
pycontrails/datalib/leo_utils/search.py,sha256=KbHQ2GARacDuUz3zEJuATSga-R32dQFVTqhZgndHUZI,8686
|
|
57
57
|
pycontrails/datalib/leo_utils/correction.py,sha256=cHf4PhHNYMqdVAFYNiTnjcVyqr1vCBMCKi0IjKB_3pw,9564
|
|
58
58
|
pycontrails/datalib/leo_utils/static/bq_roi_query.sql,sha256=xq6-tJyz0-bUwW0KjQymqygjH3WlQBmyBtP7Ci7SBe8,260
|
|
59
|
-
pycontrails/ext/synthetic_flight.py,sha256=
|
|
59
|
+
pycontrails/ext/synthetic_flight.py,sha256=DdDy1gih8bwdBjsTsvi4mK3lJhcNKlhyllpOWaaASio,16770
|
|
60
60
|
pycontrails/ext/cirium.py,sha256=DFPfRwLDwddpucAPRQhyT4bDGh0VvvoViMUd3pidam8,415
|
|
61
61
|
pycontrails/ext/empirical_grid.py,sha256=FPNQA0x4nVwBXFlbs3DgIapSrXFYhoc8b8IX0M4xhBc,4363
|
|
62
62
|
pycontrails/ext/bada.py,sha256=YlQq4nnFyWza1Am2e2ZucpaICHDuUFRTrtVzIKMzf9s,1091
|
|
63
|
-
pycontrails/utils/iteration.py,sha256=
|
|
63
|
+
pycontrails/utils/iteration.py,sha256=YGcex8pBDegU9dbDJmarxqdPzebAk_Gnc8DK3khY9SY,324
|
|
64
64
|
pycontrails/utils/__init__.py,sha256=Gt_57sBgfliFSxx9sDpuchykFDxmM11Wg9xAeSqPcnI,32
|
|
65
65
|
pycontrails/utils/types.py,sha256=1AaY1x_qGlYAl08xg6PS0MPKm3OZwFBM7xLI_nHK7EY,4869
|
|
66
66
|
pycontrails/utils/temp.py,sha256=lGU0b_R8ze4yKlsOusHIIBaoNFBrmrB3vBjgHRlfcXk,1109
|
|
67
67
|
pycontrails/utils/json.py,sha256=oTiO8xh603esfBGaGVmA5eUzR0NhAqNpQCegMMgnSbg,5896
|
|
68
68
|
pycontrails/utils/dependencies.py,sha256=ATP45xYdUbIyGFzgbOe5SbokMytvB84TcexUEFnEUZE,2559
|
|
69
|
-
pycontrails/models/extended_k15.py,sha256=
|
|
69
|
+
pycontrails/models/extended_k15.py,sha256=ZNL1XDvw-aG24_zGbP6Xkn203oVNqIwMau2exkiADS0,47994
|
|
70
70
|
pycontrails/models/pcc.py,sha256=0Qdl4u8PmUEpNYd398glTChkbTwsh83wYPt0Bmi8qd8,11068
|
|
71
|
-
pycontrails/models/tau_cirrus.py,sha256=
|
|
71
|
+
pycontrails/models/tau_cirrus.py,sha256=wMhh8xQ1byW9WdzRSJIAVDMeyZTBl_PUKMXdF6Zy1uE,5740
|
|
72
72
|
pycontrails/models/__init__.py,sha256=dQTOLQb7RdUdUwslt5se__5y_ymbInBexQmNrmAeOdE,33
|
|
73
73
|
pycontrails/models/issr.py,sha256=_qIKDgO0Owxeb0Q4WJlxcn1FJEvF3QDU-cqh2fpDsBo,7404
|
|
74
|
-
pycontrails/models/sac.py,sha256=
|
|
74
|
+
pycontrails/models/sac.py,sha256=xTPTuCwYf8_goC5xJXxRl0NRZADuNOzyGJh13cuunQM,15490
|
|
75
75
|
pycontrails/models/accf.py,sha256=_tunWpw1sYW8ES8RvpdhNahXwaf4LwdHMEdXhv7-cCI,13566
|
|
76
|
-
pycontrails/models/dry_advection.py,sha256=
|
|
76
|
+
pycontrails/models/dry_advection.py,sha256=CwR37hwQEAWNrFKBrCjUmaaB3D-ToaQrxq2x7Ek5Hc4,20470
|
|
77
77
|
pycontrails/models/pcr.py,sha256=Xde0aF8cMV9jTQ_uI2UvdHSLqotVUgPutb1Wgq7LtfY,5374
|
|
78
78
|
pycontrails/models/emissions/__init__.py,sha256=CZB2zIkLUI3NGNmq2ddvRYjEtiboY6PWJjiEiXj_zII,478
|
|
79
79
|
pycontrails/models/emissions/ffm2.py,sha256=mAvBHnp-p3hIn2fjKGq50eaMHi0jcb5hA5uXbJGeE9I,12068
|
|
@@ -87,36 +87,36 @@ pycontrails/models/apcemm/inputs.py,sha256=88GylkiaymEW_XZeFxLsICI9wV6kl8wVYsuyT
|
|
|
87
87
|
pycontrails/models/apcemm/utils.py,sha256=Ex6EqXin6yoJv2WWhBotSzhjzUlFNZm2MDgL4CvvX6E,17082
|
|
88
88
|
pycontrails/models/apcemm/apcemm.py,sha256=rKvIaEsqtLbZ5h4o4EOY4Ge4-HdPn2X4M1lEUFDvr68,39975
|
|
89
89
|
pycontrails/models/apcemm/static/apcemm_yaml_template.yaml,sha256=uAZkc57OUvDMjgX6F5f6hgDh3Hgg1NbHWRUFSiv0DEI,6745
|
|
90
|
-
pycontrails/models/humidity_scaling/humidity_scaling.py,sha256=
|
|
90
|
+
pycontrails/models/humidity_scaling/humidity_scaling.py,sha256=l5S63mH6K5DOWk8LYtlbOz8wNbJQBcWd-DqCBUxKsik,38595
|
|
91
91
|
pycontrails/models/humidity_scaling/__init__.py,sha256=nqsab_j9BCwMbTfCn4BjXMdhItlvNKkgUJ9-lb8RyIo,1119
|
|
92
92
|
pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq,sha256=tfYhbafF9Z-gGCg6VQ1YBlOaK_01e65Dc6s9b-hQ6Zo,286375
|
|
93
93
|
pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq,sha256=pShCvNUo0NYtAHhT9IBRuj38X9jejdlKfv-ZoOKmtKI,35943
|
|
94
94
|
pycontrails/models/cocip/radiative_forcing.py,sha256=WleEc6hqrAlqJYtL3oZjRW7gJr_pPQNESJdOXi6oKqE,44686
|
|
95
95
|
pycontrails/models/cocip/wind_shear.py,sha256=m6ZlWjORfI-lI-D74Z_dIMOHnK4FDYmkb0S6vSpKTO8,3868
|
|
96
96
|
pycontrails/models/cocip/cocip.py,sha256=PgNuBzvTdkrANCjS_N9GscOkT9WXTaQUkI-IGxmMG9g,104847
|
|
97
|
-
pycontrails/models/cocip/output_formats.py,sha256=
|
|
97
|
+
pycontrails/models/cocip/output_formats.py,sha256=nnEfwBdWRE7InoL9f8YLVtqK3cN4izbKuRMYds_6qOU,83950
|
|
98
98
|
pycontrails/models/cocip/__init__.py,sha256=CWrkNd6S3ZJq04pjTc2W22sVAJeJD3bJJRy_zLW8Kkc,962
|
|
99
99
|
pycontrails/models/cocip/cocip_params.py,sha256=BWmTt6yE4m-LM7lyCtj05FK3wVvU9n7iVnuauGq3jtA,12808
|
|
100
100
|
pycontrails/models/cocip/wake_vortex.py,sha256=F5S8n4eBrBM-7qNcVUtX3IrXD7Kt9pWnrKj6UK-HGeA,14555
|
|
101
|
-
pycontrails/models/cocip/cocip_uncertainty.py,sha256=
|
|
101
|
+
pycontrails/models/cocip/cocip_uncertainty.py,sha256=TZ85xAbDc5zRgQKP7wb3AfHoUIvkfHycuX86dwZCqwM,12257
|
|
102
102
|
pycontrails/models/cocip/radiative_heating.py,sha256=1U4SQWwogtyQ2u6J996kAHP0OfpZ3hH2_x4Cyt3Cy8U,18984
|
|
103
|
-
pycontrails/models/cocip/contrail_properties.py,sha256=
|
|
103
|
+
pycontrails/models/cocip/contrail_properties.py,sha256=BRldMsxNIYlKHg5ozD5_wWtJ7OGTcQvinkQUioHqaqk,55732
|
|
104
104
|
pycontrails/models/cocip/unterstrasser_wake_vortex.py,sha256=bIRS-Z4MRMdkYtth2RaDe5h1ZN0HvCE_Sw96PXQEHKQ,18931
|
|
105
105
|
pycontrails/models/ps_model/__init__.py,sha256=Fuum5Rq8ya8qkvbeq2wh6NDo-42RCRnK1Y-2syYy0Ck,553
|
|
106
106
|
pycontrails/models/ps_model/ps_model.py,sha256=fgFekJpGuAu73KvpfLhlAbIwR7JJGwQpLILWmrONywc,31925
|
|
107
107
|
pycontrails/models/ps_model/ps_aircraft_params.py,sha256=I2nBkdnRo9YGMn-0k35ooYpzPNJkHyEH5cU3K-Cz8b0,13350
|
|
108
108
|
pycontrails/models/ps_model/ps_operational_limits.py,sha256=XwMHO8yu8EZUWtxRgjRKwxmCrmKGoHO7Ob6nlfkrthI,16441
|
|
109
|
-
pycontrails/models/ps_model/ps_grid.py,sha256=
|
|
109
|
+
pycontrails/models/ps_model/ps_grid.py,sha256=IvBkPAJI3bAv8xx4pRZ6x4Sv8Pei1gmp5utTWhY9wgI,26169
|
|
110
110
|
pycontrails/models/ps_model/static/ps-aircraft-params-20250328.csv,sha256=LUYuWozE8fv4ZxuPhQIyVi0Kz4aYGyRjPcH5bSl4oNs,26185
|
|
111
111
|
pycontrails/models/ps_model/static/ps-synonym-list-20250328.csv,sha256=phtrf0m-UYQ7gjoKtIIwINzftTSNd-Bwe9CPen_Gvc8,1048
|
|
112
112
|
pycontrails/models/cocipgrid/cocip_grid_params.py,sha256=l4vBPrOKCJDz5Y1uMjmOGVyUcSWgfZtFWbjW968OPz8,5875
|
|
113
113
|
pycontrails/models/cocipgrid/__init__.py,sha256=ar6bF_8Pusbb-myujz_q5ntFylQTNH8yiM8fxP7Zk30,262
|
|
114
|
-
pycontrails/models/cocipgrid/cocip_grid.py,sha256=
|
|
114
|
+
pycontrails/models/cocipgrid/cocip_grid.py,sha256=4BOmSMQEKxl4DYluq7q8bh1DWKlgNGw0N--0qaguomA,92633
|
|
115
115
|
pycontrails/physics/geo.py,sha256=ITK23l1A2lzjNPTFC8ZKyQH59I5Cy_TvuvM_gbALo94,36297
|
|
116
116
|
pycontrails/physics/units.py,sha256=p-6PzFLpVCMpvmfrhXVh3Hs-nMJw9Y1x-hvgnL9Lo9c,12281
|
|
117
117
|
pycontrails/physics/constants.py,sha256=JHYL2IJY7del2BE_1QfKaEwtIwkbtyHvyxlm_JPHR90,3201
|
|
118
118
|
pycontrails/physics/__init__.py,sha256=_1eWbEy6evEWdfJCEkwDiSdpiDNzNWEPVqaPekHyhwU,44
|
|
119
|
-
pycontrails/physics/thermo.py,sha256=
|
|
119
|
+
pycontrails/physics/thermo.py,sha256=mGVduIY1c1DM6dVAdGcklGIJmscHXo3glDXmdeUtAZk,15376
|
|
120
120
|
pycontrails/physics/jet.py,sha256=Je1d3vgbBEaVIAL1WZ3C-4p2f9fy9dWOjP5vFVsGGh8,30358
|
|
121
121
|
pycontrails/physics/static/iata-cargo-load-factors-20250221.csv,sha256=ixsnQk1DyGxHMo0pDy4aOoQIwgOyrGfhMRPumEwPMBc,3841
|
|
122
122
|
pycontrails/physics/static/iata-passenger-load-factors-20250221.csv,sha256=Q2olRIqUpbOaavvM5ikG8m1v1YQAN3KLNHeFDPvM53Q,3835
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|