pycontrails 0.42.0__cp311-cp311-macosx_11_0_arm64.whl → 0.42.2__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pycontrails might be problematic. Click here for more details.
- pycontrails/_version.py +2 -2
- pycontrails/core/cache.py +4 -6
- pycontrails/core/datalib.py +5 -2
- pycontrails/core/fleet.py +59 -7
- pycontrails/core/flight.py +175 -49
- pycontrails/core/flightplan.py +238 -0
- pycontrails/core/interpolation.py +11 -15
- pycontrails/core/met.py +5 -5
- pycontrails/core/models.py +4 -0
- pycontrails/core/rgi_cython.cpython-311-darwin.so +0 -0
- pycontrails/core/vector.py +17 -12
- pycontrails/datalib/ecmwf/common.py +14 -19
- pycontrails/ext/bada/__init__.py +6 -6
- pycontrails/ext/cirium/__init__.py +2 -2
- pycontrails/models/cocip/cocip.py +37 -39
- pycontrails/models/cocip/cocip_params.py +37 -30
- pycontrails/models/cocip/cocip_uncertainty.py +47 -58
- pycontrails/models/cocip/radiative_forcing.py +220 -193
- pycontrails/models/cocip/wake_vortex.py +96 -91
- pycontrails/models/humidity_scaling.py +265 -8
- pycontrails/models/issr.py +1 -1
- pycontrails/models/quantiles/era5_ensemble_quantiles.npy +0 -0
- pycontrails/models/quantiles/iagos_quantiles.npy +0 -0
- pycontrails/models/sac.py +2 -0
- pycontrails/physics/geo.py +2 -1
- pycontrails/utils/json.py +3 -3
- {pycontrails-0.42.0.dist-info → pycontrails-0.42.2.dist-info}/METADATA +4 -7
- {pycontrails-0.42.0.dist-info → pycontrails-0.42.2.dist-info}/RECORD +32 -29
- {pycontrails-0.42.0.dist-info → pycontrails-0.42.2.dist-info}/LICENSE +0 -0
- {pycontrails-0.42.0.dist-info → pycontrails-0.42.2.dist-info}/NOTICE +0 -0
- {pycontrails-0.42.0.dist-info → pycontrails-0.42.2.dist-info}/WHEEL +0 -0
- {pycontrails-0.42.0.dist-info → pycontrails-0.42.2.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
"""Support for humidity scaling methodologies
|
|
1
|
+
"""Support for humidity scaling methodologies."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import abc
|
|
6
6
|
import dataclasses
|
|
7
|
+
import functools
|
|
8
|
+
import pathlib
|
|
7
9
|
import warnings
|
|
8
10
|
from typing import Any, NoReturn, overload
|
|
9
11
|
|
|
10
12
|
import numpy as np
|
|
13
|
+
import numpy.typing as npt
|
|
11
14
|
import xarray as xr
|
|
12
15
|
from overrides import overrides
|
|
13
16
|
|
|
14
|
-
from pycontrails.core.met import MetDataset
|
|
17
|
+
from pycontrails.core.met import MetDataArray, MetDataset
|
|
15
18
|
from pycontrails.core.models import Model, ModelParams
|
|
16
19
|
from pycontrails.core.vector import GeoVectorDataset
|
|
17
20
|
from pycontrails.physics import constants, thermo, units
|
|
@@ -19,7 +22,7 @@ from pycontrails.utils.types import ArrayLike
|
|
|
19
22
|
|
|
20
23
|
|
|
21
24
|
def _rhi_over_q(air_temperature: ArrayLike, air_pressure: ArrayLike) -> ArrayLike:
|
|
22
|
-
"""Compute the quotient RHi / q
|
|
25
|
+
"""Compute the quotient ``RHi / q``."""
|
|
23
26
|
return air_pressure * (constants.R_v / constants.R_d) / thermo.e_sat_ice(air_temperature)
|
|
24
27
|
|
|
25
28
|
|
|
@@ -140,12 +143,14 @@ class HumidityScaling(Model):
|
|
|
140
143
|
"being applied more than once."
|
|
141
144
|
)
|
|
142
145
|
|
|
146
|
+
p: np.ndarray | xr.DataArray
|
|
143
147
|
if isinstance(self.source, GeoVectorDataset):
|
|
144
|
-
self.source.setdefault("air_pressure", self.source.air_pressure)
|
|
148
|
+
p = self.source.setdefault("air_pressure", self.source.air_pressure)
|
|
149
|
+
else:
|
|
150
|
+
p = self.source.data["air_pressure"]
|
|
145
151
|
|
|
146
152
|
q = self.source.data["specific_humidity"]
|
|
147
153
|
T = self.source.data["air_temperature"]
|
|
148
|
-
p = self.source.data["air_pressure"]
|
|
149
154
|
kwargs = {k: self.get_source_param(k) for k in self.scaler_specific_keys}
|
|
150
155
|
|
|
151
156
|
q, rhi = self.scale(q, T, p, **kwargs)
|
|
@@ -264,7 +269,7 @@ class ExponentialBoostHumidityScaling(HumidityScaling):
|
|
|
264
269
|
rhi /= rhi_adj
|
|
265
270
|
|
|
266
271
|
# Find ISSRs
|
|
267
|
-
is_issr = rhi >= 1
|
|
272
|
+
is_issr = rhi >= 1.0
|
|
268
273
|
|
|
269
274
|
# Apply boosting to ISSRs
|
|
270
275
|
if isinstance(rhi, xr.DataArray):
|
|
@@ -440,7 +445,7 @@ def _calc_rhi_max(air_temperature: ArrayLike) -> ArrayLike:
|
|
|
440
445
|
p_ice = thermo.e_sat_ice(air_temperature)
|
|
441
446
|
p_liq = thermo.e_sat_liquid(air_temperature)
|
|
442
447
|
return xr.where(
|
|
443
|
-
air_temperature < 235,
|
|
448
|
+
air_temperature < 235.0,
|
|
444
449
|
1.67 + (1.45 - 1.67) * (air_temperature - 190.0) / (235.0 - 190.0),
|
|
445
450
|
p_liq / p_ice,
|
|
446
451
|
)
|
|
@@ -553,10 +558,262 @@ class HumidityScalingByLevel(HumidityScaling):
|
|
|
553
558
|
"attribute 'mid_troposphere_threshold'."
|
|
554
559
|
)
|
|
555
560
|
|
|
556
|
-
level = air_pressure / 100
|
|
561
|
+
level = air_pressure / 100.0
|
|
557
562
|
fp = [rhi_adj_stratosphere, rhi_adj_mid_troposphere]
|
|
558
563
|
rhi_adj = np.interp(level, xp=xp, fp=fp)
|
|
559
564
|
|
|
560
565
|
q = specific_humidity / rhi_adj
|
|
561
566
|
rhi = thermo.rhi(q, air_temperature, air_pressure)
|
|
562
567
|
return q, rhi
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
@functools.cache
|
|
571
|
+
def _load_iagos_quantiles() -> npt.NDArray[np.float64]:
|
|
572
|
+
path = pathlib.Path(__file__).parent / "quantiles" / "iagos_quantiles.npy"
|
|
573
|
+
# FIXME: Recompute to avoid the divide by 100.0 here
|
|
574
|
+
return np.load(path, allow_pickle=False) / 100.0
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
@functools.cache
|
|
578
|
+
def _load_era5_ensemble_quantiles() -> npt.NDArray[np.float64]:
|
|
579
|
+
path = pathlib.Path(__file__).parent / "quantiles" / "era5_ensemble_quantiles.npy"
|
|
580
|
+
# FIXME: Recompute to avoid the divide by 100.0 here
|
|
581
|
+
return np.load(path, allow_pickle=False) / 100.0
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def quantile_rhi_map(era5_rhi: npt.NDArray[np.float_], member: int) -> npt.NDArray[np.float64]:
|
|
585
|
+
"""Map ERA5-derived RHi to it's corresponding IAGOS quantile via histogram matching.
|
|
586
|
+
|
|
587
|
+
This matching is performed on a **single** ERA5 ensemble member.
|
|
588
|
+
|
|
589
|
+
Parameters
|
|
590
|
+
----------
|
|
591
|
+
era5_rhi : npt.NDArray[np.float_]
|
|
592
|
+
ERA5-derived RHi values for the given ensemble member.
|
|
593
|
+
member : int
|
|
594
|
+
The ERA5 ensemble member to use. Must be in the range ``[0, 10)``.
|
|
595
|
+
|
|
596
|
+
Returns
|
|
597
|
+
-------
|
|
598
|
+
npt.NDArray[np.float64]
|
|
599
|
+
The IAGOS quantiles corresponding to the ERA5-derived RHi values.
|
|
600
|
+
"""
|
|
601
|
+
|
|
602
|
+
era5_quantiles = _load_era5_ensemble_quantiles() # shape (801, 10)
|
|
603
|
+
era5_quantiles = era5_quantiles[:, member] # shape (801,)
|
|
604
|
+
iagos_quantiles = _load_iagos_quantiles() # shape (801,)
|
|
605
|
+
|
|
606
|
+
return np.interp(era5_rhi, era5_quantiles, iagos_quantiles)
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
def recalibrate_rhi(
|
|
610
|
+
era5_rhi_all_members: npt.NDArray[np.float_], member: int
|
|
611
|
+
) -> npt.NDArray[np.float_]:
|
|
612
|
+
"""Recalibrate ERA5-derived RHi values to IAGOS quantiles.
|
|
613
|
+
|
|
614
|
+
This recalibration requires values for **all** ERA5 ensemble members.
|
|
615
|
+
|
|
616
|
+
Parameters
|
|
617
|
+
----------
|
|
618
|
+
era5_rhi_all_members : npt.NDArray[np.float_]
|
|
619
|
+
ERA5-derived RHi values for all ensemble members. This array should have shape ``(n, 10)``.
|
|
620
|
+
member : int
|
|
621
|
+
The ERA5 ensemble member to use. Must be in the range ``[0, 10)``.
|
|
622
|
+
|
|
623
|
+
Returns
|
|
624
|
+
-------
|
|
625
|
+
npt.NDArray[np.float_]
|
|
626
|
+
The recalibrated RHi values. This is an array of shape ``(n,)``.
|
|
627
|
+
|
|
628
|
+
References
|
|
629
|
+
----------
|
|
630
|
+
:cite:`eckelCalibratedProbabilisticQuantitative1998`
|
|
631
|
+
"""
|
|
632
|
+
|
|
633
|
+
n_members = 10
|
|
634
|
+
assert era5_rhi_all_members.shape[1] == n_members
|
|
635
|
+
|
|
636
|
+
# Perform histogram matching on the given ensemble member
|
|
637
|
+
recalibrated_rhi = quantile_rhi_map(era5_rhi_all_members[:, member], member)
|
|
638
|
+
|
|
639
|
+
# Perform histogram matching on all other ensemble members
|
|
640
|
+
# Add up the results into a single 'ensemble_mean_rhi' array
|
|
641
|
+
ensemble_mean_rhi: npt.NDArray[np.float_] = 0.0 # type: ignore[assignment]
|
|
642
|
+
for r in range(n_members):
|
|
643
|
+
if r == member:
|
|
644
|
+
ensemble_mean_rhi += recalibrated_rhi
|
|
645
|
+
else:
|
|
646
|
+
ensemble_mean_rhi += quantile_rhi_map(era5_rhi_all_members[:, r], r)
|
|
647
|
+
|
|
648
|
+
# Divide by the number of ensemble members to get the mean
|
|
649
|
+
ensemble_mean_rhi /= n_members
|
|
650
|
+
|
|
651
|
+
eckel_a = -0.005213832567192828
|
|
652
|
+
eckel_c = 2.7859172756970354
|
|
653
|
+
|
|
654
|
+
out = (ensemble_mean_rhi - eckel_a) + eckel_c * (recalibrated_rhi - ensemble_mean_rhi)
|
|
655
|
+
return out.astype(era5_rhi_all_members.dtype)
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
@dataclasses.dataclass
|
|
659
|
+
class HistogramMatchingWithEckelParams(ModelParams):
|
|
660
|
+
"""Parameters for :class:`HistogramMatchingWithEckel`.
|
|
661
|
+
|
|
662
|
+
.. warning::
|
|
663
|
+
Experimental. This may change or be removed in a future release.
|
|
664
|
+
"""
|
|
665
|
+
|
|
666
|
+
#: A length-10 list of ERA5 ensemble members.
|
|
667
|
+
#: Each element is a :class:`MetDataArray` holding specific humidity
|
|
668
|
+
#: values for a single ensemble member. If None, a ValueError will be
|
|
669
|
+
#: raised at model instantiation time. The order of the list must be
|
|
670
|
+
#: consistent with the order of the ERA5 ensemble members.
|
|
671
|
+
ensemble_specific_humidity: list[MetDataArray] | None = None
|
|
672
|
+
|
|
673
|
+
#: The specific member used. Must be in the range [0, 10). If None,
|
|
674
|
+
#: a ValueError will be raised at model instantiation time.
|
|
675
|
+
member: int | None = None
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
class HistogramMatchingWithEckel(HumidityScaling):
|
|
679
|
+
"""Scale humidity by histogram matching to IAGOS RHi quantiles.
|
|
680
|
+
|
|
681
|
+
This method also applies the Eckel scaling to the recalibrated RHi values.
|
|
682
|
+
|
|
683
|
+
Unlike other specific humidity scaling methods, this method requires met data
|
|
684
|
+
and performs interpolation at evaluation time.
|
|
685
|
+
|
|
686
|
+
.. warning::
|
|
687
|
+
Experimental. This may change or be removed in a future release.
|
|
688
|
+
|
|
689
|
+
References
|
|
690
|
+
----------
|
|
691
|
+
:cite:`eckelCalibratedProbabilisticQuantitative1998`
|
|
692
|
+
"""
|
|
693
|
+
|
|
694
|
+
name = "histogram_matching_with_eckel"
|
|
695
|
+
long_name = "IAGOS RHi histogram matching with Eckel scaling"
|
|
696
|
+
formula = "era5_quantiles -> iagos_quantiles -> recalibrated_rhi"
|
|
697
|
+
default_params = HistogramMatchingWithEckelParams
|
|
698
|
+
|
|
699
|
+
n_members = 10 # hard-coded elsewhere
|
|
700
|
+
|
|
701
|
+
def __init__(
|
|
702
|
+
self,
|
|
703
|
+
met: MetDataset | None = None,
|
|
704
|
+
params: dict[str, Any] | None = None,
|
|
705
|
+
**params_kwargs: Any,
|
|
706
|
+
) -> None:
|
|
707
|
+
super().__init__(met, params, **params_kwargs)
|
|
708
|
+
|
|
709
|
+
# Some very crude validation
|
|
710
|
+
member = self.params["member"]
|
|
711
|
+
assert member in range(self.n_members)
|
|
712
|
+
self.member: int = member
|
|
713
|
+
|
|
714
|
+
ensemble_specific_humidity = self.params["ensemble_specific_humidity"]
|
|
715
|
+
assert len(ensemble_specific_humidity) == self.n_members
|
|
716
|
+
for member, mda in enumerate(ensemble_specific_humidity):
|
|
717
|
+
try:
|
|
718
|
+
assert mda.data["number"] == member
|
|
719
|
+
except KeyError:
|
|
720
|
+
pass
|
|
721
|
+
|
|
722
|
+
self.ensemble_specific_humidity: list[MetDataArray] = ensemble_specific_humidity
|
|
723
|
+
|
|
724
|
+
@overload
|
|
725
|
+
def eval(self, source: GeoVectorDataset, **params: Any) -> GeoVectorDataset:
|
|
726
|
+
...
|
|
727
|
+
|
|
728
|
+
@overload
|
|
729
|
+
def eval(self, source: MetDataset, **params: Any) -> NoReturn:
|
|
730
|
+
...
|
|
731
|
+
|
|
732
|
+
@overload
|
|
733
|
+
def eval(self, source: None = ..., **params: Any) -> NoReturn:
|
|
734
|
+
...
|
|
735
|
+
|
|
736
|
+
def eval(
|
|
737
|
+
self, source: GeoVectorDataset | MetDataset | None = None, **params: Any
|
|
738
|
+
) -> GeoVectorDataset | MetDataset:
|
|
739
|
+
"""Scale specific humidity by histogram matching to IAGOS RHi quantiles.
|
|
740
|
+
|
|
741
|
+
This method assumes ``source`` is equipped with the following variables:
|
|
742
|
+
|
|
743
|
+
- air_temperature
|
|
744
|
+
- specific_humidity: Humidity values for the :attr:`member` ERA5 ensemble member.
|
|
745
|
+
"""
|
|
746
|
+
|
|
747
|
+
self.update_params(params)
|
|
748
|
+
self.set_source(source)
|
|
749
|
+
self.source = self.require_source_type(GeoVectorDataset)
|
|
750
|
+
|
|
751
|
+
if "rhi" in self.source:
|
|
752
|
+
warnings.warn(
|
|
753
|
+
"Variable 'rhi' already found on source to be scaled. This "
|
|
754
|
+
"is unexpected and may be the result of humidity scaling "
|
|
755
|
+
"being applied more than once."
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
# Create a 2D array of specific humidity values for all ensemble members
|
|
759
|
+
# The specific humidity values for the current member are taken from the source
|
|
760
|
+
# This matches patterns used in other humidity scaling methods
|
|
761
|
+
# The remaining values are interpolated from the ERA5 ensemble members
|
|
762
|
+
q = self.source.data["specific_humidity"]
|
|
763
|
+
q2d = np.empty((len(self.source), self.n_members), dtype=q.dtype)
|
|
764
|
+
|
|
765
|
+
for member, mda in enumerate(self.ensemble_specific_humidity):
|
|
766
|
+
if member == self.member:
|
|
767
|
+
q2d[:, member] = q
|
|
768
|
+
else:
|
|
769
|
+
q2d[:, member] = self.source.intersect_met(mda, **self.interp_kwargs)
|
|
770
|
+
|
|
771
|
+
p = self.source.setdefault("air_pressure", self.source.air_pressure)
|
|
772
|
+
T = self.source.data["air_temperature"]
|
|
773
|
+
|
|
774
|
+
q, rhi = self.scale(q2d, T, p)
|
|
775
|
+
self.source.update(specific_humidity=q, rhi=rhi)
|
|
776
|
+
|
|
777
|
+
return self.source
|
|
778
|
+
|
|
779
|
+
@overrides
|
|
780
|
+
def scale( # type: ignore[override]
|
|
781
|
+
self,
|
|
782
|
+
specific_humidity: npt.NDArray[np.float_],
|
|
783
|
+
air_temperature: npt.NDArray[np.float_],
|
|
784
|
+
air_pressure: npt.NDArray[np.float_],
|
|
785
|
+
**kwargs: Any,
|
|
786
|
+
) -> tuple[npt.NDArray[np.float_], npt.NDArray[np.float_]]:
|
|
787
|
+
"""Scale specific humidity values via histogram matching and Eckel scaling.
|
|
788
|
+
|
|
789
|
+
Unlike the method on the base class, the method assumes each of the input
|
|
790
|
+
arrays are :class:`np.ndarray` and not :class:`xr.DataArray` objects.
|
|
791
|
+
|
|
792
|
+
Parameters
|
|
793
|
+
----------
|
|
794
|
+
specific_humidity : npt.NDArray[np.float_]
|
|
795
|
+
A 2D array of specific humidity values for all ERA5 ensemble members.
|
|
796
|
+
The shape of this array must be ``(n, 10)``, where ``n`` is the number
|
|
797
|
+
of observations and ``10`` is the number of ERA5 ensemble members.
|
|
798
|
+
air_temperature : npt.NDArray[np.float_]
|
|
799
|
+
A 1D array of air temperature values with shape ``(n,)``.
|
|
800
|
+
air_pressure : npt.NDArray[np.float_]
|
|
801
|
+
A 1D array of air pressure values with shape ``(n,)``.
|
|
802
|
+
kwargs: Any
|
|
803
|
+
Unused, kept for compatibility with the base class.
|
|
804
|
+
|
|
805
|
+
Returns
|
|
806
|
+
-------
|
|
807
|
+
specific_humidity : npt.NDArray[np.float_]
|
|
808
|
+
The recalibrated specific humidity values. A 1D array with shape ``(n,)``.
|
|
809
|
+
rhi : npt.NDArray[np.float_]
|
|
810
|
+
The recalibrated RHi values. A 1D array with shape ``(n,)``.
|
|
811
|
+
"""
|
|
812
|
+
|
|
813
|
+
rhi_over_q = _rhi_over_q(air_temperature, air_pressure)
|
|
814
|
+
rhi = rhi_over_q[:, np.newaxis] * specific_humidity
|
|
815
|
+
|
|
816
|
+
recalibrated_rhi = recalibrate_rhi(rhi, self.member)
|
|
817
|
+
recalibrated_q = recalibrated_rhi / rhi_over_q
|
|
818
|
+
|
|
819
|
+
return recalibrated_q, recalibrated_rhi
|
pycontrails/models/issr.py
CHANGED
|
@@ -51,7 +51,7 @@ class ISSR(Model):
|
|
|
51
51
|
>>> variables = ["air_temperature", "specific_humidity"]
|
|
52
52
|
>>> pressure_levels = [200, 250, 300]
|
|
53
53
|
>>> era5 = ERA5(time, variables, pressure_levels)
|
|
54
|
-
>>> met = era5.open_metdataset(
|
|
54
|
+
>>> met = era5.open_metdataset()
|
|
55
55
|
|
|
56
56
|
>>> # Instantiate and run model
|
|
57
57
|
>>> scaling = ConstantHumidityScaling(rhi_adj=0.98)
|
|
Binary file
|
|
Binary file
|
pycontrails/models/sac.py
CHANGED
|
@@ -438,6 +438,8 @@ def T_critical_sac(
|
|
|
438
438
|
# We only apply Newton's method at points with rh bounded below 1 (scipy will
|
|
439
439
|
# raise an error if Newton's method is not converging well).
|
|
440
440
|
filt = relative_humidity < 0.999
|
|
441
|
+
if not np.any(filt):
|
|
442
|
+
return T_LM
|
|
441
443
|
|
|
442
444
|
U_filt = relative_humidity[filt]
|
|
443
445
|
T_LM_filt = T_LM[filt]
|
pycontrails/physics/geo.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
|
+
import numpy.typing as npt
|
|
6
7
|
import xarray as xr
|
|
7
8
|
|
|
8
9
|
from pycontrails.physics import constants, units
|
|
@@ -834,7 +835,7 @@ def advect_level(
|
|
|
834
835
|
return (level * 100.0 + (dt_s * velocity)) / 100.0
|
|
835
836
|
|
|
836
837
|
|
|
837
|
-
def _dt_to_float_seconds(dt: np.ndarray | np.timedelta64, dtype:
|
|
838
|
+
def _dt_to_float_seconds(dt: np.ndarray | np.timedelta64, dtype: npt.DTypeLike) -> np.ndarray:
|
|
838
839
|
"""Convert a time delta to seconds as a float with specified ``dtype`` precision.
|
|
839
840
|
|
|
840
841
|
Parameters
|
pycontrails/utils/json.py
CHANGED
|
@@ -161,9 +161,9 @@ def dataframe_to_geojson_points(
|
|
|
161
161
|
|
|
162
162
|
def row_to_feature(row: pd.Series) -> dict[str, str | dict[str, Any]]:
|
|
163
163
|
point = [
|
|
164
|
-
np.
|
|
165
|
-
np.
|
|
166
|
-
np.
|
|
164
|
+
np.round(row.longitude, decimals=4) if not np.isnan(row.longitude) else None,
|
|
165
|
+
np.round(row.latitude, decimals=4) if not np.isnan(row.latitude) else None,
|
|
166
|
+
np.round(row.altitude, decimals=4) if not np.isnan(row.altitude) else None,
|
|
167
167
|
]
|
|
168
168
|
# converting to int to allow JSON serialization
|
|
169
169
|
properties = {"time": int(row.time.timestamp())}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pycontrails
|
|
3
|
-
Version: 0.42.
|
|
3
|
+
Version: 0.42.2
|
|
4
4
|
Summary: Python library for modeling aviation climate impacts
|
|
5
5
|
Author-email: Breakthrough Energy <py@contrails.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -34,12 +34,7 @@ Requires-Dist: pyproj (>=3.5)
|
|
|
34
34
|
Requires-Dist: scipy (>=1.10)
|
|
35
35
|
Requires-Dist: xarray (>=2022.3)
|
|
36
36
|
Provides-Extra: complete
|
|
37
|
-
Requires-Dist: pycontrails[ecmwf] ; extra == 'complete'
|
|
38
|
-
Requires-Dist: pycontrails[gcp] ; extra == 'complete'
|
|
39
|
-
Requires-Dist: pycontrails[gfs] ; extra == 'complete'
|
|
40
|
-
Requires-Dist: pycontrails[jupyter] ; extra == 'complete'
|
|
41
|
-
Requires-Dist: pycontrails[vis] ; extra == 'complete'
|
|
42
|
-
Requires-Dist: pycontrails[zarr] ; extra == 'complete'
|
|
37
|
+
Requires-Dist: pycontrails[ecmwf,gcp,gfs,jupyter,pwlf,vis,zarr] ; extra == 'complete'
|
|
43
38
|
Provides-Extra: dev
|
|
44
39
|
Requires-Dist: black (>=22) ; extra == 'dev'
|
|
45
40
|
Requires-Dist: black[jupyter] ; extra == 'dev'
|
|
@@ -96,6 +91,8 @@ Requires-Dist: ipywidgets (>=7.6) ; extra == 'jupyter'
|
|
|
96
91
|
Requires-Dist: jupyterlab (>=2.2) ; extra == 'jupyter'
|
|
97
92
|
Provides-Extra: open3d
|
|
98
93
|
Requires-Dist: open3d (>=0.14) ; extra == 'open3d'
|
|
94
|
+
Provides-Extra: pwlf
|
|
95
|
+
Requires-Dist: pwlf (>=2.2.1) ; extra == 'pwlf'
|
|
99
96
|
Provides-Extra: vis
|
|
100
97
|
Requires-Dist: matplotlib (>=3.3) ; extra == 'vis'
|
|
101
98
|
Requires-Dist: opencv-python-headless (>=4.5) ; extra == 'vis'
|
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
pycontrails-0.42.
|
|
2
|
-
pycontrails-0.42.
|
|
3
|
-
pycontrails-0.42.
|
|
4
|
-
pycontrails-0.42.
|
|
5
|
-
pycontrails-0.42.
|
|
6
|
-
pycontrails-0.42.
|
|
7
|
-
pycontrails/_version.py,sha256=
|
|
1
|
+
pycontrails-0.42.2.dist-info/RECORD,,
|
|
2
|
+
pycontrails-0.42.2.dist-info/LICENSE,sha256=gJ-h7SFFD1mCfR6a7HILvEtodDT6Iig8bLXdgqR6ucA,10175
|
|
3
|
+
pycontrails-0.42.2.dist-info/WHEEL,sha256=GYWT1Q_60SI2bAUaGrkLwkEA5yYDmphib6XcY6K30ZQ,110
|
|
4
|
+
pycontrails-0.42.2.dist-info/NOTICE,sha256=gKI8DcN1WhiXB2SFRKDogcjONldGubTvBxiOYdC4CXU,1926
|
|
5
|
+
pycontrails-0.42.2.dist-info/top_level.txt,sha256=Z8J1R_AiBAyCVjNw6jYLdrA68PrQqTg0t3_Yek_IZ0Q,29
|
|
6
|
+
pycontrails-0.42.2.dist-info/METADATA,sha256=Eyt-RbhPHpnumnU-YHOXVzYv6GFaHe5NXkzbjdo9hd4,8178
|
|
7
|
+
pycontrails/_version.py,sha256=JQ-ensPiphsIDBK4lnzSeMWxygjAp19P9cOtQQsBrjI,162
|
|
8
8
|
pycontrails/__init__.py,sha256=sf7Xhr91V2jAvcQkla9oPqNCaXSKQp2M_dcxkiVkl6w,1943
|
|
9
9
|
pycontrails/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
pycontrails/core/rgi_cython.cpython-311-darwin.so,sha256=
|
|
11
|
-
pycontrails/core/vector.py,sha256=
|
|
12
|
-
pycontrails/core/models.py,sha256
|
|
13
|
-
pycontrails/core/interpolation.py,sha256=
|
|
14
|
-
pycontrails/core/fleet.py,sha256=
|
|
15
|
-
pycontrails/core/flight.py,sha256=
|
|
10
|
+
pycontrails/core/rgi_cython.cpython-311-darwin.so,sha256=uWNsaY22_-09tZ4fCijYCyAAfbcwYFp7cY_KfvcCm6g,261341
|
|
11
|
+
pycontrails/core/vector.py,sha256=JF-K_6ieGh5TG0TrqF-jexH5diusfluYW1lzzzSapV8,58504
|
|
12
|
+
pycontrails/core/models.py,sha256=-_W0nbAlfeYQfiHnzAIyHB-Wi8957B_s4T8q-gmGmwQ,26969
|
|
13
|
+
pycontrails/core/interpolation.py,sha256=J-drgXpacQG_z7pOOpIIfWBW3TSkK09pEUL7HV8qfOk,23713
|
|
14
|
+
pycontrails/core/fleet.py,sha256=dkDHEvzqB0T1_zxGUQhkdZaER4SR8H1wnTryWRkc42Q,14419
|
|
15
|
+
pycontrails/core/flight.py,sha256=VIIvRtdPPqJxP170ZGcBnHngvBwhphdnvyRP3DXAx7g,61998
|
|
16
16
|
pycontrails/core/fuel.py,sha256=lEMUgLeFBoazDsiKN07s9udQ12xghOos5v3H9bjveBs,4044
|
|
17
17
|
pycontrails/core/polygon.py,sha256=FlFHJvonnxajq6iY12cuqW-MP8wGGeb3aiNJh-hks3g,16636
|
|
18
|
-
pycontrails/core/datalib.py,sha256=
|
|
19
|
-
pycontrails/core/cache.py,sha256=
|
|
18
|
+
pycontrails/core/datalib.py,sha256=bI1PRTYdYYEQAp0d6MEm7HXq0n7Xgpwa_MESsbux2RY,21613
|
|
19
|
+
pycontrails/core/cache.py,sha256=0JyO0N5gddWoeo3UeOVUHtCkXoPVhIJ-RBLk_eFgYqs,28430
|
|
20
20
|
pycontrails/core/__init__.py,sha256=C6bOLNBKeQaLCHCRza1oPrQTUazutPST7hX4C6O2MG0,866
|
|
21
|
-
pycontrails/core/
|
|
21
|
+
pycontrails/core/flightplan.py,sha256=Vq__4eDPo6hTwXMgiCj7boV4P9gTjNtst5n0sy6j4UI,7636
|
|
22
|
+
pycontrails/core/met.py,sha256=zW9HFpaaS3pXUFZxWboTo_cV6RPPMrz_j5DLiPcnkzs,86676
|
|
22
23
|
pycontrails/core/airports.py,sha256=5D0VF9DxleQlVOmMW-P8_fVVkob-aB3doO1Co2XNFss,6766
|
|
23
24
|
pycontrails/core/met_var.py,sha256=-gaodcmxx507ryMVKvFclqKkf1c8OHVVtXeG9s2eOOs,9191
|
|
24
25
|
pycontrails/core/coordinates.py,sha256=b7D2lknnnwh8rBSla9M3ojqRYiASAOrVv0OAFD8xpDw,5078
|
|
@@ -27,27 +28,27 @@ pycontrails/datalib/ecmwf/era5.py,sha256=ulII_wQDSLmaqpMdZpAlOCmCCxhpzfSdBBgb8NW
|
|
|
27
28
|
pycontrails/datalib/ecmwf/hres.py,sha256=wnGSZ67fnJ7NOw4hZXk3UCNcfFvShK1pWMm4nx0fz6c,30333
|
|
28
29
|
pycontrails/datalib/ecmwf/variables.py,sha256=akqjUS3WKnSzV1Y0KkHLylH7QByvitc3wo8NBFeSNew,8714
|
|
29
30
|
pycontrails/datalib/ecmwf/__init__.py,sha256=9rrlhfePtMrkofmFMg7t9fJ3teVufRJ0uM3Y-2PdzQ4,1045
|
|
30
|
-
pycontrails/datalib/ecmwf/common.py,sha256=
|
|
31
|
+
pycontrails/datalib/ecmwf/common.py,sha256=tqoKnYOH3B4OzdEe6ZzoyjFO03GaT9QVJqe3sBPYyWQ,4667
|
|
31
32
|
pycontrails/datalib/ecmwf/ifs.py,sha256=2Atnpc4q6Yy9LjEyE4tYzmnlC0bnnbzUiZvj7XUh0Bs,10448
|
|
32
33
|
pycontrails/datalib/gfs/gfs.py,sha256=-3_Qd1fKRU2LYCBK8mDvc9FycL2lYTEzJfXeAXpP73M,23084
|
|
33
34
|
pycontrails/datalib/gfs/variables.py,sha256=s6rKyFdDA8E0Jz8X4twM7mgq5zhRGlk5qTedItyqoY8,2860
|
|
34
35
|
pycontrails/datalib/gfs/__init__.py,sha256=tWxgqmlW8Uo07J-3fBTXPrteatzTka9mSXomhWy3NVA,684
|
|
35
36
|
pycontrails/datalib/spire/spire.py,sha256=l52ID6LdYWpWcxxVbupCBono06MvPfwIBOGI9AcxpHQ,25351
|
|
36
37
|
pycontrails/datalib/spire/__init__.py,sha256=4EZPJUmNnF8v2n6QhBvSi_3rYXRBX2zGcPE-WEA-dP8,343
|
|
37
|
-
pycontrails/ext/cirium/__init__.py,sha256=
|
|
38
|
-
pycontrails/ext/bada/__init__.py,sha256=
|
|
38
|
+
pycontrails/ext/cirium/__init__.py,sha256=erApEeJGry3Nbk5yh6YDvwDXmwgtr-Mmav2BuvC9dDU,411
|
|
39
|
+
pycontrails/ext/bada/__init__.py,sha256=n7BZKOxtAew9CaGOICDfO4mzhP_ndURtoGK_WyTbpfg,1059
|
|
39
40
|
pycontrails/utils/iteration.py,sha256=UjMn2FRDyC0A7q_MqKNpqqeNZm-lA23Ws-KV7zFzAl4,292
|
|
40
41
|
pycontrails/utils/synthetic_flight.py,sha256=y05WJE4Z_SuDlU3q5wodiLImyub_dd4MxYqGZb9XOno,16596
|
|
41
42
|
pycontrails/utils/__init__.py,sha256=Gt_57sBgfliFSxx9sDpuchykFDxmM11Wg9xAeSqPcnI,32
|
|
42
43
|
pycontrails/utils/types.py,sha256=0uH2eVmQJZiL76N0v_UtHDyv3FJHeRd7BxEZ_occ0n4,4525
|
|
43
44
|
pycontrails/utils/temp.py,sha256=6BlJ5NaQpACyL-n3FuqfscFb9Mfbgvs72BwWfSzBfmU,1100
|
|
44
|
-
pycontrails/utils/json.py,sha256=
|
|
45
|
-
pycontrails/models/humidity_scaling.py,sha256=
|
|
45
|
+
pycontrails/utils/json.py,sha256=zB_23_mqE39G231sQ_XXmxpQQ9pGjIGQCPJ2JaknRrY,5990
|
|
46
|
+
pycontrails/models/humidity_scaling.py,sha256=AkJGD_hNRxsu9na_PPAhgy6ShUE-FlYQvmMKOuFSdPo,29416
|
|
46
47
|
pycontrails/models/pcc.py,sha256=yWi0TochaCWCgrb68dUad9xPMqysIRa2hr6VT8PvxL4,11286
|
|
47
48
|
pycontrails/models/tau_cirrus.py,sha256=jYilgsGQw7aFLjIJaG8zvbu8ITNGlXZvbl18C8vHbE4,4491
|
|
48
49
|
pycontrails/models/__init__.py,sha256=dQTOLQb7RdUdUwslt5se__5y_ymbInBexQmNrmAeOdE,33
|
|
49
|
-
pycontrails/models/issr.py,sha256=
|
|
50
|
-
pycontrails/models/sac.py,sha256=
|
|
50
|
+
pycontrails/models/issr.py,sha256=a1mT_dGPliGHIDYxOtTHw3svb8KW19pHFP1wRuyiYS8,7547
|
|
51
|
+
pycontrails/models/sac.py,sha256=FNM8_LmHl7NPHFHw1R6_r3Mr-dcwELppt969OOvjth4,16150
|
|
51
52
|
pycontrails/models/accf.py,sha256=WRFGNrkt2hLgO-mIsgk3JXk9_R7Hbw0jCPUC6iGpcCg,12368
|
|
52
53
|
pycontrails/models/aircraft_performance.py,sha256=r-SdOw6Aor9JXIz4mVKe7HTrG4lKCXpAraUY2KTZhiE,1722
|
|
53
54
|
pycontrails/models/pcr.py,sha256=m9cLtZr2DK4omtljgWdIVzDpQAeb3hDEDVVfr6zMDtM,5900
|
|
@@ -57,23 +58,25 @@ pycontrails/models/emissions/emissions.py,sha256=VW7ZPWmeWfmIsEgcQ88-A08YlmdBTpK
|
|
|
57
58
|
pycontrails/models/emissions/black_carbon.py,sha256=EDU5yMTuPeWQIeUE3YDkZ6HHFii8ngfi67Svt3AOVH4,20122
|
|
58
59
|
pycontrails/models/emissions/static/edb-gaseous-v28c-engines.csv,sha256=9mok7P9NQSNJnej_gna29pTbgBuZsfI9N5OOoj1S4WI,118901
|
|
59
60
|
pycontrails/models/emissions/static/edb-nvpm-v28c-engines.csv,sha256=otZ3PWXcbu7ZuEgZ3v3bLB0CGjGRAacd69CGFUXAdSU,63472
|
|
60
|
-
pycontrails/models/cocip/radiative_forcing.py,sha256=
|
|
61
|
+
pycontrails/models/cocip/radiative_forcing.py,sha256=WfsPtCfUhK7MNTG734dDpDbsOL-BVVNKzeZ4UoUNxyQ,30055
|
|
61
62
|
pycontrails/models/cocip/wind_shear.py,sha256=p4QVwqcpqCP4Pf8rAHPhU_rPM6LlmuWy_fSpOwdIi5w,3727
|
|
62
|
-
pycontrails/models/cocip/cocip.py,sha256=
|
|
63
|
+
pycontrails/models/cocip/cocip.py,sha256=yqVVvqFCeRQoBM2nZlikowEmwebrLiF3qrqu6EPW7S8,86666
|
|
63
64
|
pycontrails/models/cocip/__init__.py,sha256=vBicDVNyw-M3bglx1iVplxm6CQRPRk5SS-3_VgL7WQM,370
|
|
64
|
-
pycontrails/models/cocip/cocip_params.py,sha256=
|
|
65
|
-
pycontrails/models/cocip/wake_vortex.py,sha256=
|
|
66
|
-
pycontrails/models/cocip/cocip_uncertainty.py,sha256=
|
|
65
|
+
pycontrails/models/cocip/cocip_params.py,sha256=MQr3I_On4m1MVB_lJbm7FREaOUGRyMNqIog4qKKZcB8,9213
|
|
66
|
+
pycontrails/models/cocip/wake_vortex.py,sha256=DV9Qvjp-nlZjBJK6TFkls8nd7aALlXQZeMpxolUSaHQ,12814
|
|
67
|
+
pycontrails/models/cocip/cocip_uncertainty.py,sha256=wJ43NJr3YZX92GiMhY6LUVni9qbsqKg0duCRSS_r_mw,11782
|
|
67
68
|
pycontrails/models/cocip/radiative_heating.py,sha256=HTvAXv4kU_HIasLUFCF15K-sRzJVK8UAulj2W_gNjKE,18770
|
|
68
69
|
pycontrails/models/cocip/contrail_properties.py,sha256=aoFg19_L2Fd7-Uv3SSMJ5i2rV3xl17XMSZMOekt2tkA,55613
|
|
69
70
|
pycontrails/models/cocip/output/flight_summary.py,sha256=vjm6UwKJT0PoIBj0zLj1_1Q8ZokAZT-GO4T3tB3Jw1I,8838
|
|
70
71
|
pycontrails/models/cocip/output/__init__.py,sha256=-PzsG-acxd6jXOdBjK4kxuYiQ_9Llf5C6JqgZ8mse6U,62
|
|
71
72
|
pycontrails/models/cocip/output/grid_cirrus.py,sha256=_2MdTTahsOK3M14ONOZAN58XS2j90xtt1MAaclLbEhc,25194
|
|
73
|
+
pycontrails/models/quantiles/iagos_quantiles.npy,sha256=mdpQBBsCVUnv8B66xbIOqcNff9bO66wqkNV7V92zD2E,6536
|
|
74
|
+
pycontrails/models/quantiles/era5_ensemble_quantiles.npy,sha256=78NME7RD7-HIy8xZgXc2cyDnfffbzm6eVN7Tau-amZA,64208
|
|
72
75
|
pycontrails/models/cocipgrid/cocip_grid_params.py,sha256=fe7w2bw-wQ-PG8ua5K7nBb19lSMfAoVuaHCVKUsKQCk,5323
|
|
73
76
|
pycontrails/models/cocipgrid/__init__.py,sha256=ar6bF_8Pusbb-myujz_q5ntFylQTNH8yiM8fxP7Zk30,262
|
|
74
77
|
pycontrails/models/cocipgrid/cocip_time_handling.py,sha256=kXO8ePbmjlqZgdV6FMxqA7IAWXUQtVQDRU8RJ12ClWU,13826
|
|
75
78
|
pycontrails/models/cocipgrid/cocip_grid.py,sha256=RCtYk1I49qNgALzLaNlI6EoJaAX4JMmXr_pDYUYJhy4,84548
|
|
76
|
-
pycontrails/physics/geo.py,sha256
|
|
79
|
+
pycontrails/physics/geo.py,sha256=qQMu4R63I_lyK3p6uztuzCViPK_ja0wHzxAU-3VHdZk,25153
|
|
77
80
|
pycontrails/physics/units.py,sha256=MV2C3qDV7Qf9Bk-ri_crqNSY-qSZj8MPdelNNu--crM,11349
|
|
78
81
|
pycontrails/physics/constants.py,sha256=GJ_M9W7N78osXopNIfRDcHuqcaINLLAhOpOHQBsaI3I,2955
|
|
79
82
|
pycontrails/physics/__init__.py,sha256=_1eWbEy6evEWdfJCEkwDiSdpiDNzNWEPVqaPekHyhwU,44
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|