pycontrails 0.51.1__cp39-cp39-macosx_10_9_x86_64.whl → 0.51.2__cp39-cp39-macosx_10_9_x86_64.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,20 +1,20 @@
1
- pycontrails-0.51.1.dist-info/RECORD,,
2
- pycontrails-0.51.1.dist-info/LICENSE,sha256=gJ-h7SFFD1mCfR6a7HILvEtodDT6Iig8bLXdgqR6ucA,10175
3
- pycontrails-0.51.1.dist-info/WHEEL,sha256=wEvD9HODgqXG21zAA07x3Gh0qpNEHOQ7qzjMqXvopac,109
4
- pycontrails-0.51.1.dist-info/NOTICE,sha256=gKI8DcN1WhiXB2SFRKDogcjONldGubTvBxiOYdC4CXU,1926
5
- pycontrails-0.51.1.dist-info/top_level.txt,sha256=dwaYXVcMhF92QWtAYcLvL0k02vyBqwhsv92lYs2V6zQ,23
6
- pycontrails-0.51.1.dist-info/METADATA,sha256=lhvTJXjoe4RWXxzCepstWZr3jUl5KSbY1cksSS4yu-Q,8366
7
- pycontrails/_version.py,sha256=VFAdktfJQ1HGHeBX5jprHcVJQgl3ZamLz76UBdxPqNE,413
1
+ pycontrails-0.51.2.dist-info/RECORD,,
2
+ pycontrails-0.51.2.dist-info/LICENSE,sha256=gJ-h7SFFD1mCfR6a7HILvEtodDT6Iig8bLXdgqR6ucA,10175
3
+ pycontrails-0.51.2.dist-info/WHEEL,sha256=wEvD9HODgqXG21zAA07x3Gh0qpNEHOQ7qzjMqXvopac,109
4
+ pycontrails-0.51.2.dist-info/NOTICE,sha256=gKI8DcN1WhiXB2SFRKDogcjONldGubTvBxiOYdC4CXU,1926
5
+ pycontrails-0.51.2.dist-info/top_level.txt,sha256=dwaYXVcMhF92QWtAYcLvL0k02vyBqwhsv92lYs2V6zQ,23
6
+ pycontrails-0.51.2.dist-info/METADATA,sha256=GrnTFo2vRstZA-G5KqvUe070DENl48rZUYrXVPjA2BM,8409
7
+ pycontrails/_version.py,sha256=NAimol_13XfyyQAJabjsIQxFxJiaGc5BgWOof3jZQM8,413
8
8
  pycontrails/__init__.py,sha256=c_Vtz7CvdiVAL8ggluash9-8tGcLO_5Vvu-3_Ie47CE,1985
9
9
  pycontrails/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  pycontrails/core/vector.py,sha256=P61Rv1M040A1SRHmdWVR_RfXcWa6faM330n-9499ilI,71722
11
- pycontrails/core/rgi_cython.cpython-39-darwin.so,sha256=B3RlFcwspFZKbptRa1COYdYZhdbPMqIec72pKVZdUM0,315696
11
+ pycontrails/core/rgi_cython.cpython-39-darwin.so,sha256=xfMh7E-kMy0r_tGtYXSpdefBxyieqiikI_ftwM-89N4,315696
12
12
  pycontrails/core/models.py,sha256=sipUAH_r0A1TxQ0yBjaPj8WC33Piw34ABHyrmRePfhg,39003
13
13
  pycontrails/core/interpolation.py,sha256=FFYdUnTzGnkjoGs-FKsK3Y3nSK5lQI-mpq5HPALZ-y4,25495
14
14
  pycontrails/core/fleet.py,sha256=84oTb8RJ3-bPVvZn3O2ljMEZLwJ9Q-E455ZzQJ4QaQU,16075
15
15
  pycontrails/core/flight.py,sha256=jpd1bfdzUzNuuE-7pDraRC5I9kYetSwFUAMRYwMVxzw,83143
16
16
  pycontrails/core/fuel.py,sha256=kJZ3P1lPm1L6rdPREM55XQ-VfJ_pt35cP4sO2Nnvmjs,4332
17
- pycontrails/core/polygon.py,sha256=bLddqnsaA7XVXFcEVXR3V1tVIu5qQ8sxPUjFbwt0lO8,17993
17
+ pycontrails/core/polygon.py,sha256=NhoK91oVE2pse1kw2mkkhxxQpJrvBld8ofTMCwNH_h8,18016
18
18
  pycontrails/core/datalib.py,sha256=m39gKxdhy9KSBhwWlrzEc5z-tTqPfcs7bPcqSxbU0k0,23971
19
19
  pycontrails/core/cache.py,sha256=rCBZiRSVoFkRwf_ay7O-eba2PaYoXdlJSz1znZPuOQk,27957
20
20
  pycontrails/core/__init__.py,sha256=4ZE7x1gMa_Q7GcgcWpPP9fQ-sTulCXWmMjsCJ0odakY,840
@@ -74,8 +74,8 @@ pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq,sha2
74
74
  pycontrails/models/cocip/radiative_forcing.py,sha256=ERuFcYMo0_1iiOricnZ8D4ext23bMnTCeZwg9vd6Vzs,44944
75
75
  pycontrails/models/cocip/wind_shear.py,sha256=p8d3iaNzxPA3MoxFEM1ZDKt0aticoD6U9cv0QmbuBzs,3860
76
76
  pycontrails/models/cocip/cocip.py,sha256=0ILMcjbgsM00rCXAeo9UkSnUsmvq1XvORhNPI-ReNcM,97591
77
- pycontrails/models/cocip/output_formats.py,sha256=d9naGliEEVuk2ER0KZEY5R2FHQZIY5NcP6PamlHcBM0,77149
78
- pycontrails/models/cocip/__init__.py,sha256=7Wy_CnmVqg_Gpg2UhIlisJOJ3naL6c5BBzTSJqdbiM4,902
77
+ pycontrails/models/cocip/output_formats.py,sha256=e3K-23EvEE2z9PuHNr2OQhwvN8_PYmNmR7Li-dsYZq8,83229
78
+ pycontrails/models/cocip/__init__.py,sha256=jd-9Tq20s1kwQBlxsYfZLi3hlT5MnWOY2XsPazq1fgE,962
79
79
  pycontrails/models/cocip/cocip_params.py,sha256=R4bewge3xLgWYbBbGwd8e8r0NlaFx2IaQPZEfiqJZRI,11392
80
80
  pycontrails/models/cocip/wake_vortex.py,sha256=i_OF193KK5BCMdVCgK0_4Aqn55f6rnL4WDWEac8um-w,14421
81
81
  pycontrails/models/cocip/cocip_uncertainty.py,sha256=4JtlCVFpLBnPRlvyEp9QFpRfHFK9joSTnxe0NJdONG4,11784