pycontrails 0.58.0__cp314-cp314-macosx_10_13_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.

Files changed (122) hide show
  1. pycontrails/__init__.py +70 -0
  2. pycontrails/_version.py +34 -0
  3. pycontrails/core/__init__.py +30 -0
  4. pycontrails/core/aircraft_performance.py +679 -0
  5. pycontrails/core/airports.py +228 -0
  6. pycontrails/core/cache.py +889 -0
  7. pycontrails/core/coordinates.py +174 -0
  8. pycontrails/core/fleet.py +483 -0
  9. pycontrails/core/flight.py +2185 -0
  10. pycontrails/core/flightplan.py +228 -0
  11. pycontrails/core/fuel.py +140 -0
  12. pycontrails/core/interpolation.py +702 -0
  13. pycontrails/core/met.py +2931 -0
  14. pycontrails/core/met_var.py +387 -0
  15. pycontrails/core/models.py +1321 -0
  16. pycontrails/core/polygon.py +549 -0
  17. pycontrails/core/rgi_cython.cpython-314-darwin.so +0 -0
  18. pycontrails/core/vector.py +2249 -0
  19. pycontrails/datalib/__init__.py +12 -0
  20. pycontrails/datalib/_met_utils/metsource.py +746 -0
  21. pycontrails/datalib/ecmwf/__init__.py +73 -0
  22. pycontrails/datalib/ecmwf/arco_era5.py +345 -0
  23. pycontrails/datalib/ecmwf/common.py +114 -0
  24. pycontrails/datalib/ecmwf/era5.py +554 -0
  25. pycontrails/datalib/ecmwf/era5_model_level.py +490 -0
  26. pycontrails/datalib/ecmwf/hres.py +804 -0
  27. pycontrails/datalib/ecmwf/hres_model_level.py +466 -0
  28. pycontrails/datalib/ecmwf/ifs.py +287 -0
  29. pycontrails/datalib/ecmwf/model_levels.py +435 -0
  30. pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +139 -0
  31. pycontrails/datalib/ecmwf/variables.py +268 -0
  32. pycontrails/datalib/geo_utils.py +261 -0
  33. pycontrails/datalib/gfs/__init__.py +28 -0
  34. pycontrails/datalib/gfs/gfs.py +656 -0
  35. pycontrails/datalib/gfs/variables.py +104 -0
  36. pycontrails/datalib/goes.py +757 -0
  37. pycontrails/datalib/himawari/__init__.py +27 -0
  38. pycontrails/datalib/himawari/header_struct.py +266 -0
  39. pycontrails/datalib/himawari/himawari.py +667 -0
  40. pycontrails/datalib/landsat.py +589 -0
  41. pycontrails/datalib/leo_utils/__init__.py +5 -0
  42. pycontrails/datalib/leo_utils/correction.py +266 -0
  43. pycontrails/datalib/leo_utils/landsat_metadata.py +300 -0
  44. pycontrails/datalib/leo_utils/search.py +250 -0
  45. pycontrails/datalib/leo_utils/sentinel_metadata.py +748 -0
  46. pycontrails/datalib/leo_utils/static/bq_roi_query.sql +6 -0
  47. pycontrails/datalib/leo_utils/vis.py +59 -0
  48. pycontrails/datalib/sentinel.py +650 -0
  49. pycontrails/datalib/spire/__init__.py +5 -0
  50. pycontrails/datalib/spire/exceptions.py +62 -0
  51. pycontrails/datalib/spire/spire.py +604 -0
  52. pycontrails/ext/bada.py +42 -0
  53. pycontrails/ext/cirium.py +14 -0
  54. pycontrails/ext/empirical_grid.py +140 -0
  55. pycontrails/ext/synthetic_flight.py +431 -0
  56. pycontrails/models/__init__.py +1 -0
  57. pycontrails/models/accf.py +425 -0
  58. pycontrails/models/apcemm/__init__.py +8 -0
  59. pycontrails/models/apcemm/apcemm.py +983 -0
  60. pycontrails/models/apcemm/inputs.py +226 -0
  61. pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +183 -0
  62. pycontrails/models/apcemm/utils.py +437 -0
  63. pycontrails/models/cocip/__init__.py +29 -0
  64. pycontrails/models/cocip/cocip.py +2742 -0
  65. pycontrails/models/cocip/cocip_params.py +305 -0
  66. pycontrails/models/cocip/cocip_uncertainty.py +291 -0
  67. pycontrails/models/cocip/contrail_properties.py +1530 -0
  68. pycontrails/models/cocip/output_formats.py +2270 -0
  69. pycontrails/models/cocip/radiative_forcing.py +1260 -0
  70. pycontrails/models/cocip/radiative_heating.py +520 -0
  71. pycontrails/models/cocip/unterstrasser_wake_vortex.py +508 -0
  72. pycontrails/models/cocip/wake_vortex.py +396 -0
  73. pycontrails/models/cocip/wind_shear.py +120 -0
  74. pycontrails/models/cocipgrid/__init__.py +9 -0
  75. pycontrails/models/cocipgrid/cocip_grid.py +2552 -0
  76. pycontrails/models/cocipgrid/cocip_grid_params.py +138 -0
  77. pycontrails/models/dry_advection.py +602 -0
  78. pycontrails/models/emissions/__init__.py +21 -0
  79. pycontrails/models/emissions/black_carbon.py +599 -0
  80. pycontrails/models/emissions/emissions.py +1353 -0
  81. pycontrails/models/emissions/ffm2.py +336 -0
  82. pycontrails/models/emissions/static/default-engine-uids.csv +239 -0
  83. pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +596 -0
  84. pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +215 -0
  85. pycontrails/models/extended_k15.py +1327 -0
  86. pycontrails/models/humidity_scaling/__init__.py +37 -0
  87. pycontrails/models/humidity_scaling/humidity_scaling.py +1075 -0
  88. pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
  89. pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
  90. pycontrails/models/issr.py +210 -0
  91. pycontrails/models/pcc.py +326 -0
  92. pycontrails/models/pcr.py +154 -0
  93. pycontrails/models/ps_model/__init__.py +18 -0
  94. pycontrails/models/ps_model/ps_aircraft_params.py +381 -0
  95. pycontrails/models/ps_model/ps_grid.py +701 -0
  96. pycontrails/models/ps_model/ps_model.py +1000 -0
  97. pycontrails/models/ps_model/ps_operational_limits.py +525 -0
  98. pycontrails/models/ps_model/static/ps-aircraft-params-20250328.csv +69 -0
  99. pycontrails/models/ps_model/static/ps-synonym-list-20250328.csv +104 -0
  100. pycontrails/models/sac.py +442 -0
  101. pycontrails/models/tau_cirrus.py +183 -0
  102. pycontrails/physics/__init__.py +1 -0
  103. pycontrails/physics/constants.py +117 -0
  104. pycontrails/physics/geo.py +1138 -0
  105. pycontrails/physics/jet.py +968 -0
  106. pycontrails/physics/static/iata-cargo-load-factors-20250221.csv +74 -0
  107. pycontrails/physics/static/iata-passenger-load-factors-20250221.csv +74 -0
  108. pycontrails/physics/thermo.py +551 -0
  109. pycontrails/physics/units.py +472 -0
  110. pycontrails/py.typed +0 -0
  111. pycontrails/utils/__init__.py +1 -0
  112. pycontrails/utils/dependencies.py +66 -0
  113. pycontrails/utils/iteration.py +13 -0
  114. pycontrails/utils/json.py +187 -0
  115. pycontrails/utils/temp.py +50 -0
  116. pycontrails/utils/types.py +163 -0
  117. pycontrails-0.58.0.dist-info/METADATA +180 -0
  118. pycontrails-0.58.0.dist-info/RECORD +122 -0
  119. pycontrails-0.58.0.dist-info/WHEEL +6 -0
  120. pycontrails-0.58.0.dist-info/licenses/LICENSE +178 -0
  121. pycontrails-0.58.0.dist-info/licenses/NOTICE +43 -0
  122. pycontrails-0.58.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,187 @@
