pycontrails 0.51.1__cp39-cp39-win_amd64.whl → 0.51.2__cp39-cp39-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 CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.51.1'
16
- __version_tuple__ = version_tuple = (0, 51, 1)
15
+ __version__ = version = '0.51.2'
16
+ __version_tuple__ = version_tuple = (0, 51, 2)
@@ -354,7 +354,7 @@ def find_multipolygon(
354
354
  return shapely.MultiPolygon()
355
355
 
356
356
  assert len(hierarchy) == 1
357
- hierarchy = hierarchy[0]
357
+ hierarchy = hierarchy[0] # type: ignore[index]
358
358
 
359
359
  polygons = _contours_to_polygons(
360
360
  contours, # type: ignore[arg-type]
@@ -4,6 +4,7 @@ from pycontrails.models.cocip.cocip import Cocip
4
4
  from pycontrails.models.cocip.cocip_params import CocipFlightParams, CocipParams
5
5
  from pycontrails.models.cocip.cocip_uncertainty import CocipUncertaintyParams, habit_dirichlet
6
6
  from pycontrails.models.cocip.output_formats import (
7
+ compare_cocip_with_goes,
7
8
  contrail_flight_summary_statistics,
8
9
  contrails_to_hi_res_grid,
9
10
  flight_waypoint_summary_statistics,
@@ -24,4 +25,5 @@ __all__ = [
24
25
  "longitude_latitude_grid",
25
26
  "natural_cirrus_properties_to_hi_res_grid",
26
27
  "time_slice_statistics",
28
+ "compare_cocip_with_goes",
27
29
  ]
@@ -14,13 +14,17 @@ This module includes functions to produce additional output formats, including t
14
14
  (6) Increase spatial resolution of natural cirrus properties, required to estimate the
15
15
  high-resolution contrail cirrus coverage for (5).
16
16
  See :func:`natural_cirrus_properties_to_hi_res_grid`.
17
+ (7) Comparing simulated contrails from CoCiP with GOES satellite imagery.
18
+ See :func:`compare_cocip_with_goes`.
17
19
  """
18
20
 
19
21
  from __future__ import annotations
20
22
 
23
+ import pathlib
21
24
  import warnings
22
25
  from collections.abc import Hashable
23
26
 
27
+ import matplotlib.pyplot as plt
24
28
  import numpy as np
25
29
  import numpy.typing as npt
26
30
  import pandas as pd
@@ -28,6 +32,7 @@ import xarray as xr
28
32
 
29
33
  from pycontrails.core.met import MetDataArray, MetDataset
30
34
  from pycontrails.core.vector import GeoVectorDataset, vector_to_lon_lat_grid
35
+ from pycontrails.datalib.goes import GOES, extract_goes_visualization
31
36
  from pycontrails.models.cocip.contrail_properties import contrail_edges, plume_mass_per_distance
32
37
  from pycontrails.models.cocip.radiative_forcing import albedo
33
38
  from pycontrails.models.humidity_scaling import HumidityScaling
@@ -2077,3 +2082,163 @@ def _repeat_rows_and_columns(
2077
2082
 
2078
2083
  # Do not repeat final row and column as they are on the edge
2079
2084
  return array_2d_rep[: -(n_reps - 1), : -(n_reps - 1)]
2085
+
2086
+
2087
+ # -----------------------------------------
2088
+ # Compare CoCiP outputs with GOES satellite
2089
+ # -----------------------------------------
2090
+
2091
+
2092
+ def compare_cocip_with_goes(
2093
+ time: np.timedelta64 | pd.Timestamp,
2094
+ flight: GeoVectorDataset | pd.DataFrame,
2095
+ contrail: GeoVectorDataset | pd.DataFrame,
2096
+ *,
2097
+ spatial_bbox: tuple[float, float, float, float] = (-160.0, -80.0, 10.0, 80.0),
2098
+ region: str = "F",
2099
+ path_write_img: pathlib.Path | None = None,
2100
+ ) -> None | pathlib.Path:
2101
+ r"""
2102
+ Compare simulated persistent contrails from CoCiP with GOES satellite imagery.
2103
+
2104
+ Parameters
2105
+ ----------
2106
+ time : np.timedelta64 | pd.Timestamp
2107
+ Time of GOES satellite image.
2108
+ flight : GeoVectorDataset | pd.DataFrame
2109
+ Flight waypoints.
2110
+ Best to use the returned output :class:`Flight` from
2111
+ :meth:`pycontrails.models.cocip.Cocip.eval`.
2112
+ contrail : GeoVectorDataset | pd.DataFrame,
2113
+ Contrail evolution outputs (:attr:`pycontrails.models.cocip.Cocip.contrail`)
2114
+ set during :meth:`pycontrails.models.cocip.Cocip.eval`.
2115
+ spatial_bbox : tuple[float, float, float, float]
2116
+ Spatial bounding box, ``(lon_min, lat_min, lon_max, lat_max)``, [:math:`\deg`]
2117
+ region : str
2118
+ 'F' for full disk (image provided every 10 m), and 'C' for CONUS (image provided every 5 m)
2119
+ path_write_img : None | pathlib.Path
2120
+ File path to save the CoCiP-GOES image.
2121
+
2122
+ Returns
2123
+ -------
2124
+ None | pathlib.Path
2125
+ File path of saved CoCiP-GOES image if ``path_write_img`` is provided.
2126
+ """
2127
+
2128
+ try:
2129
+ import cartopy.crs as ccrs
2130
+ from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter
2131
+ except ModuleNotFoundError as e:
2132
+ dependencies.raise_module_not_found_error(
2133
+ name="compare_cocip_with_goes function",
2134
+ package_name="cartopy",
2135
+ module_not_found_error=e,
2136
+ pycontrails_optional_package="goes",
2137
+ )
2138
+
2139
+ # Round `time` to nearest GOES image time slice
2140
+ if isinstance(time, np.timedelta64):
2141
+ time = pd.to_datetime(time)
2142
+
2143
+ if region == "F":
2144
+ time = time.round("10min")
2145
+ elif region == "C":
2146
+ time = time.round("5min")
2147
+ else:
2148
+ raise AssertionError("`region` only accepts inputs of `F` (full disk) or `C` (CONUS)")
2149
+
2150
+ _flight = GeoVectorDataset(flight)
2151
+ _contrail = GeoVectorDataset(contrail)
2152
+
2153
+ # Ensure the required columns are included in `flight_waypoints` and `contrails`
2154
+ _flight.ensure_vars(["flight_id", "waypoint"])
2155
+ _contrail.ensure_vars(
2156
+ ["flight_id", "waypoint", "sin_a", "cos_a", "width", "tau_contrail", "age_hours"]
2157
+ )
2158
+
2159
+ # Downselect `_flight` only to spatial domain covered by GOES full disk
2160
+ is_in_lon = _flight.dataframe["longitude"].between(spatial_bbox[0], spatial_bbox[2])
2161
+ is_in_lat = _flight.dataframe["latitude"].between(spatial_bbox[1], spatial_bbox[3])
2162
+ is_in_lon_lat = is_in_lon & is_in_lat
2163
+
2164
+ if not np.any(is_in_lon_lat):
2165
+ warnings.warn(
2166
+ "Flight trajectory does not intersect with the defined spatial bounding box or spatial "
2167
+ "domain covered by GOES."
2168
+ )
2169
+
2170
+ _flight = _flight.filter(is_in_lon_lat)
2171
+
2172
+ # Filter `_flight` if time bounds were previously defined.
2173
+ is_before_time = _flight["time"] < time
2174
+
2175
+ if not np.any(is_before_time):
2176
+ warnings.warn("No flight waypoints were recorded before the specified `time`.")
2177
+
2178
+ _flight = _flight.filter(is_before_time)
2179
+
2180
+ # Downselect `_contrail` only to include the filtered flight waypoints
2181
+ is_in_domain = _contrail.dataframe["waypoint"].isin(_flight["waypoint"])
2182
+
2183
+ if not np.any(is_in_domain):
2184
+ warnings.warn(
2185
+ "No persistent contrails were formed within the defined spatial bounding box."
2186
+ )
2187
+
2188
+ _contrail = _contrail.filter(is_in_domain)
2189
+
2190
+ # Download GOES image at `time`
2191
+ goes = GOES(region=region)
2192
+ da = goes.get(time)
2193
+ rgb, transform, extent = extract_goes_visualization(da)
2194
+ bbox = spatial_bbox[0], spatial_bbox[2], spatial_bbox[1], spatial_bbox[3]
2195
+
2196
+ # Calculate optimal figure dimensions
2197
+ d_lon = spatial_bbox[2] - spatial_bbox[0]
2198
+ d_lat = spatial_bbox[3] - spatial_bbox[1]
2199
+ x_dim = 9.99
2200
+ y_dim = x_dim * (d_lat / d_lon)
2201
+
2202
+ # Plot data
2203
+ fig = plt.figure(figsize=(1.2 * x_dim, y_dim))
2204
+ pc = ccrs.PlateCarree()
2205
+ ax = fig.add_subplot(projection=pc, extent=bbox)
2206
+ ax.coastlines() # type: ignore[attr-defined]
2207
+ ax.imshow(rgb, extent=extent, transform=transform)
2208
+
2209
+ ax.set_xticks([spatial_bbox[0], spatial_bbox[2]], crs=ccrs.PlateCarree())
2210
+ ax.set_yticks([spatial_bbox[1], spatial_bbox[3]], crs=ccrs.PlateCarree())
2211
+ lon_formatter = LongitudeFormatter(zero_direction_label=True)
2212
+ lat_formatter = LatitudeFormatter()
2213
+ ax.xaxis.set_major_formatter(lon_formatter)
2214
+ ax.yaxis.set_major_formatter(lat_formatter)
2215
+
2216
+ # Plot flight trajectory up to `time`
2217
+ ax.plot(_flight["longitude"], _flight["latitude"], c="k", linewidth=2.5)
2218
+ plt.legend(["Flight trajectory"])
2219
+
2220
+ # Plot persistent contrails at `time`
2221
+ is_time = (_contrail["time"] == time) & (~np.isnan(_contrail["age_hours"]))
2222
+ im = ax.scatter(
2223
+ _contrail["longitude"][is_time],
2224
+ _contrail["latitude"][is_time],
2225
+ c=_contrail["tau_contrail"][is_time],
2226
+ s=4,
2227
+ cmap="YlOrRd_r",
2228
+ vmin=0,
2229
+ vmax=0.2,
2230
+ )
2231
+ cbar = plt.colorbar(im)
2232
+ cbar.set_label(r"$\tau_{\rm contrail}$")
2233
+ ax.set_title(f"{time}")
2234
+ plt.tight_layout()
2235
+
2236
+ # return output path if `path_write_img` is not None
2237
+ if path_write_img is not None:
2238
+ t_str = time.strftime("%Y%m%d_%H%M%S")
2239
+ file_name = f"goes_{t_str}.png"
2240
+ output_path = path_write_img.joinpath(file_name)
2241
+ plt.savefig(output_path, dpi=150, bbox_inches="tight")
2242
+ plt.close()
2243
+
2244
+ return output_path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycontrails
3
- Version: 0.51.1
3
+ Version: 0.51.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
@@ -51,6 +51,7 @@ Requires-Dist: pytest >=8.2 ; extra == 'dev'
51
51
  Requires-Dist: pytest-cov >=2.11 ; extra == 'dev'
52
52
  Requires-Dist: requests >=2.25 ; extra == 'dev'
53
53
  Requires-Dist: ruff ==0.4.1 ; extra == 'dev'
54
+ Requires-Dist: setuptools ; extra == 'dev'
54
55
  Provides-Extra: docs
55
56
  Requires-Dist: doc8 >=1.1 ; extra == 'docs'
56
57
  Requires-Dist: furo >=2023.3 ; extra == 'docs'
@@ -1,5 +1,5 @@
1
1
  pycontrails/__init__.py,sha256=8WUs6hZAAIH1yKfwYJ8UEqNsk5voRyLmmD3Dje9DZaE,2055
2
- pycontrails/_version.py,sha256=gmP4X4NUxYBWytULG1EUTGL8LNF16D8DZ1omSI-P98c,429
2
+ pycontrails/_version.py,sha256=xMJiFm-L3Ds4ihKsGP2O4OOfKy4NICJsA72FioJ3YvQ,429
3
3
  pycontrails/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  pycontrails/core/__init__.py,sha256=eNypVTz1kHBSKAJX3CgfKw-VKrMRRkKTutmjSlrfeUs,870
5
5
  pycontrails/core/aircraft_performance.py,sha256=ikeJmdvFRDa1RdfR-JKfhQbiiIzL0c2vzcBmobmoxMs,22511
@@ -15,8 +15,8 @@ pycontrails/core/interpolation.py,sha256=Sp9s17i1QQx3jZwnwvt3vo6enWwlkYwTVKCE27N
15
15
  pycontrails/core/met.py,sha256=l0A1MEFrOUtYWO_ZHoHzYgqa1rmIh7fxA8PiwE26yT8,96251
16
16
  pycontrails/core/met_var.py,sha256=JzB7UhBLQyU4TuKZqemhpBHA6Dbt89BPYO2sYBLMkL4,9504
17
17
  pycontrails/core/models.py,sha256=VS-ct4xkojJIuqdPpT1ke1ZetNzv10nNx_Z_XalZyeo,40175
18
- pycontrails/core/polygon.py,sha256=iliIQv-EUpstP3nOEqgpqLhztW4UI_A4NeCGQuj0Ku8,18542
19
- pycontrails/core/rgi_cython.cp39-win_amd64.pyd,sha256=-WEt3DcyMcH2tgxh6imppOycjXO_0KEgM3wyNJaupQQ,257536
18
+ pycontrails/core/polygon.py,sha256=IwKnTRfKCgcOqbvKSsm-iJwd1HheS8sgsxAb6ufJy7c,18565
19
+ pycontrails/core/rgi_cython.cp39-win_amd64.pyd,sha256=kP83euCh1NtoX4UzMC93hcuohq39lveI2_Pj6UzrYIg,258560
20
20
  pycontrails/core/vector.py,sha256=MF0oWX0Ghp_G41A712VbU1GEKRNU_Pj9PtzMREPG5Z8,73916
21
21
  pycontrails/datalib/__init__.py,sha256=WnXqgv20SrHZLjFZ9qpQEwRnf0QvfZU-YvMqh7PAUwg,246
22
22
  pycontrails/datalib/goes.py,sha256=NVk6QFfHbGpOINlKlG6PR1Hn_LCmzP7k20VJQZXpVG8,27124
@@ -48,12 +48,12 @@ pycontrails/models/pcc.py,sha256=M5KhtRgdCP9pfDFgui7ibbijtRBTjx3QOJL_m1tQYfs,114
48
48
  pycontrails/models/pcr.py,sha256=G_0yR5PsCMeJBP6tZFi3M7A6Wcq8s71UvosdA7ozUkI,5502
49
49
  pycontrails/models/sac.py,sha256=Cj4Hi3324wjqLQ7I2CPVkrIh2Fq5W5pKpGrwhYADoHI,16420
50
50
  pycontrails/models/tau_cirrus.py,sha256=eXt3yRrcFBaZNNeH6ZOuU4XEZU2rOfrLKEOC7f0_Ywo,5194
51
- pycontrails/models/cocip/__init__.py,sha256=X_MlkJzQ-henQ0xGq-1bfCMajH6s9tlK5QLnN7yfQ68,929
51
+ pycontrails/models/cocip/__init__.py,sha256=miDxSFxN9PzL_ieSJb3BYeHmbKqZwGicCz1scNB5eW0,991
52
52
  pycontrails/models/cocip/cocip.py,sha256=s9j5UhPCaaxiJZDXUvQ2KnEgvQz2pMrRHlWKZijwRIw,100140
53
53
  pycontrails/models/cocip/cocip_params.py,sha256=T4IseK6KtY4hG3BuGZBtFgM90HCYecUXsb_QVEK6uGo,11670
54
54
  pycontrails/models/cocip/cocip_uncertainty.py,sha256=lksROIRLt-jxEdjJTiLP9Da-FYt1GjZKaIxwDaH2Ytg,12069
55
55
  pycontrails/models/cocip/contrail_properties.py,sha256=u6SvucHC6VtF2kujfSVFTfv0263t5uYpNOUJZAroEzc,57111
56
- pycontrails/models/cocip/output_formats.py,sha256=sYGYosAL6BQvntKXdeomAph-K6EKOgsI2VQynLEHxnM,79228
56
+ pycontrails/models/cocip/output_formats.py,sha256=VFWXGIDcWg98aQhMdstOhWlfhmHEUP582eHtyfcaFvw,85473
57
57
  pycontrails/models/cocip/radiative_forcing.py,sha256=SYmQ8lL8gpWbf6he2C9mKSjODtytbFcdnMdBM-LtBKE,46206
58
58
  pycontrails/models/cocip/radiative_heating.py,sha256=N7FTR20luERmokprdqMOl-d8-cTYZZ2ZSsTdxZnLHfs,19368
59
59
  pycontrails/models/cocip/unterstrasser_wake_vortex.py,sha256=Ymz-uO9vVhLIFwT9yuF5g1g3hcT-XWdryLsebSBqoVU,14976
@@ -92,9 +92,9 @@ pycontrails/utils/iteration.py,sha256=En2YY4NiNwCNtAVO8HL6tv9byBGKs8MKSI7R8P-gZy
92
92
  pycontrails/utils/json.py,sha256=xCv71CKVZNHk4MyoYC-hl7dXObXXbI7P8gcNCn3AUoU,6172
93
93
  pycontrails/utils/temp.py,sha256=5XXqQoEfWjz1OrhoOBZD5vkkCFeuq9LpZkyhc38gIeY,1159
94
94
  pycontrails/utils/types.py,sha256=gNG9cSZ3djW7jufg0h1fXM3kD24sBY6ENE6wsxY_Q6o,4937
95
- pycontrails-0.51.1.dist-info/LICENSE,sha256=HVr8JnZfTaA-12BfKUQZi5hdrB3awOwLWs5X_ga5QzA,10353
96
- pycontrails-0.51.1.dist-info/METADATA,sha256=DV-S88nuFZuvdNYedTdFfpc7A9_kQirr1jZqn5pmDsE,8527
97
- pycontrails-0.51.1.dist-info/NOTICE,sha256=qYeNEp8OjDK5jSW3hTlr9LQRjZeEhXQm0zDei5UFaYs,1969
98
- pycontrails-0.51.1.dist-info/WHEEL,sha256=Z6c-bE0pUM47a70GvqO_SvH_XXU0lm62gEAKtoNJ08A,100
99
- pycontrails-0.51.1.dist-info/top_level.txt,sha256=dwaYXVcMhF92QWtAYcLvL0k02vyBqwhsv92lYs2V6zQ,23
100
- pycontrails-0.51.1.dist-info/RECORD,,
95
+ pycontrails-0.51.2.dist-info/LICENSE,sha256=HVr8JnZfTaA-12BfKUQZi5hdrB3awOwLWs5X_ga5QzA,10353
96
+ pycontrails-0.51.2.dist-info/METADATA,sha256=qgSIf3DN0e3MemCUJtmRDKoAlSm5SO3bsvwYtxli3D0,8571
97
+ pycontrails-0.51.2.dist-info/NOTICE,sha256=qYeNEp8OjDK5jSW3hTlr9LQRjZeEhXQm0zDei5UFaYs,1969
98
+ pycontrails-0.51.2.dist-info/WHEEL,sha256=Z6c-bE0pUM47a70GvqO_SvH_XXU0lm62gEAKtoNJ08A,100
99
+ pycontrails-0.51.2.dist-info/top_level.txt,sha256=dwaYXVcMhF92QWtAYcLvL0k02vyBqwhsv92lYs2V6zQ,23
100
+ pycontrails-0.51.2.dist-info/RECORD,,