pycontrails 0.52.2__cp312-cp312-win_amd64.whl → 0.52.3__cp312-cp312-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/_version.py +2 -2
- pycontrails/core/interpolation.py +2 -1
- pycontrails/core/met.py +179 -2
- pycontrails/core/rgi_cython.cp312-win_amd64.pyd +0 -0
- pycontrails/models/cocip/cocip.py +96 -22
- pycontrails/models/cocip/cocip_params.py +21 -0
- pycontrails/models/cocip/output_formats.py +11 -2
- {pycontrails-0.52.2.dist-info → pycontrails-0.52.3.dist-info}/METADATA +75 -75
- {pycontrails-0.52.2.dist-info → pycontrails-0.52.3.dist-info}/RECORD +13 -13
- {pycontrails-0.52.2.dist-info → pycontrails-0.52.3.dist-info}/LICENSE +0 -0
- {pycontrails-0.52.2.dist-info → pycontrails-0.52.3.dist-info}/NOTICE +0 -0
- {pycontrails-0.52.2.dist-info → pycontrails-0.52.3.dist-info}/WHEEL +0 -0
- {pycontrails-0.52.2.dist-info → pycontrails-0.52.3.dist-info}/top_level.txt +0 -0
pycontrails/_version.py
CHANGED
|
@@ -215,7 +215,8 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
|
|
|
215
215
|
|
|
216
216
|
if ndim == 1:
|
|
217
217
|
# np.interp could be better ... although that may also promote the dtype
|
|
218
|
-
|
|
218
|
+
# 1-d view is required for evaluate_linear_1d
|
|
219
|
+
return rgi_cython.evaluate_linear_1d(values, indices[0, :], norm_distances[0, :], out)
|
|
219
220
|
|
|
220
221
|
msg = f"Invalid number of dimensions: {ndim}"
|
|
221
222
|
raise ValueError(msg)
|
pycontrails/core/met.py
CHANGED
|
@@ -9,7 +9,15 @@ import pathlib
|
|
|
9
9
|
import typing
|
|
10
10
|
import warnings
|
|
11
11
|
from abc import ABC, abstractmethod
|
|
12
|
-
from collections.abc import
|
|
12
|
+
from collections.abc import (
|
|
13
|
+
Generator,
|
|
14
|
+
Hashable,
|
|
15
|
+
Iterable,
|
|
16
|
+
Iterator,
|
|
17
|
+
Mapping,
|
|
18
|
+
MutableMapping,
|
|
19
|
+
Sequence,
|
|
20
|
+
)
|
|
13
21
|
from contextlib import ExitStack
|
|
14
22
|
from datetime import datetime
|
|
15
23
|
from typing import (
|
|
@@ -1502,6 +1510,7 @@ class MetDataArray(MetBase):
|
|
|
1502
1510
|
bounds_error: bool = ...,
|
|
1503
1511
|
fill_value: float | np.float64 | None = ...,
|
|
1504
1512
|
localize: bool = ...,
|
|
1513
|
+
lowmem: bool = ...,
|
|
1505
1514
|
indices: interpolation.RGIArtifacts | None = ...,
|
|
1506
1515
|
return_indices: Literal[False] = ...,
|
|
1507
1516
|
) -> npt.NDArray[np.float64]: ...
|
|
@@ -1518,6 +1527,7 @@ class MetDataArray(MetBase):
|
|
|
1518
1527
|
bounds_error: bool = ...,
|
|
1519
1528
|
fill_value: float | np.float64 | None = ...,
|
|
1520
1529
|
localize: bool = ...,
|
|
1530
|
+
lowmem: bool = ...,
|
|
1521
1531
|
indices: interpolation.RGIArtifacts | None = ...,
|
|
1522
1532
|
return_indices: Literal[True],
|
|
1523
1533
|
) -> tuple[npt.NDArray[np.float64], interpolation.RGIArtifacts]: ...
|
|
@@ -1533,6 +1543,7 @@ class MetDataArray(MetBase):
|
|
|
1533
1543
|
bounds_error: bool = False,
|
|
1534
1544
|
fill_value: float | np.float64 | None = np.nan,
|
|
1535
1545
|
localize: bool = False,
|
|
1546
|
+
lowmem: bool = False,
|
|
1536
1547
|
indices: interpolation.RGIArtifacts | None = None,
|
|
1537
1548
|
return_indices: bool = False,
|
|
1538
1549
|
) -> npt.NDArray[np.float64] | tuple[npt.NDArray[np.float64], interpolation.RGIArtifacts]:
|
|
@@ -1540,7 +1551,9 @@ class MetDataArray(MetBase):
|
|
|
1540
1551
|
|
|
1541
1552
|
Zero dimensional coordinates are reshaped to 1D arrays.
|
|
1542
1553
|
|
|
1543
|
-
|
|
1554
|
+
If ``lowmem == False``, method automatically loads underlying :attr:`data` into
|
|
1555
|
+
memory. Otherwise, method iterates through smaller subsets of :attr:`data` and releases
|
|
1556
|
+
subsets from memory once interpolation against each subset is finished.
|
|
1544
1557
|
|
|
1545
1558
|
If ``method == "nearest"``, the out array will have the same ``dtype`` as
|
|
1546
1559
|
the underlying :attr:`data`.
|
|
@@ -1586,10 +1599,18 @@ class MetDataArray(MetBase):
|
|
|
1586
1599
|
localize: bool, optional
|
|
1587
1600
|
Experimental. If True, downselect gridded data to smallest bounding box containing
|
|
1588
1601
|
all points. By default False.
|
|
1602
|
+
lowmem: bool, optional
|
|
1603
|
+
Experimental. If True, iterate through points binned by the time coordinate of the
|
|
1604
|
+
grided data, and downselect gridded data to the smallest bounding box containing
|
|
1605
|
+
each binned set of point *before loading into memory*. This can significantly reduce
|
|
1606
|
+
memory consumption with large numbers of points at the cost of increased runtime.
|
|
1607
|
+
By default False.
|
|
1589
1608
|
indices: tuple | None, optional
|
|
1590
1609
|
Experimental. See :func:`interpolation.interp`. None by default.
|
|
1591
1610
|
return_indices: bool, optional
|
|
1592
1611
|
Experimental. See :func:`interpolation.interp`. False by default.
|
|
1612
|
+
Note that values returned differ when ``lowmem=True`` and ``lowmem=False``,
|
|
1613
|
+
so output should only be re-used in calls with the same ``lowmem`` value.
|
|
1593
1614
|
|
|
1594
1615
|
Returns
|
|
1595
1616
|
-------
|
|
@@ -1632,10 +1653,29 @@ class MetDataArray(MetBase):
|
|
|
1632
1653
|
>>> level = np.linspace(200, 300, 10)
|
|
1633
1654
|
>>> time = pd.date_range("2022-03-01T14", periods=10, freq="5min")
|
|
1634
1655
|
>>> mda.interpolate(longitude, latitude, level, time)
|
|
1656
|
+
array([220.44347694, 223.08900738, 225.74338924, 228.41642088,
|
|
1657
|
+
231.10858599, 233.54857391, 235.71504913, 237.86478872,
|
|
1658
|
+
239.99274623, 242.10792167])
|
|
1659
|
+
|
|
1660
|
+
>>> # Can easily switch to alternative low-memory implementation
|
|
1661
|
+
>>> mda.interpolate(longitude, latitude, level, time, lowmem=True)
|
|
1635
1662
|
array([220.44347694, 223.08900738, 225.74338924, 228.41642088,
|
|
1636
1663
|
231.10858599, 233.54857391, 235.71504913, 237.86478872,
|
|
1637
1664
|
239.99274623, 242.10792167])
|
|
1638
1665
|
"""
|
|
1666
|
+
if lowmem:
|
|
1667
|
+
return self._interp_lowmem(
|
|
1668
|
+
longitude,
|
|
1669
|
+
latitude,
|
|
1670
|
+
level,
|
|
1671
|
+
time,
|
|
1672
|
+
method=method,
|
|
1673
|
+
bounds_error=bounds_error,
|
|
1674
|
+
fill_value=fill_value,
|
|
1675
|
+
indices=indices,
|
|
1676
|
+
return_indices=return_indices,
|
|
1677
|
+
)
|
|
1678
|
+
|
|
1639
1679
|
# Load if necessary
|
|
1640
1680
|
if not self.in_memory:
|
|
1641
1681
|
self._check_memory("Interpolation over")
|
|
@@ -1660,6 +1700,100 @@ class MetDataArray(MetBase):
|
|
|
1660
1700
|
return_indices=return_indices,
|
|
1661
1701
|
)
|
|
1662
1702
|
|
|
1703
|
+
def _interp_lowmem(
|
|
1704
|
+
self,
|
|
1705
|
+
longitude: float | npt.NDArray[np.float64],
|
|
1706
|
+
latitude: float | npt.NDArray[np.float64],
|
|
1707
|
+
level: float | npt.NDArray[np.float64],
|
|
1708
|
+
time: np.datetime64 | npt.NDArray[np.datetime64],
|
|
1709
|
+
*,
|
|
1710
|
+
method: str = "linear",
|
|
1711
|
+
bounds_error: bool = False,
|
|
1712
|
+
fill_value: float | np.float64 | None = np.nan,
|
|
1713
|
+
minimize_memory: bool = False,
|
|
1714
|
+
indices: interpolation.RGIArtifacts | None = None,
|
|
1715
|
+
return_indices: bool = False,
|
|
1716
|
+
) -> npt.NDArray[np.float64] | tuple[npt.NDArray[np.float64], interpolation.RGIArtifacts]:
|
|
1717
|
+
"""Interpolate values against underlying DataArray.
|
|
1718
|
+
|
|
1719
|
+
This method is used by :meth:`interpolate` when ``lowmem=True``.
|
|
1720
|
+
Parameters and return types are identical to :meth:`interpolate`, except
|
|
1721
|
+
that the ``localize`` keyword argument is omitted.
|
|
1722
|
+
"""
|
|
1723
|
+
# Convert all inputs to 1d arrays
|
|
1724
|
+
# Not validating against ndim >= 2
|
|
1725
|
+
longitude, latitude, level, time = np.atleast_1d(longitude, latitude, level, time)
|
|
1726
|
+
|
|
1727
|
+
if bounds_error:
|
|
1728
|
+
_lowmem_boundscheck(time, self.data)
|
|
1729
|
+
|
|
1730
|
+
# Create buffers for holding interpolation output
|
|
1731
|
+
# Use np.full rather than np.empty so points not covered
|
|
1732
|
+
# by masks are filled with correct out-of-bounds values.
|
|
1733
|
+
out = np.full(longitude.shape, fill_value, dtype=self.data.dtype)
|
|
1734
|
+
if return_indices:
|
|
1735
|
+
rgi_artifacts = interpolation.RGIArtifacts(
|
|
1736
|
+
xi_indices=np.full((4, longitude.size), -1, dtype=np.int64),
|
|
1737
|
+
norm_distances=np.full((4, longitude.size), np.nan, dtype=np.float64),
|
|
1738
|
+
out_of_bounds=np.full((longitude.size,), True, dtype=np.bool_),
|
|
1739
|
+
)
|
|
1740
|
+
|
|
1741
|
+
# Iterate over portions of points between adjacent time steps in gridded data
|
|
1742
|
+
for mask in _lowmem_masks(time, self.data["time"].values):
|
|
1743
|
+
if mask is None or not np.any(mask):
|
|
1744
|
+
continue
|
|
1745
|
+
|
|
1746
|
+
lon_sl = longitude[mask]
|
|
1747
|
+
lat_sl = latitude[mask]
|
|
1748
|
+
lev_sl = level[mask]
|
|
1749
|
+
t_sl = time[mask]
|
|
1750
|
+
if indices is not None:
|
|
1751
|
+
indices_sl = interpolation.RGIArtifacts(
|
|
1752
|
+
xi_indices=indices.xi_indices[:, mask],
|
|
1753
|
+
norm_distances=indices.norm_distances[:, mask],
|
|
1754
|
+
out_of_bounds=indices.out_of_bounds[mask],
|
|
1755
|
+
)
|
|
1756
|
+
else:
|
|
1757
|
+
indices_sl = None
|
|
1758
|
+
|
|
1759
|
+
coords = {"longitude": lon_sl, "latitude": lat_sl, "level": lev_sl, "time": t_sl}
|
|
1760
|
+
if any(np.all(np.isnan(coord)) for coord in coords.values()):
|
|
1761
|
+
continue
|
|
1762
|
+
da = interpolation._localize(self.data, coords)
|
|
1763
|
+
if not da._in_memory:
|
|
1764
|
+
logger.debug(
|
|
1765
|
+
"Loading %s MB subset of %s into memory.",
|
|
1766
|
+
round(da.nbytes / 1_000_000, 2),
|
|
1767
|
+
da.name,
|
|
1768
|
+
)
|
|
1769
|
+
da.load()
|
|
1770
|
+
|
|
1771
|
+
tmp = interpolation.interp(
|
|
1772
|
+
longitude=lon_sl,
|
|
1773
|
+
latitude=lat_sl,
|
|
1774
|
+
level=lev_sl,
|
|
1775
|
+
time=t_sl,
|
|
1776
|
+
da=da,
|
|
1777
|
+
method=method,
|
|
1778
|
+
bounds_error=bounds_error,
|
|
1779
|
+
fill_value=fill_value,
|
|
1780
|
+
localize=False, # would be no-op; da is localized already
|
|
1781
|
+
indices=indices_sl,
|
|
1782
|
+
return_indices=return_indices,
|
|
1783
|
+
)
|
|
1784
|
+
|
|
1785
|
+
if return_indices:
|
|
1786
|
+
out[mask], rgi_sl = tmp
|
|
1787
|
+
rgi_artifacts.xi_indices[:, mask] = rgi_sl.xi_indices
|
|
1788
|
+
rgi_artifacts.norm_distances[:, mask] = rgi_sl.norm_distances
|
|
1789
|
+
rgi_artifacts.out_of_bounds[mask] = rgi_sl.out_of_bounds
|
|
1790
|
+
else:
|
|
1791
|
+
out[mask] = tmp
|
|
1792
|
+
|
|
1793
|
+
if return_indices:
|
|
1794
|
+
return out, rgi_artifacts
|
|
1795
|
+
return out
|
|
1796
|
+
|
|
1663
1797
|
def _check_memory(self, msg_start: str) -> None:
|
|
1664
1798
|
"""Check the memory usage of the underlying data.
|
|
1665
1799
|
|
|
@@ -2656,3 +2790,46 @@ def _add_vertical_coords(data: XArrayType) -> XArrayType:
|
|
|
2656
2790
|
data.coords["altitude"] = data.coords["altitude"].astype(dtype, copy=False)
|
|
2657
2791
|
|
|
2658
2792
|
return data
|
|
2793
|
+
|
|
2794
|
+
|
|
2795
|
+
def _lowmem_boundscheck(time: npt.NDArray[np.datetime64], da: xr.DataArray) -> None:
|
|
2796
|
+
"""Extra bounds check required with low-memory interpolation strategy.
|
|
2797
|
+
|
|
2798
|
+
Because the main loop in `_interp_lowmem` processes points between time steps
|
|
2799
|
+
in gridded data, it will never encounter points that are out-of-bounds in time
|
|
2800
|
+
and may fail to produce requested out-of-bounds errors.
|
|
2801
|
+
"""
|
|
2802
|
+
da_time = da["time"].to_numpy()
|
|
2803
|
+
if not np.all((time >= da_time.min()) & (time <= da_time.max())):
|
|
2804
|
+
axis = da.get_axis_num("time")
|
|
2805
|
+
msg = f"One of the requested xi is out of bounds in dimension {axis}"
|
|
2806
|
+
raise ValueError(msg)
|
|
2807
|
+
|
|
2808
|
+
|
|
2809
|
+
def _lowmem_masks(
|
|
2810
|
+
time: npt.NDArray[np.datetime64], t_met: npt.NDArray[np.datetime64]
|
|
2811
|
+
) -> Generator[npt.NDArray[np.bool_], None, None]:
|
|
2812
|
+
"""Generate sequence of masks for low-memory interpolation."""
|
|
2813
|
+
t_met_max = t_met.max()
|
|
2814
|
+
t_met_min = t_met.min()
|
|
2815
|
+
inbounds = (time >= t_met_min) & (time <= t_met_max)
|
|
2816
|
+
if not np.any(inbounds):
|
|
2817
|
+
return
|
|
2818
|
+
|
|
2819
|
+
earliest = np.nanmin(time)
|
|
2820
|
+
istart = 0 if earliest < t_met_min else np.flatnonzero(t_met <= earliest).max()
|
|
2821
|
+
latest = np.nanmax(time)
|
|
2822
|
+
iend = t_met.size - 1 if latest > t_met_max else np.flatnonzero(t_met >= latest).min()
|
|
2823
|
+
if istart == iend:
|
|
2824
|
+
yield inbounds
|
|
2825
|
+
return
|
|
2826
|
+
|
|
2827
|
+
# Sequence of masks covers elements in time in the interval [t_met[istart], t_met[iend]].
|
|
2828
|
+
# The first iteration masks elements in the interval [t_met[istart], t_met[istart+1]]
|
|
2829
|
+
# (inclusive of both endpoints).
|
|
2830
|
+
# Subsequent iterations mask elements in the interval (t_met[i], t_met[i+1]]
|
|
2831
|
+
# (inclusive of right endpoint only).
|
|
2832
|
+
for i in range(istart, iend):
|
|
2833
|
+
mask = ((time >= t_met[i]) if i == istart else (time > t_met[i])) & (time <= t_met[i + 1])
|
|
2834
|
+
if np.any(mask):
|
|
2835
|
+
yield mask
|
|
Binary file
|
|
@@ -148,7 +148,6 @@ class Cocip(Model):
|
|
|
148
148
|
|
|
149
149
|
This implementation is regression tested against
|
|
150
150
|
results from :cite:`teohAviationContrailClimate2022`.
|
|
151
|
-
See `tests/benchmark/north-atlantic-study/validate.py`.
|
|
152
151
|
|
|
153
152
|
**Outputs**
|
|
154
153
|
|
|
@@ -549,6 +548,8 @@ class Cocip(Model):
|
|
|
549
548
|
verbose_outputs = self.params["verbose_outputs"]
|
|
550
549
|
|
|
551
550
|
interp_kwargs = self.interp_kwargs
|
|
551
|
+
if self.params["preprocess_lowmem"]:
|
|
552
|
+
interp_kwargs["lowmem"] = True
|
|
552
553
|
interpolate_met(met, self.source, "air_temperature", **interp_kwargs)
|
|
553
554
|
interpolate_met(met, self.source, "specific_humidity", **interp_kwargs)
|
|
554
555
|
interpolate_met(met, self.source, "eastward_wind", "u_wind", **interp_kwargs)
|
|
@@ -750,6 +751,8 @@ class Cocip(Model):
|
|
|
750
751
|
|
|
751
752
|
# get full met grid or flight data interpolated to the pressure level `p_dz`
|
|
752
753
|
interp_kwargs = self.interp_kwargs
|
|
754
|
+
if self.params["preprocess_lowmem"]:
|
|
755
|
+
interp_kwargs["lowmem"] = True
|
|
753
756
|
air_temperature_lower = interpolate_met(
|
|
754
757
|
met,
|
|
755
758
|
self._sac_flight,
|
|
@@ -861,6 +864,8 @@ class Cocip(Model):
|
|
|
861
864
|
|
|
862
865
|
# get met post wake vortex along initial contrail
|
|
863
866
|
interp_kwargs = self.interp_kwargs
|
|
867
|
+
if self.params["preprocess_lowmem"]:
|
|
868
|
+
interp_kwargs["lowmem"] = True
|
|
864
869
|
air_temperature_1 = interpolate_met(met, contrail_1, "air_temperature", **interp_kwargs)
|
|
865
870
|
interpolate_met(met, contrail_1, "specific_humidity", **interp_kwargs)
|
|
866
871
|
|
|
@@ -952,11 +957,14 @@ class Cocip(Model):
|
|
|
952
957
|
)
|
|
953
958
|
logger.debug("None are filtered out!")
|
|
954
959
|
|
|
955
|
-
def
|
|
956
|
-
"""
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
+
def _process_downwash_flight(self) -> tuple[MetDataset | None, MetDataset | None]:
|
|
961
|
+
"""Create and calculate properties of contrails created by downwash vortex.
|
|
962
|
+
|
|
963
|
+
``_downwash_contrail`` is a contrail representation of the waypoints of
|
|
964
|
+
``_downwash_flight``, which has already been filtered for initial persistent waypoints.
|
|
965
|
+
|
|
966
|
+
Returns MetDatasets for subsequent use if ``preprocess_lowmem=False``.
|
|
967
|
+
"""
|
|
960
968
|
self._downwash_contrail = self._create_downwash_contrail()
|
|
961
969
|
buffers = {
|
|
962
970
|
f"{coord}_buffer": self.params[f"met_{coord}_buffer"]
|
|
@@ -971,6 +979,8 @@ class Cocip(Model):
|
|
|
971
979
|
calc_timestep_geometry(self._downwash_contrail)
|
|
972
980
|
|
|
973
981
|
interp_kwargs = self.interp_kwargs
|
|
982
|
+
if self.params["preprocess_lowmem"]:
|
|
983
|
+
interp_kwargs["lowmem"] = True
|
|
974
984
|
calc_timestep_meteorology(self._downwash_contrail, met, self.params, **interp_kwargs)
|
|
975
985
|
calc_shortwave_radiation(rad, self._downwash_contrail, **interp_kwargs)
|
|
976
986
|
calc_outgoing_longwave_radiation(rad, self._downwash_contrail, **interp_kwargs)
|
|
@@ -985,6 +995,16 @@ class Cocip(Model):
|
|
|
985
995
|
# Intersect with rad dataset
|
|
986
996
|
calc_radiative_properties(self._downwash_contrail, self.params)
|
|
987
997
|
|
|
998
|
+
if self.params["preprocess_lowmem"]:
|
|
999
|
+
return None, None
|
|
1000
|
+
return met, rad
|
|
1001
|
+
|
|
1002
|
+
def _simulate_contrail_evolution(self) -> None:
|
|
1003
|
+
"""Simulate contrail evolution."""
|
|
1004
|
+
|
|
1005
|
+
met, rad = self._process_downwash_flight()
|
|
1006
|
+
interp_kwargs = self.interp_kwargs
|
|
1007
|
+
|
|
988
1008
|
contrail_contrail_overlapping = self.params["contrail_contrail_overlapping"]
|
|
989
1009
|
if contrail_contrail_overlapping and not isinstance(self.source, Fleet):
|
|
990
1010
|
warnings.warn("Contrail-Contrail Overlapping is only valid for Fleet mode.")
|
|
@@ -1022,22 +1042,7 @@ class Cocip(Model):
|
|
|
1022
1042
|
continue
|
|
1023
1043
|
|
|
1024
1044
|
# Update met, rad slices as needed
|
|
1025
|
-
|
|
1026
|
-
# created by calc_timestep_contrail_evolution. This "contrail_2" object
|
|
1027
|
-
# has constant time at "time_end", hence the buffer we apply below.
|
|
1028
|
-
# After the downwash_contrails is all used up, these updates are intended
|
|
1029
|
-
# to happen once each hour
|
|
1030
|
-
buffers["time_buffer"] = (
|
|
1031
|
-
np.timedelta64(0, "ns"),
|
|
1032
|
-
time_end - latest_contrail["time"].max(),
|
|
1033
|
-
)
|
|
1034
|
-
if time_end > met.indexes["time"].to_numpy()[-1]:
|
|
1035
|
-
logger.debug("Downselect met at time_end %s within Cocip evolution", time_end)
|
|
1036
|
-
met = latest_contrail.downselect_met(self.met, **buffers, copy=False)
|
|
1037
|
-
met = add_tau_cirrus(met)
|
|
1038
|
-
if time_end > rad.indexes["time"].to_numpy()[-1]:
|
|
1039
|
-
logger.debug("Downselect rad at time_end %s within Cocip evolution", time_end)
|
|
1040
|
-
rad = latest_contrail.downselect_met(self.rad, **buffers, copy=False)
|
|
1045
|
+
met, rad = self._maybe_downselect_met_rad(met, rad, latest_contrail, time_end)
|
|
1041
1046
|
|
|
1042
1047
|
# Recalculate latest_contrail with new values
|
|
1043
1048
|
# NOTE: We are doing a substantial amount of redundant computation here
|
|
@@ -1075,6 +1080,75 @@ class Cocip(Model):
|
|
|
1075
1080
|
|
|
1076
1081
|
self.contrail_list.append(final_contrail)
|
|
1077
1082
|
|
|
1083
|
+
def _maybe_downselect_met_rad(
|
|
1084
|
+
self,
|
|
1085
|
+
met: MetDataset | None,
|
|
1086
|
+
rad: MetDataset | None,
|
|
1087
|
+
latest_contrail: GeoVectorDataset,
|
|
1088
|
+
time_end: np.datetime64,
|
|
1089
|
+
) -> tuple[MetDataset, MetDataset]:
|
|
1090
|
+
"""Downselect ``self.met`` and ``self.rad`` if necessary to cover ``time_end``.
|
|
1091
|
+
|
|
1092
|
+
If current ``met`` and ``rad`` slices to not include ``time_end``, new slices are selected
|
|
1093
|
+
from ``self.met`` and ``self.rad``. Downselection in space will cover
|
|
1094
|
+
- locations of current contrails (``latest_contrail``),
|
|
1095
|
+
- locations of additional contrails that will be loaded from ``self._downwash_flight``
|
|
1096
|
+
before the new slices expire,
|
|
1097
|
+
plus a user-defined buffer.
|
|
1098
|
+
"""
|
|
1099
|
+
if met is None or time_end > met.indexes["time"].to_numpy()[-1]:
|
|
1100
|
+
logger.debug("Downselect met at time_end %s within Cocip evolution", time_end)
|
|
1101
|
+
met = self._definitely_downselect_met_or_rad(self.met, latest_contrail, time_end)
|
|
1102
|
+
met = add_tau_cirrus(met)
|
|
1103
|
+
|
|
1104
|
+
if rad is None or time_end > rad.indexes["time"].to_numpy()[-1]:
|
|
1105
|
+
logger.debug("Downselect rad at time_end %s within Cocip evolution", time_end)
|
|
1106
|
+
rad = self._definitely_downselect_met_or_rad(self.rad, latest_contrail, time_end)
|
|
1107
|
+
|
|
1108
|
+
return met, rad
|
|
1109
|
+
|
|
1110
|
+
def _definitely_downselect_met_or_rad(
|
|
1111
|
+
self, met: MetDataset, latest_contrail: GeoVectorDataset, time_end: np.datetime64
|
|
1112
|
+
) -> MetDataset:
|
|
1113
|
+
"""Perform downselection when required by :meth:`_maybe_downselect_met_rad`.
|
|
1114
|
+
|
|
1115
|
+
Downselects ``met`` (which should be one of ``self.met`` or ``self.rad``)
|
|
1116
|
+
to cover ``time_end``. Downselection in space covers
|
|
1117
|
+
- locations of current contrails (``latest_contrail``),
|
|
1118
|
+
- locations of additional contrails that will be loaded from ``self._downwash_flight``
|
|
1119
|
+
before the new slices expire,
|
|
1120
|
+
plus a user-defined buffer, as described in :meth:`_maybe_downselect_met_rad`.
|
|
1121
|
+
"""
|
|
1122
|
+
# compute lookahead for future contrails from downwash_flight
|
|
1123
|
+
met_time = met.indexes["time"].to_numpy()
|
|
1124
|
+
mask = met_time >= time_end
|
|
1125
|
+
lookahead = np.min(met_time[mask]) if np.any(mask) else time_end
|
|
1126
|
+
|
|
1127
|
+
# create vector for downselection based on current + future contrails
|
|
1128
|
+
future_contrails = self._downwash_flight.filter(
|
|
1129
|
+
(self._downwash_flight["time"] >= time_end)
|
|
1130
|
+
& (self._downwash_flight["time"] <= lookahead),
|
|
1131
|
+
copy=False,
|
|
1132
|
+
)
|
|
1133
|
+
vector = GeoVectorDataset(
|
|
1134
|
+
{
|
|
1135
|
+
key: np.concat((latest_contrail[key], future_contrails[key]))
|
|
1136
|
+
for key in ("longitude", "latitude", "level", "time")
|
|
1137
|
+
}
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
# compute time buffer to ensure downselection extends to time_end
|
|
1141
|
+
buffers = {
|
|
1142
|
+
f"{coord}_buffer": self.params[f"met_{coord}_buffer"]
|
|
1143
|
+
for coord in ("longitude", "latitude", "level")
|
|
1144
|
+
}
|
|
1145
|
+
buffers["time_buffer"] = (
|
|
1146
|
+
np.timedelta64(0, "ns"),
|
|
1147
|
+
max(np.timedelta64(0, "ns"), time_end - vector["time"].max()),
|
|
1148
|
+
)
|
|
1149
|
+
|
|
1150
|
+
return vector.downselect_met(met, **buffers, copy=False)
|
|
1151
|
+
|
|
1078
1152
|
def _create_downwash_contrail(self) -> GeoVectorDataset:
|
|
1079
1153
|
"""Get Contrail representation of downwash flight."""
|
|
1080
1154
|
|
|
@@ -84,6 +84,27 @@ class CocipParams(ModelParams):
|
|
|
84
84
|
#: Humidity scaling
|
|
85
85
|
humidity_scaling: HumidityScaling | None = None
|
|
86
86
|
|
|
87
|
+
#: Experimental. If ``True``, attempt to reduce memory consumption during
|
|
88
|
+
#: aircraft performance and initial contrail formation/persistent calculations
|
|
89
|
+
#: by calling :meth:`MetDataArray.interpolate` with ``lowmem=True``.
|
|
90
|
+
#:
|
|
91
|
+
#: **IMPORTANT**:
|
|
92
|
+
#:
|
|
93
|
+
#: * Memory optimizations used when ``proprocess_lowmem=True`` are designed for
|
|
94
|
+
#: meteorology backed by dask arrays with a chunk size of 1 along
|
|
95
|
+
#: the time dimension. This option may degrade performance if dask if not used
|
|
96
|
+
#: or if chunks contain more than a single time step.
|
|
97
|
+
#: * The impact on runtime of setting ``preprocess_lowmem=True`` depends on how
|
|
98
|
+
#: meteorology data is chunked. Runtime is likely to increase if meteorology
|
|
99
|
+
#: data is chunked in time only, but may decrease if meteorology data is also
|
|
100
|
+
#: chunked in longitude, latitude, and level.
|
|
101
|
+
#: * Changes to data access patterns with ``preprocess_lowmem=True`` alter locations
|
|
102
|
+
#: where interpolation is in- vs out-of-bounds. As a consequence,
|
|
103
|
+
#: Cocip output with ``preprocess_lowmem=True`` is only guaranteed to match output
|
|
104
|
+
#: with ``preprocess_lowmem=False`` when run with ``interpolation_bounds_error=True``
|
|
105
|
+
#: to ensure no out-of-bounds interpolation occurs.
|
|
106
|
+
preprocess_lowmem: bool = False
|
|
107
|
+
|
|
87
108
|
# --------------
|
|
88
109
|
# Downselect met
|
|
89
110
|
# --------------
|
|
@@ -24,7 +24,6 @@ import pathlib
|
|
|
24
24
|
import warnings
|
|
25
25
|
from collections.abc import Hashable
|
|
26
26
|
|
|
27
|
-
import matplotlib.pyplot as plt
|
|
28
27
|
import numpy as np
|
|
29
28
|
import numpy.typing as npt
|
|
30
29
|
import pandas as pd
|
|
@@ -2141,7 +2140,17 @@ def compare_cocip_with_goes(
|
|
|
2141
2140
|
name="compare_cocip_with_goes function",
|
|
2142
2141
|
package_name="cartopy",
|
|
2143
2142
|
module_not_found_error=e,
|
|
2144
|
-
pycontrails_optional_package="
|
|
2143
|
+
pycontrails_optional_package="sat",
|
|
2144
|
+
)
|
|
2145
|
+
|
|
2146
|
+
try:
|
|
2147
|
+
import matplotlib.pyplot as plt
|
|
2148
|
+
except ModuleNotFoundError as e:
|
|
2149
|
+
dependencies.raise_module_not_found_error(
|
|
2150
|
+
name="compare_cocip_with_goes function",
|
|
2151
|
+
package_name="matplotlib",
|
|
2152
|
+
module_not_found_error=e,
|
|
2153
|
+
pycontrails_optional_package="vis",
|
|
2145
2154
|
)
|
|
2146
2155
|
|
|
2147
2156
|
# Round `time` to nearest GOES image time slice
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pycontrails
|
|
3
|
-
Version: 0.52.
|
|
3
|
+
Version: 0.52.3
|
|
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
|
|
@@ -27,92 +27,92 @@ Requires-Python: >=3.9
|
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
License-File: NOTICE
|
|
30
|
-
Requires-Dist: dask
|
|
31
|
-
Requires-Dist: numpy
|
|
32
|
-
Requires-Dist: overrides
|
|
33
|
-
Requires-Dist: pandas
|
|
34
|
-
Requires-Dist: scipy
|
|
35
|
-
Requires-Dist: xarray
|
|
30
|
+
Requires-Dist: dask>=2022.3
|
|
31
|
+
Requires-Dist: numpy>=1.22
|
|
32
|
+
Requires-Dist: overrides>=6.1
|
|
33
|
+
Requires-Dist: pandas>=2.2
|
|
34
|
+
Requires-Dist: scipy>=1.10
|
|
35
|
+
Requires-Dist: xarray>=2022.3
|
|
36
36
|
Provides-Extra: complete
|
|
37
|
-
Requires-Dist: pycontrails[ecmwf,gcp,gfs,jupyter,pyproj,sat,vis,zarr]
|
|
37
|
+
Requires-Dist: pycontrails[ecmwf,gcp,gfs,jupyter,pyproj,sat,vis,zarr]; extra == "complete"
|
|
38
38
|
Provides-Extra: dev
|
|
39
|
-
Requires-Dist: black[jupyter]
|
|
40
|
-
Requires-Dist: dep-license
|
|
41
|
-
Requires-Dist: fastparquet
|
|
42
|
-
Requires-Dist: ipdb
|
|
43
|
-
Requires-Dist: memory-profiler
|
|
44
|
-
Requires-Dist: mypy
|
|
45
|
-
Requires-Dist: mypy-extensions
|
|
46
|
-
Requires-Dist: platformdirs
|
|
47
|
-
Requires-Dist: pre-commit
|
|
48
|
-
Requires-Dist: psutil
|
|
49
|
-
Requires-Dist: pyarrow
|
|
50
|
-
Requires-Dist: pytest
|
|
51
|
-
Requires-Dist: pytest-cov
|
|
52
|
-
Requires-Dist: requests
|
|
53
|
-
Requires-Dist: ruff
|
|
54
|
-
Requires-Dist: setuptools
|
|
39
|
+
Requires-Dist: black[jupyter]==24.4.2; extra == "dev"
|
|
40
|
+
Requires-Dist: dep-license; extra == "dev"
|
|
41
|
+
Requires-Dist: fastparquet>=0.8; extra == "dev"
|
|
42
|
+
Requires-Dist: ipdb>=0.13; extra == "dev"
|
|
43
|
+
Requires-Dist: memory-profiler; extra == "dev"
|
|
44
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
45
|
+
Requires-Dist: mypy-extensions>=1.0; extra == "dev"
|
|
46
|
+
Requires-Dist: platformdirs>=3.0; extra == "dev"
|
|
47
|
+
Requires-Dist: pre-commit>=2.10; extra == "dev"
|
|
48
|
+
Requires-Dist: psutil; extra == "dev"
|
|
49
|
+
Requires-Dist: pyarrow>=5.0; extra == "dev"
|
|
50
|
+
Requires-Dist: pytest>=8.2; extra == "dev"
|
|
51
|
+
Requires-Dist: pytest-cov>=2.11; extra == "dev"
|
|
52
|
+
Requires-Dist: requests>=2.25; extra == "dev"
|
|
53
|
+
Requires-Dist: ruff==0.5.3; extra == "dev"
|
|
54
|
+
Requires-Dist: setuptools; extra == "dev"
|
|
55
55
|
Provides-Extra: docs
|
|
56
|
-
Requires-Dist: doc8
|
|
57
|
-
Requires-Dist: furo
|
|
58
|
-
Requires-Dist: myst-parser
|
|
59
|
-
Requires-Dist: nb-clean
|
|
60
|
-
Requires-Dist: nbsphinx
|
|
61
|
-
Requires-Dist: nbval
|
|
62
|
-
Requires-Dist: pytest-check-links
|
|
63
|
-
Requires-Dist: sphinx
|
|
64
|
-
Requires-Dist: sphinx-autobuild
|
|
65
|
-
Requires-Dist: sphinxcontrib-bibtex
|
|
66
|
-
Requires-Dist: sphinx-copybutton
|
|
67
|
-
Requires-Dist: sphinxext.opengraph
|
|
56
|
+
Requires-Dist: doc8>=1.1; extra == "docs"
|
|
57
|
+
Requires-Dist: furo>=2023.3; extra == "docs"
|
|
58
|
+
Requires-Dist: myst-parser>=1.0; extra == "docs"
|
|
59
|
+
Requires-Dist: nb-clean>=3.2; extra == "docs"
|
|
60
|
+
Requires-Dist: nbsphinx>=0.9; extra == "docs"
|
|
61
|
+
Requires-Dist: nbval!=0.10.0,>=0.9.6; extra == "docs"
|
|
62
|
+
Requires-Dist: pytest-check-links>=0.8.0; extra == "docs"
|
|
63
|
+
Requires-Dist: sphinx>=4.2; extra == "docs"
|
|
64
|
+
Requires-Dist: sphinx-autobuild>=0.7; extra == "docs"
|
|
65
|
+
Requires-Dist: sphinxcontrib-bibtex>=2.2; extra == "docs"
|
|
66
|
+
Requires-Dist: sphinx-copybutton>=0.5; extra == "docs"
|
|
67
|
+
Requires-Dist: sphinxext.opengraph>=0.8; extra == "docs"
|
|
68
68
|
Provides-Extra: ecmwf
|
|
69
|
-
Requires-Dist: cdsapi
|
|
70
|
-
Requires-Dist: cfgrib
|
|
71
|
-
Requires-Dist: eccodes
|
|
72
|
-
Requires-Dist: ecmwf-api-client
|
|
73
|
-
Requires-Dist: netcdf4
|
|
74
|
-
Requires-Dist: platformdirs
|
|
75
|
-
Requires-Dist: requests
|
|
76
|
-
Requires-Dist: lxml
|
|
69
|
+
Requires-Dist: cdsapi>=0.4; extra == "ecmwf"
|
|
70
|
+
Requires-Dist: cfgrib>=0.9; extra == "ecmwf"
|
|
71
|
+
Requires-Dist: eccodes>=1.4; extra == "ecmwf"
|
|
72
|
+
Requires-Dist: ecmwf-api-client>=1.6; extra == "ecmwf"
|
|
73
|
+
Requires-Dist: netcdf4>=1.6.1; extra == "ecmwf"
|
|
74
|
+
Requires-Dist: platformdirs>=3.0; extra == "ecmwf"
|
|
75
|
+
Requires-Dist: requests>=2.25; extra == "ecmwf"
|
|
76
|
+
Requires-Dist: lxml>=5.1.0; extra == "ecmwf"
|
|
77
77
|
Provides-Extra: gcp
|
|
78
|
-
Requires-Dist: google-cloud-storage
|
|
79
|
-
Requires-Dist: platformdirs
|
|
80
|
-
Requires-Dist: tqdm
|
|
78
|
+
Requires-Dist: google-cloud-storage>=2.1; extra == "gcp"
|
|
79
|
+
Requires-Dist: platformdirs>=3.0; extra == "gcp"
|
|
80
|
+
Requires-Dist: tqdm>=4.61; extra == "gcp"
|
|
81
81
|
Provides-Extra: gfs
|
|
82
|
-
Requires-Dist: boto3
|
|
83
|
-
Requires-Dist: cfgrib
|
|
84
|
-
Requires-Dist: eccodes
|
|
85
|
-
Requires-Dist: platformdirs
|
|
86
|
-
Requires-Dist: tqdm
|
|
82
|
+
Requires-Dist: boto3>=1.20; extra == "gfs"
|
|
83
|
+
Requires-Dist: cfgrib>=0.9; extra == "gfs"
|
|
84
|
+
Requires-Dist: eccodes>=1.4; extra == "gfs"
|
|
85
|
+
Requires-Dist: platformdirs>=3.0; extra == "gfs"
|
|
86
|
+
Requires-Dist: tqdm>=4.61; extra == "gfs"
|
|
87
87
|
Provides-Extra: jupyter
|
|
88
|
-
Requires-Dist: ipywidgets
|
|
89
|
-
Requires-Dist: jupyterlab
|
|
88
|
+
Requires-Dist: ipywidgets>=7.6; extra == "jupyter"
|
|
89
|
+
Requires-Dist: jupyterlab>=2.2; extra == "jupyter"
|
|
90
90
|
Provides-Extra: open3d
|
|
91
|
-
Requires-Dist: open3d
|
|
91
|
+
Requires-Dist: open3d>=0.14; extra == "open3d"
|
|
92
92
|
Provides-Extra: pyproj
|
|
93
|
-
Requires-Dist: pyproj
|
|
93
|
+
Requires-Dist: pyproj>=3.5; extra == "pyproj"
|
|
94
94
|
Provides-Extra: sat
|
|
95
|
-
Requires-Dist: cartopy
|
|
96
|
-
Requires-Dist: db-dtypes
|
|
97
|
-
Requires-Dist: gcsfs
|
|
98
|
-
Requires-Dist: geojson
|
|
99
|
-
Requires-Dist: google-cloud-bigquery
|
|
100
|
-
Requires-Dist: google-cloud-bigquery-storage
|
|
101
|
-
Requires-Dist: pillow
|
|
102
|
-
Requires-Dist: pyproj
|
|
103
|
-
Requires-Dist: rasterio
|
|
104
|
-
Requires-Dist: scikit-image
|
|
95
|
+
Requires-Dist: cartopy>=0.22; extra == "sat"
|
|
96
|
+
Requires-Dist: db-dtypes>=1.2; extra == "sat"
|
|
97
|
+
Requires-Dist: gcsfs>=2022.3; extra == "sat"
|
|
98
|
+
Requires-Dist: geojson>=3.1; extra == "sat"
|
|
99
|
+
Requires-Dist: google-cloud-bigquery>=3.23; extra == "sat"
|
|
100
|
+
Requires-Dist: google-cloud-bigquery-storage>=2.25; extra == "sat"
|
|
101
|
+
Requires-Dist: pillow>=10.3; extra == "sat"
|
|
102
|
+
Requires-Dist: pyproj>=3.5; extra == "sat"
|
|
103
|
+
Requires-Dist: rasterio>=1.3; extra == "sat"
|
|
104
|
+
Requires-Dist: scikit-image>=0.18; extra == "sat"
|
|
105
105
|
Provides-Extra: vis
|
|
106
|
-
Requires-Dist: matplotlib
|
|
107
|
-
Requires-Dist: opencv-python-headless
|
|
108
|
-
Requires-Dist: scikit-learn
|
|
109
|
-
Requires-Dist: scikit-image
|
|
110
|
-
Requires-Dist: seaborn
|
|
111
|
-
Requires-Dist: shapely
|
|
106
|
+
Requires-Dist: matplotlib>=3.3; extra == "vis"
|
|
107
|
+
Requires-Dist: opencv-python-headless>=4.5; extra == "vis"
|
|
108
|
+
Requires-Dist: scikit-learn>=0.23; extra == "vis"
|
|
109
|
+
Requires-Dist: scikit-image>=0.18; extra == "vis"
|
|
110
|
+
Requires-Dist: seaborn>=0.11; extra == "vis"
|
|
111
|
+
Requires-Dist: shapely>=2.0; extra == "vis"
|
|
112
112
|
Provides-Extra: zarr
|
|
113
|
-
Requires-Dist: fsspec
|
|
114
|
-
Requires-Dist: gcsfs
|
|
115
|
-
Requires-Dist: zarr
|
|
113
|
+
Requires-Dist: fsspec>=2022.7.1; extra == "zarr"
|
|
114
|
+
Requires-Dist: gcsfs>=2022.7.1; extra == "zarr"
|
|
115
|
+
Requires-Dist: zarr>=2.12; extra == "zarr"
|
|
116
116
|
|
|
117
117
|
# pycontrails
|
|
118
118
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
pycontrails/__init__.py,sha256=EpPulx2dBYpqZNsyh6HTwGGnFsvBVHBXabG5VInwSg4,2071
|
|
2
|
-
pycontrails/_version.py,sha256=
|
|
2
|
+
pycontrails/_version.py,sha256=DwcfPcd9EyaZVcBfypzp-ZYnJMP7npcKts9iUv9NVh0,429
|
|
3
3
|
pycontrails/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
pycontrails/core/__init__.py,sha256=X0DX2FGboPN_svwN2xiBzoPpHhDtg0oKFjXQfmCqMWU,886
|
|
5
5
|
pycontrails/core/aircraft_performance.py,sha256=osV68kKLpvnzBX8fqZcBefbKoYqTxhAf2EWLRdTA7Ec,26748
|
|
@@ -10,12 +10,12 @@ pycontrails/core/fleet.py,sha256=vB1XHcajtTLlelY_u72SAYUCt3h2smzqZIpeLFJaW0M,166
|
|
|
10
10
|
pycontrails/core/flight.py,sha256=lLqS0lWLCaN8YPusi1AzPZqtyHr4dZTYJ9SC3rosd7Q,87453
|
|
11
11
|
pycontrails/core/flightplan.py,sha256=cpMZ6VCYbfwh3vnew2XgVEHnqBx1NzeAhrTVCvlbbss,7569
|
|
12
12
|
pycontrails/core/fuel.py,sha256=06YUDhvC8Rx6KbUXRB9qLTsJX2V7tLbzjwAfDH0R6l8,4472
|
|
13
|
-
pycontrails/core/interpolation.py,sha256=
|
|
14
|
-
pycontrails/core/met.py,sha256=
|
|
13
|
+
pycontrails/core/interpolation.py,sha256=FnaVFT9OQXNLTx3FjUgqkgXVohn1JL0fdQTgEAPBgag,26309
|
|
14
|
+
pycontrails/core/met.py,sha256=WOaIOZkLI7ocqK0pzEv01zhQ7-l0G_t39dppj4Iqfvw,104160
|
|
15
15
|
pycontrails/core/met_var.py,sha256=JzB7UhBLQyU4TuKZqemhpBHA6Dbt89BPYO2sYBLMkL4,9504
|
|
16
16
|
pycontrails/core/models.py,sha256=D5pnAxejpDbHfh_wszxTA4cq6dr2L0Sn3OBmSL4zSsA,40491
|
|
17
17
|
pycontrails/core/polygon.py,sha256=F403uzql_c47MPM2Qdmec6WwtFaXZyb48h-4gK-K4EU,18577
|
|
18
|
-
pycontrails/core/rgi_cython.cp312-win_amd64.pyd,sha256=
|
|
18
|
+
pycontrails/core/rgi_cython.cp312-win_amd64.pyd,sha256=wa7z0fJ5CEorJu7Pir8ZUjY_sSw-_oD2fUnYxMHbYRA,265216
|
|
19
19
|
pycontrails/core/vector.py,sha256=YdzU47DSilECjYAvqZb2M_Lgs7OP7JvrDceneq4cKCU,73762
|
|
20
20
|
pycontrails/datalib/__init__.py,sha256=Q2RrnjwtFzfsmJ2tEojDCzDMkd8R0MYw4mQz3YwUsqI,381
|
|
21
21
|
pycontrails/datalib/goes.py,sha256=UMxXXCiRL6SHY5_3cXs8GmG19eeKOOi3gKCimkyZSuc,27305
|
|
@@ -58,11 +58,11 @@ pycontrails/models/apcemm/inputs.py,sha256=zHRSWVVlwYw6ms7PpC0p0I-xFsRDUVY9eDZ1g
|
|
|
58
58
|
pycontrails/models/apcemm/utils.py,sha256=6pKQbS5EAzTnI_edVtUvGrzM0xwNq1t9MBGgCRJtg_0,17531
|
|
59
59
|
pycontrails/models/apcemm/static/apcemm_yaml_template.yaml,sha256=A3H_FWVOtqkZhG91TWLdblMKaLWIcjRMsKqkfTN6mB4,6928
|
|
60
60
|
pycontrails/models/cocip/__init__.py,sha256=miDxSFxN9PzL_ieSJb3BYeHmbKqZwGicCz1scNB5eW0,991
|
|
61
|
-
pycontrails/models/cocip/cocip.py,sha256=
|
|
62
|
-
pycontrails/models/cocip/cocip_params.py,sha256=
|
|
61
|
+
pycontrails/models/cocip/cocip.py,sha256=BpHdEw3T9lICO9AvxpWO9tAU73APvUfMqKR4QakdSlo,102726
|
|
62
|
+
pycontrails/models/cocip/cocip_params.py,sha256=JwQl8FLcp4l5-MLiMQhPsxHL8jKXg2ymWXD7Jbn3zTQ,13002
|
|
63
63
|
pycontrails/models/cocip/cocip_uncertainty.py,sha256=7W586BJEAY_wpSpfVdcdX-HpZG4twk3cMLhUR2ELTMA,12176
|
|
64
64
|
pycontrails/models/cocip/contrail_properties.py,sha256=u6SvucHC6VtF2kujfSVFTfv0263t5uYpNOUJZAroEzc,57111
|
|
65
|
-
pycontrails/models/cocip/output_formats.py,sha256=
|
|
65
|
+
pycontrails/models/cocip/output_formats.py,sha256=cmkFDo66K-2cZuH1uutJSIw0EqcOPD9Dj5bXSoyXsh4,85906
|
|
66
66
|
pycontrails/models/cocip/radiative_forcing.py,sha256=SYmQ8lL8gpWbf6he2C9mKSjODtytbFcdnMdBM-LtBKE,46206
|
|
67
67
|
pycontrails/models/cocip/radiative_heating.py,sha256=N7FTR20luERmokprdqMOl-d8-cTYZZ2ZSsTdxZnLHfs,19368
|
|
68
68
|
pycontrails/models/cocip/unterstrasser_wake_vortex.py,sha256=Ymz-uO9vVhLIFwT9yuF5g1g3hcT-XWdryLsebSBqoVU,14976
|
|
@@ -101,9 +101,9 @@ pycontrails/utils/iteration.py,sha256=En2YY4NiNwCNtAVO8HL6tv9byBGKs8MKSI7R8P-gZy
|
|
|
101
101
|
pycontrails/utils/json.py,sha256=xCv71CKVZNHk4MyoYC-hl7dXObXXbI7P8gcNCn3AUoU,6172
|
|
102
102
|
pycontrails/utils/temp.py,sha256=5XXqQoEfWjz1OrhoOBZD5vkkCFeuq9LpZkyhc38gIeY,1159
|
|
103
103
|
pycontrails/utils/types.py,sha256=gNG9cSZ3djW7jufg0h1fXM3kD24sBY6ENE6wsxY_Q6o,4937
|
|
104
|
-
pycontrails-0.52.
|
|
105
|
-
pycontrails-0.52.
|
|
106
|
-
pycontrails-0.52.
|
|
107
|
-
pycontrails-0.52.
|
|
108
|
-
pycontrails-0.52.
|
|
109
|
-
pycontrails-0.52.
|
|
104
|
+
pycontrails-0.52.3.dist-info/LICENSE,sha256=HVr8JnZfTaA-12BfKUQZi5hdrB3awOwLWs5X_ga5QzA,10353
|
|
105
|
+
pycontrails-0.52.3.dist-info/METADATA,sha256=WcCq_h2VOQZQdue96yM1vAEvn9KRdxl3siBcaS9bGrI,9351
|
|
106
|
+
pycontrails-0.52.3.dist-info/NOTICE,sha256=qYeNEp8OjDK5jSW3hTlr9LQRjZeEhXQm0zDei5UFaYs,1969
|
|
107
|
+
pycontrails-0.52.3.dist-info/WHEEL,sha256=KNRoynpGu-d6mheJI-zfvcGl1iN-y8BewbiCDXsF3cY,101
|
|
108
|
+
pycontrails-0.52.3.dist-info/top_level.txt,sha256=Z8J1R_AiBAyCVjNw6jYLdrA68PrQqTg0t3_Yek_IZ0Q,29
|
|
109
|
+
pycontrails-0.52.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|