1
+ """JSON utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import Any
7
+
8
+ import numpy as np
9
+ import pandas as pd
10
+
11
+
12
+ class NumpyEncoder(json.JSONEncoder):
13
+ """Custom JSONEncoder for numpy data types.
14
+
15
+ Examples
16
+ --------
17
+ >>> import json
18
+ >>> import numpy as np
19
+ >>> from pycontrails.utils.json import NumpyEncoder
20
+
21
+ >>> data = np.array([0, 1, 2, 3])
22
+ >>> json.dumps(data, cls=NumpyEncoder)
23
+ '[0, 1, 2, 3]'
24
+
25
+ >>> data = np.datetime64(1234567890, "s")
26
+ >>> json.dumps(data, cls=NumpyEncoder)
27
+ '"2009-02-13T23:31:30"'
28
+
29
+ Notes
30
+ -----
31
+ Adapted https://github.com/hmallen/numpyencoder/blob/master/numpyencoder/numpyencoder.py
32
+ """
33
+
34
+ def default(self, obj: Any) -> Any:
35
+ """Encode numpy data types.
36
+
37
+ This method overrides :meth:`default` on the JSONEncoder class.
38
+
39
+ Parameters
40
+ ----------
41
+ obj : Any
42
+ Object to encode.
43
+
44
+ Returns
45
+ -------
46
+ Any
47
+ Encoded object.
48
+ """
49
+ if isinstance(
50
+ obj,
51
+ np.int_
52
+ | np.intc
53
+ | np.intp
54
+ | np.int8
55
+ | np.int16
56
+ | np.int32
57
+ | np.int64
58
+ | np.uint8
59
+ | np.uint16
60
+ | np.uint32
61
+ | np.uint64,
62
+ ):
63
+ return int(obj)
64
+
65
+ if isinstance(obj, np.float16 | np.float32 | np.float64):
66
+ return float(obj)
67
+
68
+ # TODO: this is not easily reversible - np.timedelta64(str(np.timedelta64(1, "h"))) raises
69
+ if isinstance(obj, (np.timedelta64)):
70
+ return str(obj)
71
+
72
+ if isinstance(obj, (np.datetime64)):
73
+ return str(obj)
74
+
75
+ if isinstance(obj, np.complex64 | np.complex128):
76
+ return {"real": obj.real, "imag": obj.imag}
77
+
78
+ if isinstance(obj, np.ndarray):
79
+ return obj.tolist()
80
+
81
+ if isinstance(obj, (np.bool_)):
82
+ return bool(obj)
83
+
84
+ if isinstance(obj, (np.void)):
85
+ return None
86
+
87
+ if isinstance(obj, pd.Series | pd.Index):
88
+ return obj.to_numpy().tolist()
89
+
90
+ try:
91
+ return json.JSONEncoder.default(self, obj)
92
+
93
+ # last ditch attempt by looking for a to_json attribute
94
+ except TypeError as e:
95
+ try:
96
+ return obj.to_json
97
+ except AttributeError:
98
+ raise TypeError from e
99
+
100
+
101
+ def dataframe_to_geojson_points(
102
+ df: pd.DataFrame,
103
+ properties: list[str] | None = None,
104
+ filter_nan: bool | list[str] = False,
105
+ ) -> dict[str, Any]:
106
+ """Convert a pandas DataFrame to a GeoJSON-like dictionary.
107
+
108
+ This function create a Python representation of a GeoJSON FeatureCollection with Point features
109
+ based on a :class:`pandas.DataFrame` with geospatial coordinate columns.
110
+
111
+ Parameters
112
+ ----------
113
+ df : pd.DataFrame
114
+ Base dataframe.
115
+ Must contain geospatial coordinate columns ["longitude", "latitude", "altitude", "time"]
116
+ properties : list[str], optional
117
+ Specify columns to include feature properties.
118
+ By default, will use all column data that is not in the coordinate columns.
119
+ filter_nan : bool | list[str], optional
120
+ Filter out points with nan values in any columns, including coordinate columns.
121
+ If `list of str` is input, only `filter_nan` columns will be used for filtering,
122
+ allowing null values in the other columns.
123
+
124
+ Returns
125
+ -------
126
+ dict[str, Any]
127
+ Description
128
+
129
+ Raises
130
+ ------
131
+ KeyError
132
+ Raises if `properties` or `filter_nan` input contains a column label that does
133
+ not exist in `df`
134
+ """
135
+ # required columns
136
+ coord_cols = ["longitude", "latitude", "altitude", "time"]
137
+
138
+ # get all properties if not defined
139
+ if properties is None:
140
+ properties = [c for c in df.columns if c not in coord_cols]
141
+ elif [c for c in properties if c not in df.columns]:
142
+ raise KeyError(
143
+ f"{[c for c in properties if c not in df.columns]} do not exist in dataframe"
144
+ )
145
+
146
+ # downselect dataframe
147
+ cols = ["longitude", "latitude", "altitude", "time", *properties]
148
+ df = df[cols]
149
+
150
+ # filter out coords with nan values, or filter just on "filter_nan" labels
151
+ if isinstance(filter_nan, bool) and filter_nan:
152
+ df = df[np.all(~np.isnan(df[cols]), axis=1)]
153
+ elif isinstance(filter_nan, list):
154
+ if [c for c in filter_nan if c not in df.columns]:
155
+ raise KeyError(
156
+ f"{[c for c in filter_nan if c not in df.columns]} do not exist in dataframe"
157
+ )
158
+ df = df[np.all(~np.isnan(df[filter_nan]), axis=1)]
159
+
160
+ def row_to_feature(row: pd.Series) -> dict[str, str | dict[str, Any]]:
161
+ point = [
162
+ np.round(row.longitude, decimals=4) if not np.isnan(row.longitude) else None,
163
+ np.round(row.latitude, decimals=4) if not np.isnan(row.latitude) else None,
164
+ np.round(row.altitude, decimals=4) if not np.isnan(row.altitude) else None,
165
+ ]
166
+ # converting to int to allow JSON serialization
167
+ properties = {"time": int(row.time.timestamp())}
168
+ used_keys = ["time", "latitude", "longitude", "altitude"]
169
+ unused_keys = [k for k in row.keys() if k not in used_keys] # noqa: SIM118
170
+ properties.update(
171
+ {
172
+ k: (
173
+ row[k]
174
+ if not isinstance(row[k], float)
175
+ or (isinstance(row[k], float) and not np.isnan(row[k]))
176
+ else None
177
+ )
178
+ for k in unused_keys
179
+ }
180
+ )
181
+
182
+ geometry = {"type": "Point", "coordinates": point}
183
+ return {"type": "Feature", "geometry": geometry, "properties": properties}
184
+
185
+ features = []
186
+ df.apply(lambda row: features.append(row_to_feature(row)), axis=1)
187
+ return {"type": "FeatureCollection", "features": features}
@@ -0,0 +1,50 @@
1
+ """Temp utilities."""
2
+
3
+ import logging
4
+ import os
5
+ import tempfile
6
+ from collections.abc import Generator
7
+ from contextlib import contextmanager
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def temp_filename() -> str:
13
+ """Get a filename in the host computers temp directory.
14
+
15
+ More robust than using tempfile.NamedTemporaryFile()
16
+
17
+ Returns
18
+ -------
19
+ str
20
+ Temp filename
21
+
22
+ See Also
23
+ --------
24
+ temp_file : Context manager for temp file creation and cleanup
25
+ """
26
+ return os.path.join(tempfile.gettempdir(), os.urandom(24).hex())
27
+
28
+
29
+ def remove_tempfile(temp_filename: str) -> None:
30
+ """Remove temp file.
31
+
32
+ Parameters
33
+ ----------
34
+ temp_filename : str
35
+ Temp filename
36
+ """
37
+ try:
38
+ os.unlink(temp_filename)
39
+ except OSError as e:
40
+ logger.warning("Failed to delete temp file %s with error %s", temp_filename, e)
41
+
42
+
43
+ @contextmanager
44
+ def temp_file() -> Generator[str, None, None]:
45
+ """Get context manager for temp file creation and cleanup."""
46
+ filename = temp_filename()
47
+ try:
48
+ yield filename
49
+ finally:
50
+ remove_tempfile(filename)
@@ -0,0 +1,163 @@
1
+ """Convienence types."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ import sys
7
+ from collections.abc import Callable
8
+ from datetime import datetime
9
+ from typing import Any, TypeVar
10
+
11
+ import numpy as np
12
+ import numpy.typing as npt
13
+ import pandas as pd
14
+ import xarray as xr
15
+
16
+ #: Array like (np.ndarray, xr.DataArray)
17
+ ArrayLike = TypeVar("ArrayLike", np.ndarray, xr.DataArray)
18
+
19
+ #: Array or Float (np.ndarray, float)
20
+ ArrayOrFloat = TypeVar("ArrayOrFloat", np.ndarray, float)
21
+
22
+ #: Array like input (np.ndarray, xr.DataArray, float)
23
+ ArrayScalarLike = TypeVar("ArrayScalarLike", np.ndarray, xr.DataArray, float)
24
+
25
+ #: Datetime like input (datetime, pd.Timestamp, np.datetime64)
26
+ DatetimeLike = TypeVar("DatetimeLike", datetime, pd.Timestamp, np.datetime64, str)
27
+
28
+ # Crude fix for autodoc issue calling TypeVar.__dict__ on Python 3.13
29
+ if "sphinx" in sys.modules and sys.version_info >= (3, 13):
30
+ ArrayLike.__dict__ = {}
31
+ ArrayOrFloat.__dict__ = {}
32
+ ArrayScalarLike.__dict__ = {}
33
+ DatetimeLike.__dict__ = {}
34
+
35
+
36
+ def support_arraylike(
37
+ func: Callable[[npt.NDArray[np.floating]], npt.NDArray[np.floating]],
38
+ ) -> Callable[[ArrayScalarLike], ArrayScalarLike]:
39
+ """Extend a numpy universal function operating on arrays of floats.
40
+
41
+ This decorator allows `func` to support any ArrayScalarLike parameter and
42
+ keeps the return type consistent with the parameter.
43
+
44
+ Parameters
45
+ ----------
46
+ func : Callable[[ArrayScalarLike], np.ndarray]
47
+ A numpy `ufunc` taking in a single array with `float`-like dtype.
48
+ This decorator assumes `func` returns a numpy array.
49
+
50
+ Returns
51
+ -------
52
+ Callable[[ArrayScalarLike], ArrayScalarLike]
53
+ Extended function.
54
+
55
+ See Also
56
+ --------
57
+ - `numpy ufuncs <https://numpy.org/doc/stable/reference/ufuncs.html>`_
58
+ """
59
+
60
+ def wrapped(arr: ArrayScalarLike) -> ArrayScalarLike:
61
+ x = np.asarray(arr)
62
+
63
+ # Convert to float if not already
64
+ if x.dtype not in (np.float32, np.float64):
65
+ x = x.astype(np.float64)
66
+ ret = func(x)
67
+
68
+ # Numpy in, numpy out
69
+ if isinstance(arr, np.ndarray):
70
+ return ret
71
+
72
+ # Keep python native numeric types native
73
+ if isinstance(arr, float | int):
74
+ return ret.item()
75
+
76
+ # Recreate pd.Series
77
+ if isinstance(arr, pd.Series):
78
+ return pd.Series(data=ret, index=arr.index)
79
+
80
+ # Recreate xr.DataArray
81
+ if isinstance(arr, xr.DataArray):
82
+ return arr.copy(data=ret) # See documentation for xr.copy!
83
+
84
+ # Pass numpy `ret` through for anything else
85
+ return ret
86
+
87
+ # this line produces a mypy error starting on mypy version 1.1.0,
88
+ # likely due to changes in https://github.com/python/mypy/pull/16942
89
+ return functools.update_wrapper(wrapped, func) # type: ignore
90
+
91
+
92
+ def apply_nan_mask_to_arraylike(arr: ArrayLike, nan_mask: np.ndarray) -> ArrayLike:
93
+ """Apply ``nan_mask`` to ``arr`` while maintaining the type.
94
+
95
+ The parameter ``arr`` should have a ``float`` ``dtype``.
96
+
97
+ This function is tested against :class:`xr.DataArray`, :class:`pd.Series`, and
98
+ :class:`np.ndarray` types.
99
+
100
+ Parameters
101
+ ----------
102
+ arr : ArrayLike
103
+ Array with ``np.float64`` entries
104
+ nan_mask : np.ndarray
105
+ Boolean array of the same shape as ``arr``
106
+
107
+ Returns
108
+ -------
109
+ ArrayLike
110
+ Array ``arr`` with values in ``nan_mask`` set to ``np.nan``. The ``arr`` is
111
+ mutated in place if it is a :class:`np.ndarray`. For :class:`xr.DataArray`,
112
+ a copy is returned.
113
+
114
+ Notes
115
+ -----
116
+ When ``arr`` is a :class:`xr.DataArray`, this function keeps any ``attrs``
117
+ from ``arr`` in the returned instance.
118
+ """
119
+ if isinstance(arr, xr.DataArray):
120
+ # The previous implementation uses xr.where instead of arr.where
121
+ # There was some change in xarray 2022.6.0 that broke the former implementation
122
+ # Instead, use arr.where
123
+ return arr.where(~nan_mask, np.nan)
124
+
125
+ # If we want to avoid copying, use np.where(~nan_mask, arr, np.nan)
126
+ arr[nan_mask] = np.nan
127
+ return arr
128
+
129
+
130
+ _Object = TypeVar("_Object")
131
+
132
+
133
+ def type_guard(
134
+ obj: Any,
135
+ type_: type[_Object] | tuple[type[_Object], ...],
136
+ error_message: str | None = None,
137
+ ) -> _Object:
138
+ """Shortcut utility to type guard a variable with custom error message.
139
+
140
+ Parameters
141
+ ----------
142
+ obj : Any
143
+ Any variable object
144
+ type_ : Type[_Object]
145
+ Type of variable.
146
+ Can be a tuple of types
147
+ error_message : str, optional
148
+ Custom error message
149
+
150
+ Returns
151
+ -------
152
+ _Object
153
+ Returns the input object ensured to be ``type_``
154
+
155
+ Raises
156
+ ------
157
+ ValueError
158
+ Raises ValueError if ``obj`` is not ``type_``
159
+ """
160
+ if not isinstance(obj, type_):
161
+ raise TypeError(error_message or f"Object must be of type {type_}")
162
+
163
+ return obj
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.4
2
+ Name: pycontrails
3
+ Version: 0.58.0
4
+ Summary: Python library for modeling aviation climate impacts
5
+ Author-email: "Contrails.org" <py@contrails.org>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Changelog, https://py.contrails.org/changelog.html
8
+ Project-URL: Documentation, https://py.contrails.org
9
+ Project-URL: Issues, https://github.com/contrailcirrus/pycontrails/issues
10
+ Project-URL: Repository, https://github.com/contrailcirrus/pycontrails
11
+ Keywords: contrails,climate,aviation,geospatial
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
23
+ Classifier: Topic :: Scientific/Engineering :: GIS
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ License-File: NOTICE
29
+ Requires-Dist: dask>=2022.3
30
+ Requires-Dist: numpy>=1.22
31
+ Requires-Dist: pandas>=2.0
32
+ Requires-Dist: scipy>=1.12
33
+ Requires-Dist: typing-extensions>=4.5; python_version < "3.12"
34
+ Requires-Dist: xarray>=2022.3
35
+ Provides-Extra: complete
36
+ Requires-Dist: pycontrails[ecmwf,gcp,gfs,jupyter,pyproj,sat,vis,zarr]; extra == "complete"
37
+ Provides-Extra: dev
38
+ Requires-Dist: fastparquet>=0.8; extra == "dev"
39
+ Requires-Dist: ipdb>=0.13; extra == "dev"
40
+ Requires-Dist: memory_profiler; extra == "dev"
41
+ Requires-Dist: mypy>=1.8; extra == "dev"
42
+ Requires-Dist: mypy-extensions>=1.0; extra == "dev"
43
+ Requires-Dist: platformdirs>=3.0; extra == "dev"
44
+ Requires-Dist: pre-commit>=2.10; extra == "dev"
45
+ Requires-Dist: psutil; extra == "dev"
46
+ Requires-Dist: pyarrow>=5.0; extra == "dev"
47
+ Requires-Dist: pytest>=8.2; extra == "dev"
48
+ Requires-Dist: pytest-cov>=2.11; extra == "dev"
49
+ Requires-Dist: requests>=2.25; extra == "dev"
50
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
51
+ Provides-Extra: docs
52
+ Requires-Dist: doc8>=1.1; extra == "docs"
53
+ Requires-Dist: furo>=2023.3; extra == "docs"
54
+ Requires-Dist: myst-parser>=1.0; extra == "docs"
55
+ Requires-Dist: nb-clean>=3.2; extra == "docs"
56
+ Requires-Dist: nbsphinx>=0.9; extra == "docs"
57
+ Requires-Dist: nbval!=0.10.0,>=0.9.6; extra == "docs"
58
+ Requires-Dist: pytest-check-links>=0.8.0; extra == "docs"
59
+ Requires-Dist: sphinx>=4.2; extra == "docs"
60
+ Requires-Dist: sphinx-autobuild>=0.7; extra == "docs"
61
+ Requires-Dist: sphinxcontrib-bibtex>=2.2; extra == "docs"
62
+ Requires-Dist: sphinx_copybutton>=0.5; extra == "docs"
63
+ Requires-Dist: sphinxext.opengraph>=0.8; extra == "docs"
64
+ Provides-Extra: ecmwf
65
+ Requires-Dist: cdsapi>=0.4; extra == "ecmwf"
66
+ Requires-Dist: cfgrib>=0.9; extra == "ecmwf"
67
+ Requires-Dist: eccodes>=2.38; extra == "ecmwf"
68
+ Requires-Dist: ecmwf-api-client>=1.6; extra == "ecmwf"
69
+ Requires-Dist: netcdf4>=1.6.1; extra == "ecmwf"
70
+ Requires-Dist: platformdirs>=3.0; extra == "ecmwf"
71
+ Requires-Dist: requests>=2.25; extra == "ecmwf"
72
+ Provides-Extra: gcp
73
+ Requires-Dist: google-cloud-storage>=2.1; extra == "gcp"
74
+ Requires-Dist: platformdirs>=3.0; extra == "gcp"
75
+ Requires-Dist: tqdm>=4.61; extra == "gcp"
76
+ Provides-Extra: gfs
77
+ Requires-Dist: cfgrib>=0.9; extra == "gfs"
78
+ Requires-Dist: eccodes>=2.38; extra == "gfs"
79
+ Requires-Dist: netcdf4>=1.6.1; extra == "gfs"
80
+ Requires-Dist: platformdirs>=3.0; extra == "gfs"
81
+ Requires-Dist: tqdm>=4.61; extra == "gfs"
82
+ Provides-Extra: jupyter
83
+ Requires-Dist: ipywidgets>=7.6; extra == "jupyter"
84
+ Requires-Dist: jupyterlab>=2.2; extra == "jupyter"
85
+ Provides-Extra: sat
86
+ Requires-Dist: cartopy>=0.22; extra == "sat"
87
+ Requires-Dist: db-dtypes>=1.2; extra == "sat"
88
+ Requires-Dist: gcsfs>=2022.3; extra == "sat"
89
+ Requires-Dist: geojson>=3.1; extra == "sat"
90
+ Requires-Dist: geopandas>=1.1.1; extra == "sat"
91
+ Requires-Dist: google-cloud-bigquery>=3.23; extra == "sat"
92
+ Requires-Dist: google-cloud-bigquery-storage>=2.25; extra == "sat"
93
+ Requires-Dist: pillow>=10.3; extra == "sat"
94
+ Requires-Dist: pyproj>=3.5; extra == "sat"
95
+ Requires-Dist: rasterio>=1.3; extra == "sat"
96
+ Requires-Dist: s3fs>=2022.3; extra == "sat"
97
+ Requires-Dist: scikit-image>=0.18; extra == "sat"
98
+ Requires-Dist: shapely>=2.0; extra == "sat"
99
+ Provides-Extra: open3d
100
+ Requires-Dist: open3d>=0.14; extra == "open3d"
101
+ Provides-Extra: pyproj
102
+ Requires-Dist: pyproj>=3.5; extra == "pyproj"
103
+ Provides-Extra: vis
104
+ Requires-Dist: matplotlib>=3.3; extra == "vis"
105
+ Requires-Dist: opencv-python-headless>=4.5; extra == "vis"
106
+ Requires-Dist: scikit-learn>=0.23; extra == "vis"
107
+ Requires-Dist: scikit-image>=0.18; extra == "vis"
108
+ Requires-Dist: seaborn>=0.11; extra == "vis"
109
+ Requires-Dist: shapely>=2.0; extra == "vis"
110
+ Provides-Extra: zarr
111
+ Requires-Dist: fsspec>=2022.7.1; extra == "zarr"
112
+ Requires-Dist: gcsfs>=2022.7.1; extra == "zarr"
113
+ Requires-Dist: zarr>=2.12; extra == "zarr"
114
+ Dynamic: license-file
115
+
116
+ # pycontrails
117
+
118
+ > Python library for modeling aviation climate impacts
119
+
120
+ | | |
121
+ |---------------|-------------------------------------------------------------------|
122
+ | **Version** | [![PyPI version](https://img.shields.io/pypi/v/pycontrails.svg)](https://pypi.python.org/pypi/pycontrails) [![conda-forge version](https://anaconda.org/conda-forge/pycontrails/badges/version.svg)](https://anaconda.org/conda-forge/pycontrails) [![Supported python versions](https://img.shields.io/pypi/pyversions/pycontrails.svg)](https://pypi.python.org/pypi/pycontrails) |
123
+ | **Citation** | [![DOI](https://zenodo.org/badge/617248930.svg)](https://zenodo.org/badge/latestdoi/617248930) |
124
+ | **Tests** | [![Unit test](https://github.com/contrailcirrus/pycontrails/actions/workflows/test.yaml/badge.svg)](https://github.com/contrailcirrus/pycontrails/actions/workflows/test.yaml) [![Docs](https://github.com/contrailcirrus/pycontrails/actions/workflows/docs.yaml/badge.svg?event=push)](https://github.com/contrailcirrus/pycontrails/actions/workflows/docs.yaml) [![Release](https://github.com/contrailcirrus/pycontrails/actions/workflows/release.yaml/badge.svg)](https://github.com/contrailcirrus/pycontrails/actions/workflows/release.yaml) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/contrailcirrus/pycontrails/badge)](https://securityscorecards.dev/viewer?uri=github.com/contrailcirrus/pycontrails)|
125
+ | **License** | [![Apache License 2.0](https://img.shields.io/pypi/l/pycontrails.svg)](https://github.com/contrailcirrus/pycontrails/blob/main/LICENSE) |
126
+ | **Community** | [![Github Discussions](https://img.shields.io/github/discussions/contrailcirrus/pycontrails)](https://github.com/contrailcirrus/pycontrails/discussions) [![Github Issues](https://img.shields.io/github/issues/contrailcirrus/pycontrails)](https://github.com/contrailcirrus/pycontrails/issues) [![Github PRs](https://img.shields.io/github/issues-pr/contrailcirrus/pycontrails)](https://github.com/contrailcirrus/pycontrails/pulls) |
127
+
128
+ **pycontrails** is an open source project and Python package for modeling aircraft contrails and other
129
+ aviation related climate impacts.
130
+
131
+ `pycontrails` defines common [data structures](https://py.contrails.org/api.html#data) and [interfaces](https://py.contrails.org/api.html#datalib) to efficiently build and run [models](https://py.contrails.org/api.html#models) of aircraft performance, emissions, and radiative forcing.
132
+
133
+ ## Documentation
134
+
135
+ Documentation and examples available at [py.contrails.org](https://py.contrails.org/).
136
+
137
+ <!-- Try out an [interactive Colab Notebook](). -->
138
+
139
+ ## Install
140
+
141
+ ### Install with pip
142
+
143
+ You can install pycontrails from PyPI with `pip` (Python 3.11 or later required):
144
+
145
+ ```bash
146
+ $ pip install pycontrails
147
+
148
+ # install with all optional dependencies
149
+ $ pip install "pycontrails[complete]"
150
+ ```
151
+
152
+ Install the latest development version directly from GitHub:
153
+
154
+ ```bash
155
+ pip install git+https://github.com/contrailcirrus/pycontrails.git
156
+ ```
157
+
158
+ ### Install with conda
159
+
160
+ You can install pycontrails from the [conda-forge](https://conda-forge.org/) channel with `conda` (or other `conda`-like package managers such as `mamba`):
161
+
162
+ ```bash
163
+ conda install -c conda-forge pycontrails
164
+ ```
165
+
166
+ The conda-forge package includes all optional runtime dependencies.
167
+
168
+ See more installation options in the [install documentation](https://py.contrails.org/install).
169
+
170
+ ## Get Involved
171
+
172
+ - Ask questions, discuss models, and present ideas in [GitHub Discussions](https://github.com/contrailcirrus/pycontrails/discussions).
173
+ - Report bugs or suggest changes in [GitHub Issues](https://github.com/contrailcirrus/pycontrails/issues).
174
+ - Review the [contributing guidelines](https://py.contrails.org/contributing.html) and contribute improvements as [Pull Requests](https://github.com/contrailcirrus/pycontrails/pulls).
175
+
176
+ ## License
177
+
178
+ [Apache License 2.0](https://github.com/contrailcirrus/pycontrails/blob/main/LICENSE)
179
+
180
+ Additional attributions in [NOTICE](https://github.com/contrailcirrus/pycontrails/blob/main/NOTICE).