pycontrails 0.59.0__cp314-cp314-macosx_10_15_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 (123) 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 +2936 -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 +764 -0
  37. pycontrails/datalib/gruan.py +343 -0
  38. pycontrails/datalib/himawari/__init__.py +27 -0
  39. pycontrails/datalib/himawari/header_struct.py +266 -0
  40. pycontrails/datalib/himawari/himawari.py +671 -0
  41. pycontrails/datalib/landsat.py +589 -0
  42. pycontrails/datalib/leo_utils/__init__.py +5 -0
  43. pycontrails/datalib/leo_utils/correction.py +266 -0
  44. pycontrails/datalib/leo_utils/landsat_metadata.py +300 -0
  45. pycontrails/datalib/leo_utils/search.py +250 -0
  46. pycontrails/datalib/leo_utils/sentinel_metadata.py +748 -0
  47. pycontrails/datalib/leo_utils/static/bq_roi_query.sql +6 -0
  48. pycontrails/datalib/leo_utils/vis.py +59 -0
  49. pycontrails/datalib/sentinel.py +650 -0
  50. pycontrails/datalib/spire/__init__.py +5 -0
  51. pycontrails/datalib/spire/exceptions.py +62 -0
  52. pycontrails/datalib/spire/spire.py +604 -0
  53. pycontrails/ext/bada.py +42 -0
  54. pycontrails/ext/cirium.py +14 -0
  55. pycontrails/ext/empirical_grid.py +140 -0
  56. pycontrails/ext/synthetic_flight.py +431 -0
  57. pycontrails/models/__init__.py +1 -0
  58. pycontrails/models/accf.py +425 -0
  59. pycontrails/models/apcemm/__init__.py +8 -0
  60. pycontrails/models/apcemm/apcemm.py +983 -0
  61. pycontrails/models/apcemm/inputs.py +226 -0
  62. pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +183 -0
  63. pycontrails/models/apcemm/utils.py +437 -0
  64. pycontrails/models/cocip/__init__.py +29 -0
  65. pycontrails/models/cocip/cocip.py +2742 -0
  66. pycontrails/models/cocip/cocip_params.py +305 -0
  67. pycontrails/models/cocip/cocip_uncertainty.py +291 -0
  68. pycontrails/models/cocip/contrail_properties.py +1530 -0
  69. pycontrails/models/cocip/output_formats.py +2270 -0
  70. pycontrails/models/cocip/radiative_forcing.py +1260 -0
  71. pycontrails/models/cocip/radiative_heating.py +520 -0
  72. pycontrails/models/cocip/unterstrasser_wake_vortex.py +508 -0
  73. pycontrails/models/cocip/wake_vortex.py +396 -0
  74. pycontrails/models/cocip/wind_shear.py +120 -0
  75. pycontrails/models/cocipgrid/__init__.py +9 -0
  76. pycontrails/models/cocipgrid/cocip_grid.py +2552 -0
  77. pycontrails/models/cocipgrid/cocip_grid_params.py +138 -0
  78. pycontrails/models/dry_advection.py +602 -0
  79. pycontrails/models/emissions/__init__.py +21 -0
  80. pycontrails/models/emissions/black_carbon.py +599 -0
  81. pycontrails/models/emissions/emissions.py +1353 -0
  82. pycontrails/models/emissions/ffm2.py +336 -0
  83. pycontrails/models/emissions/static/default-engine-uids.csv +239 -0
  84. pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +596 -0
  85. pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +215 -0
  86. pycontrails/models/extended_k15.py +1327 -0
  87. pycontrails/models/humidity_scaling/__init__.py +37 -0
  88. pycontrails/models/humidity_scaling/humidity_scaling.py +1075 -0
  89. pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
  90. pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
  91. pycontrails/models/issr.py +210 -0
  92. pycontrails/models/pcc.py +326 -0
  93. pycontrails/models/pcr.py +154 -0
  94. pycontrails/models/ps_model/__init__.py +18 -0
  95. pycontrails/models/ps_model/ps_aircraft_params.py +381 -0
  96. pycontrails/models/ps_model/ps_grid.py +701 -0
  97. pycontrails/models/ps_model/ps_model.py +1000 -0
  98. pycontrails/models/ps_model/ps_operational_limits.py +525 -0
  99. pycontrails/models/ps_model/static/ps-aircraft-params-20250328.csv +69 -0
  100. pycontrails/models/ps_model/static/ps-synonym-list-20250328.csv +104 -0
  101. pycontrails/models/sac.py +442 -0
  102. pycontrails/models/tau_cirrus.py +183 -0
  103. pycontrails/physics/__init__.py +1 -0
  104. pycontrails/physics/constants.py +117 -0
  105. pycontrails/physics/geo.py +1138 -0
  106. pycontrails/physics/jet.py +968 -0
  107. pycontrails/physics/static/iata-cargo-load-factors-20250221.csv +74 -0
  108. pycontrails/physics/static/iata-passenger-load-factors-20250221.csv +74 -0
  109. pycontrails/physics/thermo.py +551 -0
  110. pycontrails/physics/units.py +472 -0
  111. pycontrails/py.typed +0 -0
  112. pycontrails/utils/__init__.py +1 -0
  113. pycontrails/utils/dependencies.py +66 -0
  114. pycontrails/utils/iteration.py +13 -0
  115. pycontrails/utils/json.py +187 -0
  116. pycontrails/utils/temp.py +50 -0
  117. pycontrails/utils/types.py +163 -0
  118. pycontrails-0.59.0.dist-info/METADATA +179 -0
  119. pycontrails-0.59.0.dist-info/RECORD +123 -0
  120. pycontrails-0.59.0.dist-info/WHEEL +6 -0
  121. pycontrails-0.59.0.dist-info/licenses/LICENSE +178 -0
  122. pycontrails-0.59.0.dist-info/licenses/NOTICE +43 -0
  123. pycontrails-0.59.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
+ ]