pycontrails 0.53.0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_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 (109) hide show
  1. pycontrails/__init__.py +70 -0
  2. pycontrails/_version.py +16 -0
  3. pycontrails/core/__init__.py +30 -0
  4. pycontrails/core/aircraft_performance.py +641 -0
  5. pycontrails/core/airports.py +226 -0
  6. pycontrails/core/cache.py +881 -0
  7. pycontrails/core/coordinates.py +174 -0
  8. pycontrails/core/fleet.py +470 -0
  9. pycontrails/core/flight.py +2312 -0
  10. pycontrails/core/flightplan.py +220 -0
  11. pycontrails/core/fuel.py +140 -0
  12. pycontrails/core/interpolation.py +721 -0
  13. pycontrails/core/met.py +2833 -0
  14. pycontrails/core/met_var.py +307 -0
  15. pycontrails/core/models.py +1181 -0
  16. pycontrails/core/polygon.py +549 -0
  17. pycontrails/core/rgi_cython.cpython-313-x86_64-linux-gnu.so +0 -0
  18. pycontrails/core/vector.py +2191 -0
  19. pycontrails/datalib/__init__.py +12 -0
  20. pycontrails/datalib/_leo_utils/search.py +250 -0
  21. pycontrails/datalib/_leo_utils/static/bq_roi_query.sql +6 -0
  22. pycontrails/datalib/_leo_utils/vis.py +59 -0
  23. pycontrails/datalib/_met_utils/metsource.py +743 -0
  24. pycontrails/datalib/ecmwf/__init__.py +53 -0
  25. pycontrails/datalib/ecmwf/arco_era5.py +527 -0
  26. pycontrails/datalib/ecmwf/common.py +109 -0
  27. pycontrails/datalib/ecmwf/era5.py +538 -0
  28. pycontrails/datalib/ecmwf/era5_model_level.py +482 -0
  29. pycontrails/datalib/ecmwf/hres.py +782 -0
  30. pycontrails/datalib/ecmwf/hres_model_level.py +495 -0
  31. pycontrails/datalib/ecmwf/ifs.py +284 -0
  32. pycontrails/datalib/ecmwf/model_levels.py +79 -0
  33. pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +139 -0
  34. pycontrails/datalib/ecmwf/variables.py +256 -0
  35. pycontrails/datalib/gfs/__init__.py +28 -0
  36. pycontrails/datalib/gfs/gfs.py +646 -0
  37. pycontrails/datalib/gfs/variables.py +100 -0
  38. pycontrails/datalib/goes.py +772 -0
  39. pycontrails/datalib/landsat.py +568 -0
  40. pycontrails/datalib/sentinel.py +512 -0
  41. pycontrails/datalib/spire.py +739 -0
  42. pycontrails/ext/bada.py +41 -0
  43. pycontrails/ext/cirium.py +14 -0
  44. pycontrails/ext/empirical_grid.py +140 -0
  45. pycontrails/ext/synthetic_flight.py +426 -0
  46. pycontrails/models/__init__.py +1 -0
  47. pycontrails/models/accf.py +406 -0
  48. pycontrails/models/apcemm/__init__.py +8 -0
  49. pycontrails/models/apcemm/apcemm.py +983 -0
  50. pycontrails/models/apcemm/inputs.py +226 -0
  51. pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +183 -0
  52. pycontrails/models/apcemm/utils.py +437 -0
  53. pycontrails/models/cocip/__init__.py +29 -0
  54. pycontrails/models/cocip/cocip.py +2617 -0
  55. pycontrails/models/cocip/cocip_params.py +299 -0
  56. pycontrails/models/cocip/cocip_uncertainty.py +285 -0
  57. pycontrails/models/cocip/contrail_properties.py +1517 -0
  58. pycontrails/models/cocip/output_formats.py +2261 -0
  59. pycontrails/models/cocip/radiative_forcing.py +1262 -0
  60. pycontrails/models/cocip/radiative_heating.py +520 -0
  61. pycontrails/models/cocip/unterstrasser_wake_vortex.py +403 -0
  62. pycontrails/models/cocip/wake_vortex.py +396 -0
  63. pycontrails/models/cocip/wind_shear.py +120 -0
  64. pycontrails/models/cocipgrid/__init__.py +9 -0
  65. pycontrails/models/cocipgrid/cocip_grid.py +2573 -0
  66. pycontrails/models/cocipgrid/cocip_grid_params.py +138 -0
  67. pycontrails/models/dry_advection.py +486 -0
  68. pycontrails/models/emissions/__init__.py +21 -0
  69. pycontrails/models/emissions/black_carbon.py +594 -0
  70. pycontrails/models/emissions/emissions.py +1353 -0
  71. pycontrails/models/emissions/ffm2.py +336 -0
  72. pycontrails/models/emissions/static/default-engine-uids.csv +239 -0
  73. pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +596 -0
  74. pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +215 -0
  75. pycontrails/models/humidity_scaling/__init__.py +37 -0
  76. pycontrails/models/humidity_scaling/humidity_scaling.py +1025 -0
  77. pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
  78. pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
  79. pycontrails/models/issr.py +210 -0
  80. pycontrails/models/pcc.py +327 -0
  81. pycontrails/models/pcr.py +154 -0
  82. pycontrails/models/ps_model/__init__.py +17 -0
  83. pycontrails/models/ps_model/ps_aircraft_params.py +376 -0
  84. pycontrails/models/ps_model/ps_grid.py +505 -0
  85. pycontrails/models/ps_model/ps_model.py +1017 -0
  86. pycontrails/models/ps_model/ps_operational_limits.py +540 -0
  87. pycontrails/models/ps_model/static/ps-aircraft-params-20240524.csv +68 -0
  88. pycontrails/models/ps_model/static/ps-synonym-list-20240524.csv +103 -0
  89. pycontrails/models/sac.py +459 -0
  90. pycontrails/models/tau_cirrus.py +168 -0
  91. pycontrails/physics/__init__.py +1 -0
  92. pycontrails/physics/constants.py +116 -0
  93. pycontrails/physics/geo.py +989 -0
  94. pycontrails/physics/jet.py +837 -0
  95. pycontrails/physics/thermo.py +451 -0
  96. pycontrails/physics/units.py +472 -0
  97. pycontrails/py.typed +0 -0
  98. pycontrails/utils/__init__.py +1 -0
  99. pycontrails/utils/dependencies.py +66 -0
  100. pycontrails/utils/iteration.py +13 -0
  101. pycontrails/utils/json.py +188 -0
  102. pycontrails/utils/temp.py +50 -0
  103. pycontrails/utils/types.py +165 -0
  104. pycontrails-0.53.0.dist-info/LICENSE +178 -0
  105. pycontrails-0.53.0.dist-info/METADATA +181 -0
  106. pycontrails-0.53.0.dist-info/NOTICE +43 -0
  107. pycontrails-0.53.0.dist-info/RECORD +109 -0
  108. pycontrails-0.53.0.dist-info/WHEEL +6 -0
  109. pycontrails-0.53.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,451 @@
