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,74 @@
1
+ Date,Global,Africa,Asia Pacific,Europe,Latin America,Middle East,North America
2
+ 15/12/2018,0.488,0.381,0.54,0.567,0.291,0.488,0.414
3
+ 15/1/2019,0.451,0.354,0.501,0.501,0.299,0.421,0.4
4
+ 15/2/2019,0.447,0.363,0.473,0.53,0.297,0.466,0.379
5
+ 15/3/2019,0.495,0.384,0.556,0.56,0.323,0.488,0.416
6
+ 15/4/2019,0.463,0.374,0.518,0.496,0.325,0.458,0.405
7
+ 15/5/2019,0.468,0.386,0.52,0.513,0.353,0.469,0.398
8
+ 15/6/2019,0.454,0.324,0.522,0.498,0.337,0.44,0.382
9
+ 15/7/2019,0.45,0.323,0.519,0.485,0.354,0.453,0.373
10
+ 15/8/2019,0.446,0.302,0.516,0.477,0.372,0.435,0.377
11
+ 15/9/2019,0.464,0.329,0.539,0.501,0.379,0.459,0.381
12
+ 15/10/2019,0.477,0.361,0.539,0.533,0.364,0.477,0.394
13
+ 15/11/2019,0.496,0.404,0.538,0.569,0.403,0.497,0.413
14
+ 15/12/2019,0.467,0.368,0.519,0.53,0.3,0.47,0.395
15
+ 15/1/2020,0.45,0.356,0.474,0.501,0.311,0.426,0.424
16
+ 15/2/2020,0.464,0.368,0.543,0.531,0.342,0.461,0.372
17
+ 15/3/2020,0.545,0.425,0.656,0.63,0.411,0.532,0.429
18
+ 15/4/2020,0.58,0.486,0.691,0.648,0.554,0.525,0.487
19
+ 15/5/2020,0.576,0.612,0.643,0.625,0.561,0.483,0.526
20
+ 15/6/2020,0.573,0.547,0.645,0.62,0.512,0.494,0.521
21
+ 15/7/2020,0.564,0.489,0.639,0.594,0.464,0.53,0.506
22
+ 15/8/2020,0.548,0.502,0.616,0.568,0.478,0.535,0.489
23
+ 15/9/2020,0.569,0.507,0.642,0.62,0.456,0.579,0.484
24
+ 15/10/2020,0.576,0.502,0.617,0.651,0.443,0.606,0.496
25
+ 15/11/2020,0.582,0.496,0.631,0.655,0.436,0.6,0.5
26
+ 15/12/2020,0.573,0.51,0.639,0.653,0.367,0.597,0.482
27
+ 15/1/2021,0.589,0.48,0.665,0.627,0.39,0.569,0.532
28
+ 15/2/2021,0.575,0.476,0.692,0.641,0.429,0.598,0.453
29
+ 15/3/2021,0.588,0.499,0.661,0.685,0.453,0.613,0.472
30
+ 15/4/2021,0.578,0.504,0.633,0.681,0.457,0.598,0.473
31
+ 15/5/2021,0.572,0.502,0.646,0.656,0.423,0.589,0.469
32
+ 15/6/2021,0.565,0.48,0.676,0.626,0.381,0.581,0.458
33
+ 15/7/2021,0.544,0.455,0.654,0.598,0.387,0.536,0.443
34
+ 15/8/2021,0.542,0.43,0.698,0.575,0.404,0.529,0.437
35
+ 15/9/2021,0.553,0.428,0.68,0.604,0.37,0.558,0.447
36
+ 15/10/2021,0.561,0.45,0.661,0.626,0.421,0.572,0.449
37
+ 15/11/2021,0.559,0.434,0.654,0.631,0.446,0.572,0.444
38
+ 15/12/2021,0.542,0.502,0.634,0.623,0.413,0.556,0.43
39
+ 15/1/2022,0.541,0.492,0.609,0.584,0.417,0.513,0.474
40
+ 15/2/2022,0.532,0.502,0.592,0.636,0.476,0.529,0.429
41
+ 15/3/2022,0.549,0.494,0.638,0.671,0.448,0.526,0.442
42
+ 15/4/2022,0.516,0.49,0.631,0.578,0.419,0.504,0.419
43
+ 15/5/2022,0.505,0.495,0.627,0.548,0.387,0.487,0.411
44
+ 15/6/2022,0.492,0.447,0.608,0.507,0.383,0.488,0.404
45
+ 15/7/2022,0.472,0.452,0.563,0.493,0.374,0.469,0.398
46
+ 15/8/2022,0.467,0.418,0.547,0.502,0.374,0.466,0.393
47
+ 15/9/2022,0.481,0.451,0.572,0.528,0.381,0.478,0.396
48
+ 15/10/2022,0.487,0.437,0.561,0.558,0.384,0.48,0.401
49
+ 15/11/2022,0.491,0.458,0.545,0.569,0.382,0.475,0.419
50
+ 15/12/2022,0.472,0.432,0.528,0.559,0.322,0.454,0.406
51
+ 15/1/2023,0.448,0.439,0.452,0.541,0.325,0.411,0.423
52
+ 15/2/2023,0.456,0.468,0.464,0.574,0.361,0.445,0.4
53
+ 15/3/2023,0.462,0.489,0.485,0.57,0.366,0.456,0.393
54
+ 15/4/2023,0.427,0.482,0.442,0.497,0.364,0.431,0.373
55
+ 15/5/2023,0.415,0.448,0.422,0.489,0.333,0.41,0.373
56
+ 15/6/2023,0.432,0.446,0.468,0.476,0.337,0.446,0.374
57
+ 15/7/2023,0.421,0.417,0.457,0.472,0.322,0.411,0.37
58
+ 15/8/2023,0.42,0.388,0.443,0.484,0.326,0.407,0.377
59
+ 15/9/2023,0.438,0.436,0.466,0.5,0.319,0.424,0.392
60
+ 15/10/2023,0.452,0.416,0.472,0.53,0.354,0.46,0.392
61
+ 15/11/2023,0.467,0.421,0.479,0.57,0.363,0.469,0.408
62
+ 15/12/2023,0.459,0.41,0.479,0.562,0.316,0.455,0.403
63
+ 15/1/2024,0.457,0.431,0.446,0.555,0.344,0.439,0.435
64
+ 15/2/2024,0.451,0.451,0.432,0.584,0.376,0.463,0.396
65
+ 15/3/2024,0.473,0.473,0.475,0.581,0.402,0.496,0.404
66
+ 15/4/2024,0.439,0.429,0.445,0.515,0.387,0.447,0.387
67
+ 15/5/2024,0.446,0.438,0.453,0.518,0.362,0.461,0.397
68
+ 15/6/2024,0.458,0.385,0.496,0.507,0.336,0.473,0.388
69
+ 15/7/2024,0.444,0.4,0.48,0.496,0.338,0.458,0.382
70
+ 15/8/2024,0.44,0.378,0.466,0.501,0.359,0.445,0.387
71
+ 15/9/2024,0.456,0.392,0.485,0.525,0.368,0.474,0.389
72
+ 15/10/2024,0.473,0.401,0.493,0.555,0.411,0.48,0.411
73
+ 15/11/2024,0.49,0.425,0.5,0.576,0.396,0.494,0.438
74
+ 15/12/2024,0.473,0.415,0.491,0.567,0.335,0.473,0.421
@@ -0,0 +1,74 @@
1
+ Date,Global,Africa,Asia Pacific,Europe,Latin America,Middle East,North America
2
+ 15/12/2018,0.804,0.724,0.81,0.81,0.818,0.736,0.825
3
+ 15/1/2019,0.796,0.709,0.81,0.796,0.825,0.76,0.795
4
+ 15/2/2019,0.806,0.704,0.826,0.815,0.813,0.726,0.808
5
+ 15/3/2019,0.817,0.72,0.812,0.837,0.815,0.739,0.85
6
+ 15/4/2019,0.828,0.733,0.817,0.851,0.822,0.803,0.839
7
+ 15/5/2019,0.815,0.676,0.802,0.837,0.832,0.732,0.851
8
+ 15/6/2019,0.844,0.706,0.821,0.875,0.832,0.767,0.887
9
+ 15/7/2019,0.857,0.735,0.831,0.89,0.853,0.812,0.888
10
+ 15/8/2019,0.857,0.755,0.839,0.889,0.833,0.821,0.875
11
+ 15/9/2019,0.819,0.721,0.801,0.866,0.819,0.75,0.828
12
+ 15/10/2019,0.82,0.697,0.815,0.855,0.819,0.734,0.841
13
+ 15/11/2019,0.818,0.708,0.813,0.833,0.822,0.732,0.828
14
+ 15/12/2019,0.823,0.724,0.816,0.828,0.825,0.78,0.859
15
+ 15/1/2020,0.803,0.702,0.799,0.816,0.826,0.785,0.812
16
+ 15/2/2020,0.759,0.668,0.678,0.813,0.812,0.725,0.811
17
+ 15/3/2020,0.606,0.609,0.589,0.67,0.681,0.599,0.557
18
+ 15/4/2020,0.366,0.111,0.538,0.32,0.55,0.284,0.15
19
+ 15/5/2020,0.507,0.071,0.62,0.427,0.623,0.255,0.381
20
+ 15/6/2020,0.576,0.162,0.638,0.555,0.666,0.357,0.524
21
+ 15/7/2020,0.579,0.296,0.657,0.609,0.631,0.396,0.476
22
+ 15/8/2020,0.585,0.39,0.65,0.635,0.639,0.372,0.477
23
+ 15/9/2020,0.601,0.378,0.692,0.586,0.706,0.365,0.525
24
+ 15/10/2020,0.602,0.482,0.687,0.552,0.721,0.387,0.558
25
+ 15/11/2020,0.58,0.474,0.664,0.523,0.74,0.372,0.518
26
+ 15/12/2020,0.575,0.549,0.616,0.578,0.73,0.44,0.516
27
+ 15/1/2021,0.541,0.544,0.566,0.576,0.685,0.422,0.484
28
+ 15/2/2021,0.554,0.516,0.591,0.563,0.683,0.398,0.527
29
+ 15/3/2021,0.623,0.53,0.669,0.593,0.708,0.422,0.624
30
+ 15/4/2021,0.633,0.476,0.678,0.563,0.723,0.404,0.668
31
+ 15/5/2021,0.658,0.53,0.678,0.593,0.768,0.389,0.728
32
+ 15/6/2021,0.696,0.587,0.657,0.658,0.784,0.459,0.806
33
+ 15/7/2021,0.731,0.614,0.675,0.725,0.793,0.513,0.841
34
+ 15/8/2021,0.7,0.64,0.545,0.746,0.774,0.56,0.786
35
+ 15/9/2021,0.676,0.56,0.605,0.719,0.773,0.524,0.727
36
+ 15/10/2021,0.706,0.558,0.629,0.741,0.809,0.577,0.769
37
+ 15/11/2021,0.713,0.616,0.597,0.752,0.822,0.616,0.786
38
+ 15/12/2021,0.723,0.647,0.625,0.745,0.816,0.663,0.793
39
+ 15/1/2022,0.645,0.623,0.576,0.682,0.782,0.591,0.663
40
+ 15/2/2022,0.698,0.648,0.629,0.721,0.795,0.648,0.745
41
+ 15/3/2022,0.747,0.657,0.642,0.739,0.808,0.718,0.839
42
+ 15/4/2022,0.778,0.68,0.67,0.795,0.809,0.713,0.858
43
+ 15/5/2022,0.794,0.696,0.696,0.807,0.807,0.762,0.86
44
+ 15/6/2022,0.824,0.743,0.729,0.86,0.817,0.772,0.891
45
+ 15/7/2022,0.835,0.753,0.764,0.87,0.831,0.812,0.882
46
+ 15/8/2022,0.818,0.757,0.74,0.862,0.824,0.796,0.856
47
+ 15/9/2022,0.816,0.743,0.747,0.847,0.823,0.795,0.855
48
+ 15/10/2022,0.82,0.726,0.755,0.848,0.833,0.791,0.864
49
+ 15/11/2022,0.808,0.748,0.77,0.838,0.82,0.775,0.832
50
+ 15/12/2022,0.811,0.769,0.772,0.836,0.785,0.8,0.842
51
+ 15/1/2023,0.777,0.742,0.774,0.762,0.813,0.791,0.784
52
+ 15/2/2023,0.778,0.756,0.792,0.752,0.811,0.798,0.771
53
+ 15/3/2023,0.807,0.739,0.792,0.805,0.812,0.794,0.837
54
+ 15/4/2023,0.813,0.708,0.784,0.838,0.814,0.76,0.856
55
+ 15/5/2023,0.818,0.699,0.773,0.848,0.811,0.799,0.863
56
+ 15/6/2023,0.842,0.689,0.804,0.877,0.825,0.794,0.887
57
+ 15/7/2023,0.852,0.746,0.816,0.877,0.867,0.821,0.897
58
+ 15/8/2023,0.846,0.764,0.822,0.876,0.851,0.83,0.858
59
+ 15/9/2023,0.826,0.731,0.8,0.86,0.839,0.816,0.83
60
+ 15/10/2023,0.831,0.707,0.821,0.856,0.848,0.806,0.836
61
+ 15/11/2023,0.818,0.704,0.814,0.837,0.844,0.777,0.827
62
+ 15/12/2023,0.821,0.732,0.812,0.851,0.827,0.782,0.829
63
+ 15/1/2024,0.799,0.731,0.808,0.782,0.85,0.799,0.799
64
+ 15/2/2024,0.806,0.744,0.844,0.761,0.827,0.808,0.795
65
+ 15/3/2024,0.82,0.721,0.835,0.809,0.831,0.775,0.837
66
+ 15/4/2024,0.824,0.734,0.824,0.838,0.822,0.792,0.83
67
+ 15/5/2024,0.834,0.729,0.818,0.852,0.834,0.808,0.858
68
+ 15/6/2024,0.85,0.771,0.829,0.877,0.842,0.795,0.876
69
+ 15/7/2024,0.86,0.75,0.834,0.882,0.862,0.84,0.889
70
+ 15/8/2024,0.862,0.779,0.86,0.879,0.84,0.823,0.871
71
+ 15/9/2024,0.836,0.765,0.831,0.865,0.834,0.814,0.824
72
+ 15/10/2024,0.839,0.738,0.841,0.862,0.845,0.803,0.832
73
+ 15/11/2024,0.834,0.733,0.849,0.853,0.845,0.812,0.81
74
+ 15/12/2024,0.84,0.76,0.833,0.865,0.83,0.805,0.85
@@ -0,0 +1,551 @@
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.epsilon
88
+
89
+
90
+ def water_vapor_partial_pressure_along_mixing_line(
91
+ specific_humidity: ArrayScalarLike,
92
+ air_pressure: ArrayScalarLike,
93
+ T_plume: ArrayScalarLike,
94
+ T_ambient: ArrayScalarLike,
95
+ G: ArrayScalarLike,
96
+ ) -> ArrayScalarLike:
97
+ """
98
+ Calculate water vapor partial pressure along mixing line.
99
+
100
+ Parameters
101
+ ----------
102
+ specific_humidity : ArrayScalarLike
103
+ Specific humidity at each waypoint, [:math:`kg_{H_{2}O} / kg_{air}`]
104
+ air_pressure : ArrayScalarLike
105
+ Pressure altitude at each waypoint, [:math:`Pa`]
106
+ T_plume : ArrayScalarLike
107
+ Plume temperature evolution along mixing line, [:math:`K`]
108
+ T_ambient : ArrayScalarLike
109
+ Ambient temperature for each waypoint, [:math:`K`]
110
+ G : ArrayScalarLike
111
+ Slope of the mixing line in a temperature-humidity diagram.
112
+
113
+ Returns
114
+ -------
115
+ ArrayScalarLike
116
+ Water vapor partial pressure along mixing line (p_mw), [:math:`Pa`]
117
+
118
+ References
119
+ ----------
120
+ Eq. (2) of Karcher et al. (2015).
121
+ """
122
+ p_wa = p_vapor(specific_humidity, air_pressure)
123
+ return p_wa + G * (T_plume - T_ambient)
124
+
125
+
126
+ # -------------------
127
+ # Saturation Pressure
128
+ # -------------------
129
+
130
+
131
+ def e_sat_ice(T: ArrayScalarLike) -> ArrayScalarLike:
132
+ r"""Calculate saturation pressure of water vapor over ice.
133
+
134
+ Parameters
135
+ ----------
136
+ T : ArrayScalarLike
137
+ Temperature, [:math:`K`]
138
+
139
+ Returns
140
+ -------
141
+ ArrayScalarLike
142
+ Saturation pressure of water vapor over ice, [:math:`Pa`]
143
+
144
+ References
145
+ ----------
146
+ - :cite:`sonntag1994`
147
+
148
+ """
149
+ # Goff Gratch equation (Smithsonian Tables, 1984)
150
+ # return np.log10(-9.09718 * (273.16/T - 1) - 3.56654 * np.log10(273.16/T) + \
151
+ # 0.87679 * (1 - T/273.16) + np.log10(6.1071))
152
+
153
+ # Magnus Teten (Murray, 1967)
154
+ # return 6.1078 * np.exp(21.8745 * (T - 273.16) / (T - 7.66))
155
+
156
+ # Zhang 2017 - incorrect implementation of Magnus Teten
157
+ # return 6.1808 * np.exp(21.875 * (T - 276.16) / (T - 7.66))
158
+
159
+ # Guide to Meteorological Instruments and Methods of Observation (CIMO Guide) (WMO, 2008)
160
+ # return 6.112 * np.exp(22.46 * (T - 273.16) / (272.62 + T - 273.16))
161
+
162
+ # Sonntag (1994) is used in CoCiP
163
+
164
+ # FIXME: Presently, mypy is not aware that numpy ufuncs will return `xr.DataArray``
165
+ # when xr.DataArray is passed in. This will get fixed at some point in the future
166
+ # as `numpy` their typing patterns, after which the "type: ignore" comment can
167
+ # get ripped out.
168
+ # We could explicitly check for `xr.DataArray` then use `xr.apply_ufunc`, but
169
+ # this only renders our code more boilerplate and less performant.
170
+ # This comment is pasted several places in `pycontrails` -- they should all be
171
+ # addressed at the same time.
172
+ return 100.0 * np.exp( # type: ignore[return-value]
173
+ (-6024.5282 / T)
174
+ + 24.7219
175
+ + (0.010613868 * T)
176
+ - (1.3198825e-5 * (T**2))
177
+ - 0.49382577 * np.log(T)
178
+ )
179
+
180
+
181
+ def sonntag_e_sat_liquid(T: ArrayScalarLike) -> ArrayScalarLike:
182
+ """Calculate saturation pressure of water vapor over liquid water using Sonntag (1994).
183
+
184
+ Parameters
185
+ ----------
186
+ T : ArrayScalarLike
187
+ Temperature, [:math:`K`]
188
+
189
+ Returns
190
+ -------
191
+ ArrayScalarLike
192
+ Saturation pressure of water vapor over liquid water, [:math:`Pa`]
193
+ """
194
+ return 100.0 * np.exp( # type: ignore[return-value]
195
+ -6096.9385 / T + 16.635794 - 0.02711193 * T + 1.673952 * 1e-5 * T**2 + 2.433502 * np.log(T)
196
+ )
197
+
198
+
199
+ def mk05_e_sat_liquid(T: ArrayScalarLike) -> ArrayScalarLike:
200
+ """Calculate saturation pressure of water vapor over liquid water using Murphy and Koop (2005).
201
+
202
+ Parameters
203
+ ----------
204
+ T : ArrayScalarLike
205
+ Temperature, [:math:`K`]
206
+
207
+ Returns
208
+ -------
209
+ ArrayScalarLike
210
+ Saturation pressure of water vapor over liquid water, [:math:`Pa`]
211
+
212
+ Notes
213
+ -----
214
+ Several formulations exist for the saturation vapor pressure over liquid water.
215
+
216
+ Buck (Buck Research Manual 1996)..
217
+
218
+ 6.1121 * np.exp((18.678 * (T - 273.15) / 234.5) * (T - 273.15) / (257.14 + (T - 273.15)))
219
+
220
+ Magnus Tetens (Murray, 1967)..
221
+
222
+ 6.1078 * np.exp(17.269388 * (T - 273.16) / (T - 35.86))
223
+
224
+ Guide to Meteorological Instruments and Methods of Observation (CIMO Guide) (WMO, 2008)..
225
+
226
+ 6.112 * np.exp(17.62 * (T - 273.15) / (243.12 + T - 273.15))
227
+
228
+ Sonntag (1994) (see :func:`sonntag_e_sat_liquid`) is used in older versions of CoCiP.
229
+ """
230
+
231
+ return np.exp( # type: ignore[return-value]
232
+ 54.842763
233
+ - 6763.22 / T
234
+ - 4.21 * np.log(T)
235
+ + 0.000367 * T
236
+ + np.tanh(0.0415 * (T - 218.8))
237
+ * (53.878 - 1331.22 / T - 9.44523 * np.log(T) + 0.014025 * T)
238
+ )
239
+
240
+
241
+ def sonntag_e_sat_liquid_prime(T: ArrayScalarLike) -> ArrayScalarLike:
242
+ """Calculate the derivative of :func:`sonntag_e_sat_liquid`.
243
+
244
+ Parameters
245
+ ----------
246
+ T : ArrayScalarLike
247
+ Temperature, [:math:`K`].
248
+
249
+ Returns
250
+ -------
251
+ ArrayScalarLike
252
+ Derivative of :func:`sonntag_e_sat_liquid`
253
+ """
254
+ d_inside = 6096.9385 / (T**2) - 0.02711193 + 1.673952 * 1e-5 * 2 * T + 2.433502 / T
255
+ return sonntag_e_sat_liquid(T) * d_inside
256
+
257
+
258
+ def mk05_e_sat_liquid_prime(T: ArrayScalarLike) -> ArrayScalarLike:
259
+ """Calculate the derivative of :func:`mk05_e_sat_liquid`.
260
+
261
+ Parameters
262
+ ----------
263
+ T : ArrayScalarLike
264
+ Temperature, [:math:`K`].
265
+
266
+ Returns
267
+ -------
268
+ ArrayScalarLike
269
+ Derivative of :func:`mk05_e_sat_liquid`
270
+ """
271
+ tanh_term = np.tanh(0.0415 * (T - 218.8))
272
+ return mk05_e_sat_liquid(T) * (
273
+ 6763.22 / T**2
274
+ - 4.21 / T
275
+ + 0.000367
276
+ + 0.0415 * (1 - tanh_term**2) * (53.878 - 1331.22 / T - 9.44523 * np.log(T) + 0.014025 * T)
277
+ + tanh_term * (1331.22 / T**2 - 9.44523 / T + 0.014025)
278
+ )
279
+
280
+
281
+ # Set aliases. These could be swapped out or made configurable.
282
+ e_sat_liquid = mk05_e_sat_liquid
283
+ e_sat_liquid_prime = mk05_e_sat_liquid_prime
284
+
285
+
286
+ @support_arraylike
287
+ def _e_sat_piecewise(T: np.ndarray) -> np.ndarray:
288
+ """Calculate `e_sat_liquid` when T is above freezing otherwise `e_sat_ice`.
289
+
290
+ Parameters
291
+ ----------
292
+ T : np.ndarray
293
+ Temperature, [:math:`K`]
294
+
295
+ Returns
296
+ -------
297
+ np.ndarray
298
+ Piecewise array of e_sat_liquid and e_sat_ice values.
299
+ """
300
+ condlist = [T >= -constants.absolute_zero, T < constants.absolute_zero] # noqa: SIM300
301
+ funclist = [e_sat_liquid, e_sat_ice, np.nan] # nan passed through
302
+ return np.piecewise(T, condlist, funclist)
303
+
304
+
305
+ # ----------------------------
306
+ # Saturation Specific Humidity
307
+ # ----------------------------
308
+
309
+
310
+ def q_sat(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
311
+ r"""Calculate saturation specific humidity over liquid or ice.
312
+
313
+ When T is above 0 C, liquid saturation is computed. Otherwise, ice saturation
314
+ is computed.
315
+
316
+ Parameters
317
+ ----------
318
+ T : ArrayScalarLike
319
+ Temperature, [:math:`K`]
320
+ p : ArrayScalarLike
321
+ Pressure, [:math:`Pa`]
322
+
323
+ Returns
324
+ -------
325
+ ArrayScalarLike
326
+ Saturation specific humidity, [:math:`kg \ kg^{-1}`]
327
+
328
+ Notes
329
+ -----
330
+ Smith et al. (1999)
331
+ """
332
+ e_sat = _e_sat_piecewise(T)
333
+ return constants.epsilon * e_sat / p
334
+
335
+
336
+ def q_sat_ice(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
337
+ r"""Calculate saturation specific humidity over ice.
338
+
339
+ Parameters
340
+ ----------
341
+ T : ArrayScalarLike
342
+ Temperature, [:math:`K`]
343
+ p : ArrayScalarLike
344
+ Pressure, [:math:`Pa`]
345
+
346
+ Returns
347
+ -------
348
+ ArrayScalarLike
349
+ Saturation specific humidity, [:math:`kg \ kg^{-1}`]
350
+
351
+ Notes
352
+ -----
353
+ Smith et al. (1999)
354
+ """
355
+ return constants.epsilon * e_sat_ice(T) / p
356
+
357
+
358
+ def q_sat_liquid(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
359
+ r"""Calculate saturation specific humidity over liquid.
360
+
361
+ Parameters
362
+ ----------
363
+ T : ArrayScalarLike
364
+ Temperature, [:math:`K`]
365
+ p : ArrayScalarLike
366
+ Pressure, [:math:`Pa`]
367
+
368
+ Returns
369
+ -------
370
+ ArrayScalarLike
371
+ Saturation specific humidity, [:math:`kg \ kg^{-1}`]
372
+
373
+ Notes
374
+ -----
375
+ Smith et al. (1999)
376
+ """
377
+ return constants.epsilon * e_sat_liquid(T) / p
378
+
379
+
380
+ # -----------------
381
+ # Relative Humidity
382
+ # -----------------
383
+
384
+
385
+ def rh(q: ArrayScalarLike, T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
386
+ r"""Calculate the relative humidity with respect to to liquid water.
387
+
388
+ Parameters
389
+ ----------
390
+ q : ArrayScalarLike
391
+ Specific humidity, [:math:`kg \ kg^{-1}`]
392
+ T : ArrayScalarLike
393
+ Temperature, [:math:`K`]
394
+ p : ArrayScalarLike
395
+ Pressure, [:math:`Pa`]
396
+
397
+ Returns
398
+ -------
399
+ ArrayScalarLike
400
+ Relative Humidity, :math:`[0 - 1]`
401
+ """
402
+ return (q * p) / (constants.epsilon * e_sat_liquid(T))
403
+
404
+
405
+ def rhi(q: ArrayScalarLike, T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
406
+ r"""Calculate the relative humidity with respect to ice (RHi).
407
+
408
+ Parameters
409
+ ----------
410
+ q : ArrayScalarLike
411
+ Specific humidity, [:math:`kg \ kg^{-1}`]
412
+ T : ArrayScalarLike
413
+ Temperature, [:math:`K`]
414
+ p : ArrayScalarLike
415
+ Pressure, [:math:`Pa`]
416
+
417
+ Returns
418
+ -------
419
+ ArrayScalarLike
420
+ Relative Humidity over ice, :math:`[0 - 1]`
421
+ """
422
+ return (q * p) / (constants.epsilon * e_sat_ice(T))
423
+
424
+
425
+ # --------------
426
+ # Met Properties
427
+ # --------------
428
+
429
+
430
+ def pressure_dz(T: ArrayScalarLike, p: ArrayScalarLike, dz: float) -> ArrayScalarLike:
431
+ r"""Calculate the pressure altitude ``dz`` meters below input pressure.
432
+
433
+ Returns surface pressure if the calculated pressure altitude is greater
434
+ than :const:`constants.p_surface`.
435
+
436
+ Parameters
437
+ ----------
438
+ T : ArrayScalarLike
439
+ Temperature, [:math:`K`]
440
+ p : ArrayScalarLike
441
+ Pressure, [:math:`Pa`]
442
+ dz : float
443
+ Difference in altitude between measurements, [:math:`m`]
444
+
445
+ Returns
446
+ -------
447
+ ArrayScalarLike
448
+ Pressure at altitude, [:math:`Pa`]
449
+
450
+ Notes
451
+ -----
452
+ This is used to calculate the temperature gradient and wind shear.
453
+ """
454
+ dp = rho_d(T, p) * constants.g * dz
455
+
456
+ # FIXME: Presently, mypy is not aware that numpy ufuncs will return `xr.DataArray``
457
+ # when xr.DataArray is passed in. This will get fixed at some point in the future
458
+ # as `numpy` their typing patterns, after which the "type: ignore" comment can
459
+ # get ripped out.
460
+ # We could explicitly check for `xr.DataArray` then use `xr.apply_ufunc`, but
461
+ # this only renders our code more boilerplate and less performant.
462
+ # This comment is pasted several places in `pycontrails` -- they should all be
463
+ # addressed at the same time.
464
+ return np.minimum(p + dp, constants.p_surface) # type: ignore[return-value]
465
+
466
+
467
+ def T_potential_gradient(
468
+ T_top: ArrayScalarLike,
469
+ p_top: ArrayScalarLike,
470
+ T_btm: ArrayScalarLike,
471
+ p_btm: ArrayScalarLike,
472
+ dz: float,
473
+ ) -> ArrayScalarLike:
474
+ r"""Calculate the potential temperature gradient between two altitudes.
475
+
476
+ Parameters
477
+ ----------
478
+ T_top : ArrayScalarLike
479
+ Temperature at original altitude, [:math:`K`]
480
+ p_top : ArrayScalarLike
481
+ Pressure at original altitude, [:math:`Pa`]
482
+ T_btm : ArrayScalarLike
483
+ Temperature at lower altitude, [:math:`K`]
484
+ p_btm : ArrayScalarLike
485
+ Pressure at lower altitude, [:math:`Pa`]
486
+ dz : float
487
+ Difference in altitude between measurements, [:math:`m`]
488
+
489
+ Returns
490
+ -------
491
+ ArrayScalarLike
492
+ Potential Temperature gradient, [:math:`K \ m^{-1}`]
493
+ """
494
+ T_potential_top = T_potential(T_top, p_top)
495
+ T_potential_btm = T_potential(T_btm, p_btm)
496
+ return (T_potential_top - T_potential_btm) / dz
497
+
498
+
499
+ def T_potential(T: ArrayScalarLike, p: ArrayScalarLike) -> ArrayScalarLike:
500
+ r"""Calculate potential temperature.
501
+
502
+ The potential temperature is the temperature that
503
+ an air parcel would attain if adiabatically
504
+ brought to a standard reference pressure, :const:`constants.p_surface`.
505
+
506
+ Parameters
507
+ ----------
508
+ T : ArrayScalarLike
509
+ Temperature , [:math:`K`]
510
+ p : ArrayScalarLike
511
+ Pressure, [:math:`Pa`]
512
+
513
+ Returns
514
+ -------
515
+ ArrayScalarLike
516
+ Potential Temperature, [:math:`K`]
517
+
518
+ References
519
+ ----------
520
+ - https://en.wikipedia.org/wiki/Potential_temperature
521
+ """
522
+ return T * (constants.p_surface / p) ** (constants.R_d / constants.c_pd)
523
+
524
+
525
+ def brunt_vaisala_frequency(p: np.ndarray, T: np.ndarray, T_grad: np.ndarray) -> np.ndarray:
526
+ r"""Calculate the Brunt-Vaisaila frequency.
527
+
528
+ The Brunt-Vaisaila frequency is the frequency at which a vertically
529
+ displaced parcel will oscillate within a statically stable environment.
530
+
531
+ Parameters
532
+ ----------
533
+ p : np.ndarray
534
+ Pressure, [:math:`Pa`]
535
+ T : np.ndarray
536
+ Temperature , [:math:`K`]
537
+ T_grad : np.ndarray
538
+ Potential Temperature gradient (see :func:`T_potential_gradient`), [:math:`K \ m^{-1}`]
539
+
540
+ Returns
541
+ -------
542
+ np.ndarray
543
+ Brunt-Vaisaila frequency, [:math:`s^{-1}`]
544
+
545
+ References
546
+ ----------
547
+ - https://en.wikipedia.org/wiki/Brunt%E2%80%93V%C3%A4is%C3%A4l%C3%A4_frequency
548
+ """
549
+ theta = T_potential(T, p)
550
+ T_grad.clip(min=1e-6, out=T_grad)
551
+ return (T_grad * constants.g / theta) ** 0.5