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.
- pycontrails/__init__.py +70 -0
- pycontrails/_version.py +34 -0
- pycontrails/core/__init__.py +30 -0
- pycontrails/core/aircraft_performance.py +679 -0
- pycontrails/core/airports.py +228 -0
- pycontrails/core/cache.py +889 -0
- pycontrails/core/coordinates.py +174 -0
- pycontrails/core/fleet.py +483 -0
- pycontrails/core/flight.py +2185 -0
- pycontrails/core/flightplan.py +228 -0
- pycontrails/core/fuel.py +140 -0
- pycontrails/core/interpolation.py +702 -0
- pycontrails/core/met.py +2931 -0
- pycontrails/core/met_var.py +387 -0
- pycontrails/core/models.py +1321 -0
- pycontrails/core/polygon.py +549 -0
- pycontrails/core/rgi_cython.cpython-314-darwin.so +0 -0
- pycontrails/core/vector.py +2249 -0
- pycontrails/datalib/__init__.py +12 -0
- pycontrails/datalib/_met_utils/metsource.py +746 -0
- pycontrails/datalib/ecmwf/__init__.py +73 -0
- pycontrails/datalib/ecmwf/arco_era5.py +345 -0
- pycontrails/datalib/ecmwf/common.py +114 -0
- pycontrails/datalib/ecmwf/era5.py +554 -0
- pycontrails/datalib/ecmwf/era5_model_level.py +490 -0
- pycontrails/datalib/ecmwf/hres.py +804 -0
- pycontrails/datalib/ecmwf/hres_model_level.py +466 -0
- pycontrails/datalib/ecmwf/ifs.py +287 -0
- pycontrails/datalib/ecmwf/model_levels.py +435 -0
- pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +139 -0
- pycontrails/datalib/ecmwf/variables.py +268 -0
- pycontrails/datalib/geo_utils.py +261 -0
- pycontrails/datalib/gfs/__init__.py +28 -0
- pycontrails/datalib/gfs/gfs.py +656 -0
- pycontrails/datalib/gfs/variables.py +104 -0
- pycontrails/datalib/goes.py +757 -0
- pycontrails/datalib/himawari/__init__.py +27 -0
- pycontrails/datalib/himawari/header_struct.py +266 -0
- pycontrails/datalib/himawari/himawari.py +667 -0
- pycontrails/datalib/landsat.py +589 -0
- pycontrails/datalib/leo_utils/__init__.py +5 -0
- pycontrails/datalib/leo_utils/correction.py +266 -0
- pycontrails/datalib/leo_utils/landsat_metadata.py +300 -0
- pycontrails/datalib/leo_utils/search.py +250 -0
- pycontrails/datalib/leo_utils/sentinel_metadata.py +748 -0
- pycontrails/datalib/leo_utils/static/bq_roi_query.sql +6 -0
- pycontrails/datalib/leo_utils/vis.py +59 -0
- pycontrails/datalib/sentinel.py +650 -0
- pycontrails/datalib/spire/__init__.py +5 -0
- pycontrails/datalib/spire/exceptions.py +62 -0
- pycontrails/datalib/spire/spire.py +604 -0
- pycontrails/ext/bada.py +42 -0
- pycontrails/ext/cirium.py +14 -0
- pycontrails/ext/empirical_grid.py +140 -0
- pycontrails/ext/synthetic_flight.py +431 -0
- pycontrails/models/__init__.py +1 -0
- pycontrails/models/accf.py +425 -0
- pycontrails/models/apcemm/__init__.py +8 -0
- pycontrails/models/apcemm/apcemm.py +983 -0
- pycontrails/models/apcemm/inputs.py +226 -0
- pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +183 -0
- pycontrails/models/apcemm/utils.py +437 -0
- pycontrails/models/cocip/__init__.py +29 -0
- pycontrails/models/cocip/cocip.py +2742 -0
- pycontrails/models/cocip/cocip_params.py +305 -0
- pycontrails/models/cocip/cocip_uncertainty.py +291 -0
- pycontrails/models/cocip/contrail_properties.py +1530 -0
- pycontrails/models/cocip/output_formats.py +2270 -0
- pycontrails/models/cocip/radiative_forcing.py +1260 -0
- pycontrails/models/cocip/radiative_heating.py +520 -0
- pycontrails/models/cocip/unterstrasser_wake_vortex.py +508 -0
- pycontrails/models/cocip/wake_vortex.py +396 -0
- pycontrails/models/cocip/wind_shear.py +120 -0
- pycontrails/models/cocipgrid/__init__.py +9 -0
- pycontrails/models/cocipgrid/cocip_grid.py +2552 -0
- pycontrails/models/cocipgrid/cocip_grid_params.py +138 -0
- pycontrails/models/dry_advection.py +602 -0
- pycontrails/models/emissions/__init__.py +21 -0
- pycontrails/models/emissions/black_carbon.py +599 -0
- pycontrails/models/emissions/emissions.py +1353 -0
- pycontrails/models/emissions/ffm2.py +336 -0
- pycontrails/models/emissions/static/default-engine-uids.csv +239 -0
- pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +596 -0
- pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +215 -0
- pycontrails/models/extended_k15.py +1327 -0
- pycontrails/models/humidity_scaling/__init__.py +37 -0
- pycontrails/models/humidity_scaling/humidity_scaling.py +1075 -0
- pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
- pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
- pycontrails/models/issr.py +210 -0
- pycontrails/models/pcc.py +326 -0
- pycontrails/models/pcr.py +154 -0
- pycontrails/models/ps_model/__init__.py +18 -0
- pycontrails/models/ps_model/ps_aircraft_params.py +381 -0
- pycontrails/models/ps_model/ps_grid.py +701 -0
- pycontrails/models/ps_model/ps_model.py +1000 -0
- pycontrails/models/ps_model/ps_operational_limits.py +525 -0
- pycontrails/models/ps_model/static/ps-aircraft-params-20250328.csv +69 -0
- pycontrails/models/ps_model/static/ps-synonym-list-20250328.csv +104 -0
- pycontrails/models/sac.py +442 -0
- pycontrails/models/tau_cirrus.py +183 -0
- pycontrails/physics/__init__.py +1 -0
- pycontrails/physics/constants.py +117 -0
- pycontrails/physics/geo.py +1138 -0
- pycontrails/physics/jet.py +968 -0
- pycontrails/physics/static/iata-cargo-load-factors-20250221.csv +74 -0
- pycontrails/physics/static/iata-passenger-load-factors-20250221.csv +74 -0
- pycontrails/physics/thermo.py +551 -0
- pycontrails/physics/units.py +472 -0
- pycontrails/py.typed +0 -0
- pycontrails/utils/__init__.py +1 -0
- pycontrails/utils/dependencies.py +66 -0
- pycontrails/utils/iteration.py +13 -0
- pycontrails/utils/json.py +187 -0
- pycontrails/utils/temp.py +50 -0
- pycontrails/utils/types.py +163 -0
- pycontrails-0.58.0.dist-info/METADATA +180 -0
- pycontrails-0.58.0.dist-info/RECORD +122 -0
- pycontrails-0.58.0.dist-info/WHEEL +6 -0
- pycontrails-0.58.0.dist-info/licenses/LICENSE +178 -0
- pycontrails-0.58.0.dist-info/licenses/NOTICE +43 -0
- pycontrails-0.58.0.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"""Wave-vortex downwash functions.
|
|
2
|
+
|
|
3
|
+
This module includes equations from the original CoCiP model
|
|
4
|
+
:cite:`schumannContrailCirrusPrediction2012`. An alternative set of equations based on
|
|
5
|
+
:cite:`unterstrasserPropertiesYoungContrails2016` is available in
|
|
6
|
+
:py:mod:`unterstrasser_wake_vortex`.
|
|
7
|
+
|
|
8
|
+
Unterstrasser Notes
|
|
9
|
+
-------------------
|
|
10
|
+
|
|
11
|
+
Improved estimation of the survival fraction of the contrail ice crystal number ``f_surv``
|
|
12
|
+
during the wake-vortex phase. This is a parameterised model that is developed based on
|
|
13
|
+
outputs provided by large eddy simulations.
|
|
14
|
+
|
|
15
|
+
For comparison, CoCiP assumes that ``f_surv`` is equal to the change in the contrail ice water
|
|
16
|
+
content (by mass) before and after the wake vortex phase. However, for larger (smaller) ice
|
|
17
|
+
particles, their survival fraction by number could be smaller (larger) than their survival fraction
|
|
18
|
+
by mass. This is particularly important in the "soot-poor" scenario, for example, in cleaner
|
|
19
|
+
lean-burn engines where their soot emissions can be 3-4 orders of magnitude lower than conventional
|
|
20
|
+
RQL engines.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import numpy as np
|
|
27
|
+
import numpy.typing as npt
|
|
28
|
+
|
|
29
|
+
from pycontrails.models.cocip import wind_shear
|
|
30
|
+
from pycontrails.physics import constants, thermo
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def max_downward_displacement(
|
|
34
|
+
wingspan: npt.NDArray[np.floating] | float,
|
|
35
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
36
|
+
aircraft_mass: npt.NDArray[np.floating] | float,
|
|
37
|
+
air_temperature: npt.NDArray[np.floating],
|
|
38
|
+
dT_dz: npt.NDArray[np.floating],
|
|
39
|
+
ds_dz: npt.NDArray[np.floating],
|
|
40
|
+
air_pressure: npt.NDArray[np.floating],
|
|
41
|
+
effective_vertical_resolution: float,
|
|
42
|
+
wind_shear_enhancement_exponent: npt.NDArray[np.floating] | float,
|
|
43
|
+
) -> npt.NDArray[np.floating]:
|
|
44
|
+
"""
|
|
45
|
+
Calculate the maximum contrail downward displacement after the wake vortex phase.
|
|
46
|
+
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
wingspan : npt.NDArray[np.floating] | float
|
|
50
|
+
aircraft wingspan, [:math:`m`]
|
|
51
|
+
true_airspeed : npt.NDArray[np.floating]
|
|
52
|
+
true airspeed for each waypoint, [:math:`m s^{-1}`]
|
|
53
|
+
aircraft_mass : npt.NDArray[np.floating] | float
|
|
54
|
+
aircraft mass for each waypoint, [:math:`kg`]
|
|
55
|
+
air_temperature : npt.NDArray[np.floating]
|
|
56
|
+
ambient temperature for each waypoint, [:math:`K`]
|
|
57
|
+
dT_dz : npt.NDArray[np.floating]
|
|
58
|
+
potential temperature gradient, [:math:`K m^{-1}`]
|
|
59
|
+
ds_dz : npt.NDArray[np.floating]
|
|
60
|
+
Difference in wind speed over dz in the atmosphere, [:math:`m s^{-1} / m`]
|
|
61
|
+
air_pressure : npt.NDArray[np.floating]
|
|
62
|
+
pressure altitude at each waypoint, [:math:`Pa`]
|
|
63
|
+
effective_vertical_resolution: float
|
|
64
|
+
Passed through to :func:`wind_shear.wind_shear_enhancement_factor`, [:math:`m`]
|
|
65
|
+
wind_shear_enhancement_exponent: npt.NDArray[np.floating] | float
|
|
66
|
+
Passed through to :func:`wind_shear.wind_shear_enhancement_factor`
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
npt.NDArray[np.floating]
|
|
71
|
+
Max contrail downward displacement after the wake vortex phase, [:math:`m`]
|
|
72
|
+
|
|
73
|
+
References
|
|
74
|
+
----------
|
|
75
|
+
- :cite:`holzapfelProbabilisticTwoPhaseWake2003`
|
|
76
|
+
- :cite:`schumannContrailCirrusPrediction2012`
|
|
77
|
+
"""
|
|
78
|
+
rho_air = thermo.rho_d(air_temperature, air_pressure)
|
|
79
|
+
n_bv = thermo.brunt_vaisala_frequency(air_pressure, air_temperature, dT_dz)
|
|
80
|
+
t_0 = effective_time_scale(wingspan, true_airspeed, aircraft_mass, rho_air)
|
|
81
|
+
|
|
82
|
+
dz_max_strong = downward_displacement_strongly_stratified(
|
|
83
|
+
wingspan, true_airspeed, aircraft_mass, rho_air, n_bv
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
is_weakly_stratified = n_bv * t_0 < 0.8
|
|
87
|
+
if isinstance(wingspan, np.ndarray):
|
|
88
|
+
wingspan = wingspan[is_weakly_stratified]
|
|
89
|
+
if isinstance(aircraft_mass, np.ndarray):
|
|
90
|
+
aircraft_mass = aircraft_mass[is_weakly_stratified]
|
|
91
|
+
|
|
92
|
+
dz_max_weak = downward_displacement_weakly_stratified(
|
|
93
|
+
wingspan=wingspan,
|
|
94
|
+
true_airspeed=true_airspeed[is_weakly_stratified],
|
|
95
|
+
aircraft_mass=aircraft_mass,
|
|
96
|
+
rho_air=rho_air[is_weakly_stratified],
|
|
97
|
+
n_bv=n_bv[is_weakly_stratified],
|
|
98
|
+
dz_max_strong=dz_max_strong[is_weakly_stratified],
|
|
99
|
+
ds_dz=ds_dz[is_weakly_stratified],
|
|
100
|
+
t_0=t_0[is_weakly_stratified],
|
|
101
|
+
effective_vertical_resolution=effective_vertical_resolution,
|
|
102
|
+
wind_shear_enhancement_exponent=wind_shear_enhancement_exponent,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
dz_max_strong[is_weakly_stratified] = dz_max_weak
|
|
106
|
+
return dz_max_strong
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def effective_time_scale(
|
|
110
|
+
wingspan: npt.NDArray[np.floating] | float,
|
|
111
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
112
|
+
aircraft_mass: npt.NDArray[np.floating] | float,
|
|
113
|
+
rho_air: npt.NDArray[np.floating],
|
|
114
|
+
) -> npt.NDArray[np.floating]:
|
|
115
|
+
r"""
|
|
116
|
+
Calculate the effective time scale of the wake vortex.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
wingspan : npt.NDArray[np.floating] | float
|
|
121
|
+
aircraft wingspan, [:math:`m`]
|
|
122
|
+
true_airspeed : npt.NDArray[np.floating]
|
|
123
|
+
true airspeed for each waypoint, [:math:`m \ s^{-1}`]
|
|
124
|
+
aircraft_mass : npt.NDArray[np.floating] | float
|
|
125
|
+
aircraft mass for each waypoint, [:math:`kg`]
|
|
126
|
+
rho_air : npt.NDArray[np.floating]
|
|
127
|
+
density of air for each waypoint, [:math:`kg \ m^{-3}`]
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
npt.NDArray[np.floating]
|
|
132
|
+
Wake vortex effective time scale, [:math:`s`]
|
|
133
|
+
|
|
134
|
+
Notes
|
|
135
|
+
-----
|
|
136
|
+
See section 2.5 (pg 547) of :cite:`schumannContrailCirrusPrediction2012`.
|
|
137
|
+
|
|
138
|
+
References
|
|
139
|
+
----------
|
|
140
|
+
- :cite:`schumannContrailCirrusPrediction2012`
|
|
141
|
+
"""
|
|
142
|
+
c = np.pi**4 / 32
|
|
143
|
+
return c * wingspan**3 * rho_air * true_airspeed / (aircraft_mass * constants.g)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def downward_displacement_strongly_stratified(
|
|
147
|
+
wingspan: npt.NDArray[np.floating] | float,
|
|
148
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
149
|
+
aircraft_mass: npt.NDArray[np.floating] | float,
|
|
150
|
+
rho_air: npt.NDArray[np.floating],
|
|
151
|
+
n_bv: npt.NDArray[np.floating],
|
|
152
|
+
) -> npt.NDArray[np.floating]:
|
|
153
|
+
"""
|
|
154
|
+
Calculate the maximum contrail downward displacement under strongly stratified conditions.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
wingspan : npt.NDArray[np.floating] | float
|
|
159
|
+
aircraft wingspan, [:math:`m`]
|
|
160
|
+
true_airspeed : npt.NDArray[np.floating]
|
|
161
|
+
true airspeed for each waypoint, [:math:`m s^{-1}`]
|
|
162
|
+
aircraft_mass : npt.NDArray[np.floating] | float
|
|
163
|
+
aircraft mass for each waypoint, [:math:`kg`]
|
|
164
|
+
rho_air : npt.NDArray[np.floating]
|
|
165
|
+
density of air for each waypoint, [:math:`kg m^{-3}`]
|
|
166
|
+
n_bv : npt.NDArray[np.floating]
|
|
167
|
+
Brunt-Vaisaila frequency, [:math:`s^{-1}`]
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
npt.NDArray[np.floating]
|
|
172
|
+
Maximum contrail downward displacement, strongly stratified conditions, [:math:`m`]
|
|
173
|
+
|
|
174
|
+
Notes
|
|
175
|
+
-----
|
|
176
|
+
See section 2.5 (pg 547 - 548) of :cite:`schumannContrailCirrusPrediction2012`.
|
|
177
|
+
|
|
178
|
+
References
|
|
179
|
+
----------
|
|
180
|
+
- :cite:`schumannContrailCirrusPrediction2012`
|
|
181
|
+
"""
|
|
182
|
+
c = (1.49 * 16) / (2 * np.pi**3) # This is W2 in Schumann's Fortran code
|
|
183
|
+
return (c * aircraft_mass * constants.g) / (wingspan**2 * rho_air * true_airspeed * n_bv)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def downward_displacement_weakly_stratified(
|
|
187
|
+
wingspan: npt.NDArray[np.floating] | float,
|
|
188
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
189
|
+
aircraft_mass: npt.NDArray[np.floating] | float,
|
|
190
|
+
rho_air: npt.NDArray[np.floating],
|
|
191
|
+
n_bv: npt.NDArray[np.floating],
|
|
192
|
+
dz_max_strong: npt.NDArray[np.floating],
|
|
193
|
+
ds_dz: npt.NDArray[np.floating],
|
|
194
|
+
t_0: npt.NDArray[np.floating],
|
|
195
|
+
effective_vertical_resolution: float,
|
|
196
|
+
wind_shear_enhancement_exponent: npt.NDArray[np.floating] | float,
|
|
197
|
+
) -> npt.NDArray[np.floating]:
|
|
198
|
+
"""
|
|
199
|
+
Calculate the maximum contrail downward displacement under weakly/stably stratified conditions.
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
wingspan : npt.NDArray[np.floating] | float
|
|
204
|
+
aircraft wingspan, [:math:`m`]
|
|
205
|
+
true_airspeed : npt.NDArray[np.floating]
|
|
206
|
+
true airspeed for each waypoint, [:math:`m s^{-1}`]
|
|
207
|
+
aircraft_mass : npt.NDArray[np.floating] | float
|
|
208
|
+
aircraft mass for each waypoint, [:math:`kg`]
|
|
209
|
+
rho_air : npt.NDArray[np.floating]
|
|
210
|
+
density of air for each waypoint, [:math:`kg m^{-3}`]
|
|
211
|
+
n_bv : npt.NDArray[np.floating]
|
|
212
|
+
Brunt-Vaisaila frequency, [:math:`s^{-1}`]
|
|
213
|
+
dz_max_strong : npt.NDArray[np.floating]
|
|
214
|
+
Max contrail downward displacement under strongly stratified conditions, [:math:`m`]
|
|
215
|
+
ds_dz : npt.NDArray[np.floating]
|
|
216
|
+
Difference in wind speed over dz in the atmosphere, [:math:`m s^{-1} / m`]
|
|
217
|
+
t_0 : npt.NDArray[np.floating]
|
|
218
|
+
Wake vortex effective time scale, [:math:`s`]
|
|
219
|
+
effective_vertical_resolution: float
|
|
220
|
+
Passed through to :func:`wind_shear.wind_shear_enhancement_factor`, [:math:`m`]
|
|
221
|
+
wind_shear_enhancement_exponent: npt.NDArray[np.floating] | float
|
|
222
|
+
Passed through to :func:`wind_shear.wind_shear_enhancement_factor`
|
|
223
|
+
|
|
224
|
+
Returns
|
|
225
|
+
-------
|
|
226
|
+
npt.NDArray[np.floating]
|
|
227
|
+
Maximum contrail downward displacement, weakly/stably stratified conditions, [:math:`m`]
|
|
228
|
+
|
|
229
|
+
Notes
|
|
230
|
+
-----
|
|
231
|
+
See section 2.5 (pg 548) of :cite:`schumannContrailCirrusPrediction2012`.
|
|
232
|
+
|
|
233
|
+
References
|
|
234
|
+
----------
|
|
235
|
+
- :cite:`schumannContrailCirrusPrediction2012`
|
|
236
|
+
"""
|
|
237
|
+
b_0 = wake_vortex_separation(wingspan)
|
|
238
|
+
dz_max = np.maximum(dz_max_strong, 10.0)
|
|
239
|
+
shear_enhancement_factor = wind_shear.wind_shear_enhancement_factor(
|
|
240
|
+
dz_max, effective_vertical_resolution, wind_shear_enhancement_exponent
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Calculate epsilon and epsilon star
|
|
244
|
+
# In Schumann's Fortran code, epsn = EDR and epsn_st = EPSN
|
|
245
|
+
epsn = turbulent_kinetic_energy_dissipation_rate(ds_dz, shear_enhancement_factor)
|
|
246
|
+
epsn_st = normalized_dissipation_rate(epsn, wingspan, true_airspeed, aircraft_mass, rho_air)
|
|
247
|
+
return b_0 * (7.68 * (1 - 4.07 * epsn_st + 5.67 * epsn_st**2) * (0.79 - n_bv * t_0) + 1.88)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def wake_vortex_separation(
|
|
251
|
+
wingspan: npt.NDArray[np.floating] | float,
|
|
252
|
+
) -> npt.NDArray[np.floating] | float:
|
|
253
|
+
"""
|
|
254
|
+
Calculate the wake vortex separation.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
wingspan : npt.NDArray[np.floating] | float
|
|
259
|
+
aircraft wingspan, [:math:`m`]
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
npt.NDArray[np.floating] | float
|
|
264
|
+
wake vortex separation, [:math:`m`]
|
|
265
|
+
"""
|
|
266
|
+
return (np.pi * wingspan) / 4.0
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def turbulent_kinetic_energy_dissipation_rate(
|
|
270
|
+
ds_dz: npt.NDArray[np.floating],
|
|
271
|
+
shear_enhancement_factor: npt.NDArray[np.floating] | float = 1.0,
|
|
272
|
+
) -> npt.NDArray[np.floating]:
|
|
273
|
+
"""
|
|
274
|
+
Calculate the turbulent kinetic energy dissipation rate (epsilon).
|
|
275
|
+
|
|
276
|
+
The shear enhancement factor is used to account for any sub-grid scale turbulence.
|
|
277
|
+
|
|
278
|
+
Parameters
|
|
279
|
+
----------
|
|
280
|
+
ds_dz : npt.NDArray[np.floating]
|
|
281
|
+
Difference in wind speed over dz in the atmosphere, [:math:`m s^{-1} / m`]
|
|
282
|
+
shear_enhancement_factor : npt.NDArray[np.floating] | float
|
|
283
|
+
Multiplication factor to enhance the wind shear
|
|
284
|
+
|
|
285
|
+
Returns
|
|
286
|
+
-------
|
|
287
|
+
npt.NDArray[np.floating]
|
|
288
|
+
turbulent kinetic energy dissipation rate, [:math:`m^{2} s^{-3}`]
|
|
289
|
+
|
|
290
|
+
Notes
|
|
291
|
+
-----
|
|
292
|
+
- See eq. (37) in :cite:`schumannContrailCirrusPrediction2012`.
|
|
293
|
+
- In a personal correspondence, Dr. Schumann identified a print error in Eq. (37)
|
|
294
|
+
of the 2012 paper where the shear term should not be squared.
|
|
295
|
+
The correct equation is listed in Eq. (13) :cite:`schumannTurbulentMixingStably1995`.
|
|
296
|
+
|
|
297
|
+
References
|
|
298
|
+
----------
|
|
299
|
+
- :cite:`schumannContrailCirrusPrediction2012`
|
|
300
|
+
- :cite:`schumannTurbulentMixingStably1995`
|
|
301
|
+
"""
|
|
302
|
+
return 0.5 * 0.1**2 * (ds_dz * shear_enhancement_factor**2)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def normalized_dissipation_rate(
|
|
306
|
+
epsilon: npt.NDArray[np.floating],
|
|
307
|
+
wingspan: npt.NDArray[np.floating] | float,
|
|
308
|
+
true_airspeed: npt.NDArray[np.floating],
|
|
309
|
+
aircraft_mass: npt.NDArray[np.floating] | float,
|
|
310
|
+
rho_air: npt.NDArray[np.floating] | float,
|
|
311
|
+
) -> npt.NDArray[np.floating]:
|
|
312
|
+
"""
|
|
313
|
+
Calculate the normalized dissipation rate of the sinking wake vortex.
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
epsilon: npt.NDArray[np.floating]
|
|
318
|
+
turbulent kinetic energy dissipation rate, [:math:`m^{2} s^{-3}`]
|
|
319
|
+
wingspan : npt.NDArray[np.floating] | float
|
|
320
|
+
aircraft wingspan, [:math:`m`]
|
|
321
|
+
true_airspeed : npt.NDArray[np.floating]
|
|
322
|
+
true airspeed for each waypoint, [:math:`m s^{-1}`]
|
|
323
|
+
aircraft_mass : npt.NDArray[np.floating] | float
|
|
324
|
+
aircraft mass for each waypoint, [:math:`kg`]
|
|
325
|
+
rho_air : npt.NDArray[np.floating] | float
|
|
326
|
+
density of air for each waypoint, [:math:`kg m^{-3}`]
|
|
327
|
+
|
|
328
|
+
Returns
|
|
329
|
+
-------
|
|
330
|
+
npt.NDArray[np.floating]
|
|
331
|
+
Normalized dissipation rate of the sinking wake vortex
|
|
332
|
+
|
|
333
|
+
Notes
|
|
334
|
+
-----
|
|
335
|
+
See page 548 of :cite:`schumannContrailCirrusPrediction2012`.
|
|
336
|
+
|
|
337
|
+
References
|
|
338
|
+
----------
|
|
339
|
+
- :cite:`schumannContrailCirrusPrediction2012`
|
|
340
|
+
"""
|
|
341
|
+
c = (np.pi / 4) ** (1 / 3) * np.pi**3 / 8 # This is W6 in Schumann's Fortran code
|
|
342
|
+
numer = c * (epsilon * wingspan) ** (1 / 3) * wingspan**2 * rho_air * true_airspeed
|
|
343
|
+
|
|
344
|
+
# epsn_st = epsilon star
|
|
345
|
+
epsn_st = numer / (constants.g * aircraft_mass)
|
|
346
|
+
|
|
347
|
+
# In a personal correspondence, Schumann gives the precise value
|
|
348
|
+
# of 0.358906526 here
|
|
349
|
+
# In the 2012 paper, Schumann gives 0.36
|
|
350
|
+
# The precise value is likely insignificant because we don't expect epsn_st
|
|
351
|
+
# to be larger than 0.36
|
|
352
|
+
return np.minimum(epsn_st, 0.36)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def initial_contrail_width(
|
|
356
|
+
wingspan: npt.NDArray[np.floating] | float, dz_max: npt.NDArray[np.floating]
|
|
357
|
+
) -> npt.NDArray[np.floating]:
|
|
358
|
+
"""
|
|
359
|
+
Calculate the initial contrail width.
|
|
360
|
+
|
|
361
|
+
Parameters
|
|
362
|
+
----------
|
|
363
|
+
wingspan : npt.NDArray[np.floating] | float
|
|
364
|
+
aircraft wingspan, [:math:`m`]
|
|
365
|
+
dz_max : npt.NDArray[np.floating]
|
|
366
|
+
Max contrail downward displacement after the wake vortex phase, [:math:`m`]
|
|
367
|
+
Only the size of this array is used; the values are ignored.
|
|
368
|
+
|
|
369
|
+
Returns
|
|
370
|
+
-------
|
|
371
|
+
npt.NDArray[np.floating]
|
|
372
|
+
Initial contrail width, [:math:`m`]
|
|
373
|
+
"""
|
|
374
|
+
return np.full_like(dz_max, np.pi / 4) * wingspan
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def initial_contrail_depth(
|
|
378
|
+
dz_max: npt.NDArray[np.floating], initial_wake_vortex_depth: float | npt.NDArray[np.floating]
|
|
379
|
+
) -> npt.NDArray[np.floating]:
|
|
380
|
+
"""
|
|
381
|
+
Calculate the initial contrail depth.
|
|
382
|
+
|
|
383
|
+
Parameters
|
|
384
|
+
----------
|
|
385
|
+
dz_max : npt.NDArray[np.floating]
|
|
386
|
+
Max contrail downward displacement after the wake vortex phase, [:math:`m`]
|
|
387
|
+
initial_wake_vortex_depth : float | npt.NDArray[np.floating]
|
|
388
|
+
Initial wake vortex depth scaling factor.
|
|
389
|
+
Denoted `C_D0` in eq (14) in :cite:`schumannContrailCirrusPrediction2012`.
|
|
390
|
+
|
|
391
|
+
Returns
|
|
392
|
+
-------
|
|
393
|
+
npt.NDArray[np.floating]
|
|
394
|
+
Initial contrail depth, [:math:`m`]
|
|
395
|
+
"""
|
|
396
|
+
return dz_max * initial_wake_vortex_depth
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""Wind shear functions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import numpy.typing as npt
|
|
7
|
+
|
|
8
|
+
from pycontrails.utils.types import ArrayScalarLike
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def wind_shear_enhancement_factor(
|
|
12
|
+
contrail_depth: npt.NDArray[np.floating],
|
|
13
|
+
effective_vertical_resolution: float | npt.NDArray[np.floating],
|
|
14
|
+
wind_shear_enhancement_exponent: float | npt.NDArray[np.floating],
|
|
15
|
+
) -> npt.NDArray[np.floating]:
|
|
16
|
+
r"""Calculate the multiplication factor to enhance the wind shear based on contrail depth.
|
|
17
|
+
|
|
18
|
+
This factor accounts for any subgrid-scale that is not captured by the resolution
|
|
19
|
+
of the meteorological datasets.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
contrail_depth : npt.NDArray[np.floating]
|
|
24
|
+
Contrail depth , [:math:`m`]. Expected to be positive and bounded away from 0.
|
|
25
|
+
effective_vertical_resolution : float | npt.NDArray[np.floating]
|
|
26
|
+
Vertical resolution of met data , [:math:`m`]
|
|
27
|
+
wind_shear_enhancement_exponent : float | npt.NDArray[np.floating]
|
|
28
|
+
Exponent used in calculation. Expected to be nonnegative.
|
|
29
|
+
Discussed in paragraphs following eq. (39) in Schumann 2012 and referenced as `n`.
|
|
30
|
+
When this parameter is 0, no enhancement occurs.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
npt.NDArray[np.floating]
|
|
35
|
+
Wind shear enhancement factor
|
|
36
|
+
|
|
37
|
+
Notes
|
|
38
|
+
-----
|
|
39
|
+
Implementation based on eq (39) in :cite:`schumannContrailCirrusPrediction2012`.
|
|
40
|
+
|
|
41
|
+
References
|
|
42
|
+
----------
|
|
43
|
+
- :cite:`schumannContrailCirrusPrediction2012`
|
|
44
|
+
"""
|
|
45
|
+
ratio = effective_vertical_resolution / contrail_depth
|
|
46
|
+
return 0.5 * (1.0 + ratio**wind_shear_enhancement_exponent)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def wind_shear_normal(
|
|
50
|
+
u_wind_top: ArrayScalarLike,
|
|
51
|
+
u_wind_btm: ArrayScalarLike,
|
|
52
|
+
v_wind_top: ArrayScalarLike,
|
|
53
|
+
v_wind_btm: ArrayScalarLike,
|
|
54
|
+
cos_a: ArrayScalarLike,
|
|
55
|
+
sin_a: ArrayScalarLike,
|
|
56
|
+
dz: float,
|
|
57
|
+
) -> ArrayScalarLike:
|
|
58
|
+
r"""Calculate the total wind shear normal to an axis.
|
|
59
|
+
|
|
60
|
+
The total wind shear is the vertical gradient of the horizontal velocity.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
u_wind_top : ArrayScalarLike
|
|
65
|
+
u wind speed in the top layer, [:math:`m \ s^{-1}`]
|
|
66
|
+
u_wind_btm : ArrayScalarLike
|
|
67
|
+
u wind speed in the bottom layer, [:math:`m \ s^{-1}`]
|
|
68
|
+
v_wind_top : ArrayScalarLike
|
|
69
|
+
v wind speed in the top layer, [:math:`m \ s^{-1}`]
|
|
70
|
+
v_wind_btm : ArrayScalarLike
|
|
71
|
+
v wind speed in the bottom layer, [:math:`m \ s^{-1}`]
|
|
72
|
+
cos_a : ArrayScalarLike
|
|
73
|
+
Cosine component of segment
|
|
74
|
+
sin_a : ArrayScalarLike
|
|
75
|
+
Sine component of segment
|
|
76
|
+
dz : float
|
|
77
|
+
Difference in altitude between measurements, [:math:`m`]
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
ArrayScalarLike
|
|
82
|
+
Wind shear normal to axis, [:math:`s^{-1}`]
|
|
83
|
+
"""
|
|
84
|
+
du_dz = (u_wind_top - u_wind_btm) / dz
|
|
85
|
+
dv_dz = (v_wind_top - v_wind_btm) / dz
|
|
86
|
+
return dv_dz * cos_a - du_dz * sin_a
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def wind_shear(
|
|
90
|
+
u_wind_top: ArrayScalarLike,
|
|
91
|
+
u_wind_btm: ArrayScalarLike,
|
|
92
|
+
v_wind_top: ArrayScalarLike,
|
|
93
|
+
v_wind_btm: ArrayScalarLike,
|
|
94
|
+
dz: float,
|
|
95
|
+
) -> ArrayScalarLike:
|
|
96
|
+
r"""Calculate the total wind shear.
|
|
97
|
+
|
|
98
|
+
The total wind shear is the vertical gradient of the horizontal velocity.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
u_wind_top : ArrayScalarLike
|
|
103
|
+
u wind speed in the top layer, [:math:`m \ s^{-1}`]
|
|
104
|
+
u_wind_btm : ArrayScalarLike
|
|
105
|
+
u wind speed in the bottom layer, [:math:`m \ s^{-1}`]
|
|
106
|
+
v_wind_top : ArrayScalarLike
|
|
107
|
+
v wind speed in the top layer, [:math:`m \ s^{-1}`]
|
|
108
|
+
v_wind_btm : ArrayScalarLike
|
|
109
|
+
v wind speed in the bottom layer, [:math:`m \ s^{-1}`]
|
|
110
|
+
dz : float
|
|
111
|
+
Difference in altitude between measurements, [:math:`m`]
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
ArrayScalarLike
|
|
116
|
+
Total wind shear, [:math:`s^{-1}`]
|
|
117
|
+
"""
|
|
118
|
+
du_dz = (u_wind_top - u_wind_btm) / dz
|
|
119
|
+
dv_dz = (v_wind_top - v_wind_btm) / dz
|
|
120
|
+
return (du_dz**2 + dv_dz**2) ** 0.5
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Grid-like Contrail Cirrus Prediction (CoCiP) modeling support."""
|
|
2
|
+
|
|
3
|
+
from pycontrails.models.cocipgrid.cocip_grid import CocipGrid
|
|
4
|
+
from pycontrails.models.cocipgrid.cocip_grid_params import CocipGridParams
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"CocipGrid",
|
|
8
|
+
"CocipGridParams",
|
|
9
|
+
]
|