1
+ """Thermodynamic relationships."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+ from pycontrails.physics import constants
8
+ from pycontrails.utils.types import ArrayScalarLike, support_arraylike
9
+
10
+ # -------------------
11
+ # Material Properties
12
+ # -------------------
13
+
14
+
15
+ def rho_d(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
16
+ r"""Calculate air density for (T, p) assuming dry air.
17
+
18
+ Parameters
19
+ ----------
20
+ T : ArrayScalarLike
21
+ Temperature, [:math:`K`]
22
+ p : ArrayScalarLike
23
+ Pressure, [:math:`Pa`]
24
+
25
+ Returns
26
+ -------
27
+ ArrayScalarLike
28
+ Air density of dry air, [:math:`kg \ m^{-3}`]
29
+ """
30
+ return p / (constants.R_d * T)
31
+
32
+
33
+ def rho_v(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
34
+ r"""Calculate the air density for (T, p) assuming all water vapor.
35
+
36
+ Parameters
37
+ ----------
38
+ T : ArrayScalarLike
39
+ Temperature, [:math:`K`]
40
+ p : ArrayScalarLike
41
+ Pressure, [:math:`Pa`]
42
+
43
+ Returns
44
+ -------
45
+ ArrayScalarLike
46
+ Air density of water vapor, [:math:`kg \ m^{-3}`]
47
+ """
48
+ return p / (constants.R_v * T)
49
+
50
+
51
+ def c_pm(q: ArrayScalarLike) -> ArrayScalarLike:
52
+ r"""Calculate isobaric heat capacity of moist air.
53
+
54
+ Parameters
55
+ ----------
56
+ q : ArrayScalarLike
57
+ Specific humidity, [:math:`kg \ kg^{-1}`]
58
+
59
+ Returns
60
+ -------
61
+ ArrayScalarLike
62
+ Isobaric heat capacity of moist air, [:math:`J \ kg^{-1} \ K^{-1}`]
63
+
64
+ Notes
65
+ -----
66
+ Some models (including CoCiP) use a constant value here (1004 :math:`J \ kg^{-1} \ K^{-1}`)
67
+
68
+ """
69
+ return constants.c_pd * (1.0 - q) + constants.c_pv * q
70
+
71
+
72
+ def p_vapor(q: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
73
+ r"""Calculate the vapor pressure.
74
+
75
+ Parameters
76
+ ----------
77
+ q : ArrayScalarTypeVar
78
+ Specific humidity, [:math:`kg \ kg^{-1}`]
79
+ p : ArrayScalarTypeVar
80
+ Pressure, [:math:`Pa`]
81
+
82
+ Returns
83
+ -------
84
+ ArrayScalarTypeVar
85
+ Vapor pressure, [:math:`Pa`]
86
+ """
87
+ return q * p * (constants.R_v / constants.R_d)
88
+
89
+
90
+ # -------------------
91
+ # Saturation Pressure
92
+ # -------------------
93
+
94
+
95
+ def e_sat_ice(T: ArrayScalarLike) -> ArrayScalarLike:
96
+ r"""Calculate saturation pressure of water vapor over ice.
97
+
98
+ Parameters
99
+ ----------
100
+ T : ArrayScalarLike
101
+ Temperature, [:math:`K`]
102
+
103
+ Returns
104
+ -------
105
+ ArrayScalarLike
106
+ Saturation pressure of water vapor over ice, [:math:`Pa`]
107
+
108
+ References
109
+ ----------
110
+ - :cite:`sonntag1994`
111
+
112
+ """
113
+ # Goff Gratch equation (Smithsonian Tables, 1984)
114
+ # return np.log10(-9.09718 * (273.16/T - 1) - 3.56654 * np.log10(273.16/T) + \
115
+ # 0.87679 * (1 - T/273.16) + np.log10(6.1071))
116
+
117
+ # Magnus Teten (Murray, 1967)
118
+ # return 6.1078 * np.exp(21.8745 * (T - 273.16) / (T - 7.66))
119
+
120
+ # Zhang 2017 - incorrect implementation of Magnus Teten
121
+ # return 6.1808 * np.exp(21.875 * (T - 276.16) / (T - 7.66))
122
+
123
+ # Guide to Meteorological Instruments and Methods of Observation (CIMO Guide) (WMO, 2008)
124
+ # return 6.112 * np.exp(22.46 * (T - 273.16) / (272.62 + T - 273.16))
125
+
126
+ # Sonntag (1994) is used in CoCiP
127
+
128
+ # FIXME: Presently, mypy is not aware that numpy ufuncs will return `xr.DataArray``
129
+ # when xr.DataArray is passed in. This will get fixed at some point in the future
130
+ # as `numpy` their typing patterns, after which the "type: ignore" comment can
131
+ # get ripped out.
132
+ # We could explicitly check for `xr.DataArray` then use `xr.apply_ufunc`, but
133
+ # this only renders our code more boilerplate and less performant.
134
+ # This comment is pasted several places in `pycontrails` -- they should all be
135
+ # addressed at the same time.
136
+ return 100.0 * np.exp( # type: ignore[return-value]
137
+ (-6024.5282 / T)
138
+ + 24.7219
139
+ + (0.010613868 * T)
140
+ - (1.3198825e-5 * (T**2))
141
+ - 0.49382577 * np.log(T)
142
+ )
143
+
144
+
145
+ def e_sat_liquid(T: ArrayScalarLike) -> ArrayScalarLike:
146
+ r"""Calculate saturation pressure of water vapor over liquid water.
147
+
148
+ Parameters
149
+ ----------
150
+ T : ArrayScalarLike
151
+ Temperature, [:math:`K`]
152
+
153
+ Returns
154
+ -------
155
+ ArrayScalarLike
156
+ Saturation pressure of water vapor over liquid water, [:math:`Pa`]
157
+
158
+ References
159
+ ----------
160
+ - :cite:`sonntag1994`
161
+ """
162
+ # Buck (Buck Research Manual 1996)
163
+ # 6.1121 * np.exp((18.678 * (T - 273.15) / 234.5) * (T - 273.15) / (257.14 + (T - 273.15)))
164
+
165
+ # Magnus Tetens (Murray, 1967)
166
+ # 6.1078 * np.exp(17.269388 * (T - 273.16) / (T - 35.86))
167
+
168
+ # Guide to Meteorological Instruments and Methods of Observation (CIMO Guide) (WMO, 2008)
169
+ # 6.112 * np.exp(17.62 * (T - 273.15) / (243.12 + T - 273.15))
170
+
171
+ # Sonntag (1994) is used in CoCiP
172
+
173
+ # FIXME: Presently, mypy is not aware that numpy ufuncs will return `xr.DataArray``
174
+ # when xr.DataArray is passed in. This will get fixed at some point in the future
175
+ # as `numpy` their typing patterns, after which the "type: ignore" comment can
176
+ # get ripped out.
177
+ # We could explicitly check for `xr.DataArray` then use `xr.apply_ufunc`, but
178
+ # this only renders our code more boilerplate and less performant.
179
+ # This comment is pasted several places in `pycontrails` -- they should all be
180
+ # addressed at the same time.
181
+ return 100.0 * np.exp( # type: ignore[return-value]
182
+ -6096.9385 / T + 16.635794 - 0.02711193 * T + 1.673952 * 1e-5 * T**2 + 2.433502 * np.log(T)
183
+ )
184
+
185
+
186
+ @support_arraylike
187
+ def _e_sat_piecewise(T: np.ndarray) -> np.ndarray:
188
+ """Calculate `e_sat_liquid` when T is above freezing otherwise `e_sat_ice`.
189
+
190
+ Parameters
191
+ ----------
192
+ T : np.ndarray
193
+ Temperature, [:math:`K`]
194
+
195
+ Returns
196
+ -------
197
+ np.ndarray
198
+ Piecewise array of e_sat_liquid and e_sat_ice values.
199
+ """
200
+ condlist = [T >= -constants.absolute_zero, T < constants.absolute_zero] # noqa: SIM300
201
+ funclist = [e_sat_liquid, e_sat_ice, np.nan] # nan passed through
202
+ return np.piecewise(T, condlist, funclist)
203
+
204
+
205
+ # ----------------------------
206
+ # Saturation Specific Humidity
207
+ # ----------------------------
208
+
209
+
210
+ def q_sat(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
211
+ r"""Calculate saturation specific humidity over liquid or ice.
212
+
213
+ When T is above 0 C, liquid saturation is computed. Otherwise, ice saturation
214
+ is computed.
215
+
216
+ Parameters
217
+ ----------
218
+ T : ArrayScalarLike
219
+ Temperature, [:math:`K`]
220
+ p : ArrayScalarLike
221
+ Pressure, [:math:`Pa`]
222
+
223
+ Returns
224
+ -------
225
+ ArrayScalarLike
226
+ Saturation specific humidity, [:math:`kg \ kg^{-1}`]
227
+
228
+ Notes
229
+ -----
230
+ Smith et al. (1999)
231
+ """
232
+ e_sat = _e_sat_piecewise(T)
233
+ return constants.epsilon * e_sat / p
234
+
235
+
236
+ def q_sat_ice(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
237
+ r"""Calculate saturation specific humidity over ice.
238
+
239
+ Parameters
240
+ ----------
241
+ T : ArrayScalarLike
242
+ Temperature, [:math:`K`]
243
+ p : ArrayScalarLike
244
+ Pressure, [:math:`Pa`]
245
+
246
+ Returns
247
+ -------
248
+ ArrayScalarLike
249
+ Saturation specific humidity, [:math:`kg \ kg^{-1}`]
250
+
251
+ Notes
252
+ -----
253
+ Smith et al. (1999)
254
+ """
255
+ return constants.epsilon * e_sat_ice(T) / p
256
+
257
+
258
+ def q_sat_liquid(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
259
+ r"""Calculate saturation specific humidity over liquid.
260
+
261
+ Parameters
262
+ ----------
263
+ T : ArrayScalarLike
264
+ Temperature, [:math:`K`]
265
+ p : ArrayScalarLike
266
+ Pressure, [:math:`Pa`]
267
+
268
+ Returns
269
+ -------
270
+ ArrayScalarLike
271
+ Saturation specific humidity, [:math:`kg \ kg^{-1}`]
272
+
273
+ Notes
274
+ -----
275
+ Smith et al. (1999)
276
+ """
277
+ return constants.epsilon * e_sat_liquid(T) / p
278
+
279
+
280
+ # -----------------
281
+ # Relative Humidity
282
+ # -----------------
283
+
284
+
285
+ def rh(q: ArrayScalarLike, T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
286
+ r"""Calculate the relative humidity with respect to to liquid water.
287
+
288
+ Parameters
289
+ ----------
290
+ q : ArrayScalarLike
291
+ Specific humidity, [:math:`kg \ kg^{-1}`]
292
+ T : ArrayScalarLike
293
+ Temperature, [:math:`K`]
294
+ p : ArrayScalarLike
295
+ Pressure, [:math:`Pa`]
296
+
297
+ Returns
298
+ -------
299
+ ArrayScalarLike
300
+ Relative Humidity, :math:`[0 - 1]`
301
+ """
302
+ return (q * p * (constants.R_v / constants.R_d)) / e_sat_liquid(T)
303
+
304
+
305
+ def rhi(q: ArrayScalarLike, T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
306
+ r"""Calculate the relative humidity with respect to ice (RHi).
307
+
308
+ Parameters
309
+ ----------
310
+ q : ArrayScalarLike
311
+ Specific humidity, [:math:`kg \ kg^{-1}`]
312
+ T : ArrayScalarLike
313
+ Temperature, [:math:`K`]
314
+ p : ArrayScalarLike
315
+ Pressure, [:math:`Pa`]
316
+
317
+ Returns
318
+ -------
319
+ ArrayScalarLike
320
+ Relative Humidity over ice, :math:`[0 - 1]`
321
+ """
322
+ return (q * p * (constants.R_v / constants.R_d)) / e_sat_ice(T)
323
+
324
+
325
+ # --------------
326
+ # Met Properties
327
+ # --------------
328
+
329
+
330
+ def pressure_dz(T: ArrayScalarLike, p: ArrayScalarLike, dz: float) -> ArrayScalarLike:
331
+ r"""Calculate the pressure altitude ``dz`` meters below input pressure.
332
+
333
+ Returns surface pressure if the calculated pressure altitude is greater
334
+ than :const:`constants.p_surface`.
335
+
336
+ Parameters
337
+ ----------
338
+ T : ArrayScalarLike
339
+ Temperature, [:math:`K`]
340
+ p : ArrayScalarLike
341
+ Pressure, [:math:`Pa`]
342
+ dz : float
343
+ Difference in altitude between measurements, [:math:`m`]
344
+
345
+ Returns
346
+ -------
347
+ ArrayScalarLike
348
+ Pressure at altitude, [:math:`Pa`]
349
+
350
+ Notes
351
+ -----
352
+ This is used to calculate the temperature gradient and wind shear.
353
+ """
354
+ dp = rho_d(T, p) * constants.g * dz
355
+
356
+ # FIXME: Presently, mypy is not aware that numpy ufuncs will return `xr.DataArray``
357
+ # when xr.DataArray is passed in. This will get fixed at some point in the future
358
+ # as `numpy` their typing patterns, after which the "type: ignore" comment can
359
+ # get ripped out.
360
+ # We could explicitly check for `xr.DataArray` then use `xr.apply_ufunc`, but
361
+ # this only renders our code more boilerplate and less performant.
362
+ # This comment is pasted several places in `pycontrails` -- they should all be
363
+ # addressed at the same time.
364
+ return np.minimum(p + dp, constants.p_surface) # type: ignore[return-value]
365
+
366
+
367
+ def T_potential_gradient(
368
+ T_top: ArrayScalarLike,
369
+ p_top: ArrayScalarLike,
370
+ T_btm: ArrayScalarLike,
371
+ p_btm: ArrayScalarLike,
372
+ dz: float,
373
+ ) -> ArrayScalarLike:
374
+ r"""Calculate the potential temperature gradient between two altitudes.
375
+
376
+ Parameters
377
+ ----------
378
+ T_top : ArrayScalarLike
379
+ Temperature at original altitude, [:math:`K`]
380
+ p_top : ArrayScalarLike
381
+ Pressure at original altitude, [:math:`Pa`]
382
+ T_btm : ArrayScalarLike
383
+ Temperature at lower altitude, [:math:`K`]
384
+ p_btm : ArrayScalarLike
385
+ Pressure at lower altitude, [:math:`Pa`]
386
+ dz : float
387
+ Difference in altitude between measurements, [:math:`m`]
388
+
389
+ Returns
390
+ -------
391
+ ArrayScalarLike
392
+ Potential Temperature gradient, [:math:`K \ m^{-1}`]
393
+ """
394
+ T_potential_top = T_potential(T_top, p_top)
395
+ T_potential_btm = T_potential(T_btm, p_btm)
396
+ return (T_potential_top - T_potential_btm) / dz
397
+
398
+
399
+ def T_potential(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
400
+ r"""Calculate potential temperature.
401
+
402
+ The potential temperature is the temperature that
403
+ an air parcel would attain if adiabatically
404
+ brought to a standard reference pressure, :const:`constants.p_surface`.
405
+
406
+ Parameters
407
+ ----------
408
+ T : ArrayScalarLike
409
+ Temperature , [:math:`K`]
410
+ p : ArrayScalarLike
411
+ Pressure, [:math:`Pa`]
412
+
413
+ Returns
414
+ -------
415
+ ArrayScalarLike
416
+ Potential Temperature, [:math:`K`]
417
+
418
+ References
419
+ ----------
420
+ - https://en.wikipedia.org/wiki/Potential_temperature
421
+ """
422
+ return T * (constants.p_surface / p) ** (constants.R_d / constants.c_pd)
423
+
424
+
425
+ def brunt_vaisala_frequency(p: np.ndarray, T: np.ndarray, T_grad: np.ndarray) -> np.ndarray:
426
+ r"""Calculate the Brunt-Vaisaila frequency.
427
+
428
+ The Brunt-Vaisaila frequency is the frequency at which a vertically
429
+ displaced parcel will oscillate within a statically stable environment.
430
+
431
+ Parameters
432
+ ----------
433
+ p : np.ndarray
434
+ Pressure, [:math:`Pa`]
435
+ T : np.ndarray
436
+ Temperature , [:math:`K`]
437
+ T_grad : np.ndarray
438
+ Potential Temperature gradient (see :func:`T_potential_gradient`), [:math:`K \ m^{-1}`]
439
+
440
+ Returns
441
+ -------
442
+ np.ndarray
443
+ Brunt-Vaisaila frequency, [:math:`s^{-1}`]
444
+
445
+ References
446
+ ----------
447
+ - https://en.wikipedia.org/wiki/Brunt%E2%80%93V%C3%A4is%C3%A4l%C3%A4_frequency
448
+ """
449
+ theta = T_potential(T, p)
450
+ T_grad.clip(min=1e-6, out=T_grad)
451
+ return (T_grad * constants.g / theta) ** 0.5