pycontrails 0.54.7__tar.gz → 0.54.9__tar.gz

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 (279) hide show
  1. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/workflows/release.yaml +19 -1
  2. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/workflows/scorecard.yaml +1 -1
  3. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/workflows/test.yaml +2 -2
  4. {pycontrails-0.54.7 → pycontrails-0.54.9}/CHANGELOG.md +37 -0
  5. {pycontrails-0.54.7/pycontrails.egg-info → pycontrails-0.54.9}/PKG-INFO +3 -2
  6. pycontrails-0.54.9/docs/_static/img/favicon.png +0 -0
  7. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/index.rst +1 -1
  8. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/_version.py +9 -4
  9. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/aircraft_performance.py +48 -35
  10. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/cache.py +4 -0
  11. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/flightplan.py +10 -2
  12. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/met.py +12 -7
  13. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/models.py +54 -9
  14. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/rgi_cython.c +180 -198
  15. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/vector.py +11 -3
  16. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/goes.py +146 -2
  17. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/spire/spire.py +6 -8
  18. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/ext/synthetic_flight.py +1 -1
  19. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/cocip.py +14 -5
  20. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/contrail_properties.py +4 -6
  21. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/output_formats.py +12 -4
  22. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/radiative_forcing.py +2 -8
  23. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocipgrid/cocip_grid.py +11 -11
  24. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/humidity_scaling/humidity_scaling.py +49 -4
  25. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/ps_model/ps_aircraft_params.py +1 -1
  26. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/ps_model/ps_grid.py +22 -22
  27. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/ps_model/ps_model.py +7 -13
  28. pycontrails-0.54.7/pycontrails/models/ps_model/static/ps-aircraft-params-20240524.csv → pycontrails-0.54.9/pycontrails/models/ps_model/static/ps-aircraft-params-20250328.csv +58 -57
  29. pycontrails-0.54.7/pycontrails/models/ps_model/static/ps-synonym-list-20240524.csv → pycontrails-0.54.9/pycontrails/models/ps_model/static/ps-synonym-list-20250328.csv +1 -0
  30. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/tau_cirrus.py +1 -0
  31. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/physics/jet.py +5 -4
  32. pycontrails-0.54.7/pycontrails/physics/static/iata-cargo-load-factors-20241115.csv → pycontrails-0.54.9/pycontrails/physics/static/iata-cargo-load-factors-20250221.csv +3 -0
  33. pycontrails-0.54.7/pycontrails/physics/static/iata-passenger-load-factors-20241115.csv → pycontrails-0.54.9/pycontrails/physics/static/iata-passenger-load-factors-20250221.csv +3 -0
  34. {pycontrails-0.54.7 → pycontrails-0.54.9/pycontrails.egg-info}/PKG-INFO +3 -2
  35. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails.egg-info/SOURCES.txt +4 -4
  36. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_cocip_grid_parity.py +1 -1
  37. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_flight.py +1 -1
  38. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_flightplan.py +15 -5
  39. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_goes.py +76 -0
  40. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_grid_to_netcdf.py +2 -1
  41. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_humidity_scaling.py +53 -5
  42. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_ps_model.py +44 -12
  43. pycontrails-0.54.7/docs/_static/img/favicon.png +0 -0
  44. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  45. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  46. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/dependabot.yaml +0 -0
  47. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/pull_request_template.md +0 -0
  48. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/workflows/docs.yaml +0 -0
  49. {pycontrails-0.54.7 → pycontrails-0.54.9}/.github/workflows/doctest.yaml +0 -0
  50. {pycontrails-0.54.7 → pycontrails-0.54.9}/.gitignore +0 -0
  51. {pycontrails-0.54.7 → pycontrails-0.54.9}/.pre-commit-config.yaml +0 -0
  52. {pycontrails-0.54.7 → pycontrails-0.54.9}/.zenodo.json +0 -0
  53. {pycontrails-0.54.7 → pycontrails-0.54.9}/CONTRIBUTING.md +0 -0
  54. {pycontrails-0.54.7 → pycontrails-0.54.9}/LICENSE +0 -0
  55. {pycontrails-0.54.7 → pycontrails-0.54.9}/Makefile +0 -0
  56. {pycontrails-0.54.7 → pycontrails-0.54.9}/NOTICE +0 -0
  57. {pycontrails-0.54.7 → pycontrails-0.54.9}/README.md +0 -0
  58. {pycontrails-0.54.7 → pycontrails-0.54.9}/RELEASE.md +0 -0
  59. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/_static/css/style.css +0 -0
  60. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/_static/img/colab.png +0 -0
  61. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/_static/img/logo-dark.png +0 -0
  62. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/_static/img/logo.png +0 -0
  63. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/_static/pycontrails.bib +0 -0
  64. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/api.rst +0 -0
  65. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/changelog.rst +0 -0
  66. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/conf.py +0 -0
  67. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/contributing.rst +0 -0
  68. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/develop.rst +0 -0
  69. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/flight.rst +0 -0
  70. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/install.rst +0 -0
  71. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/integrations/ACCF.ipynb +0 -0
  72. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/integrations/APCEMM.ipynb +0 -0
  73. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/literature.rst +0 -0
  74. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/meteorology.rst +0 -0
  75. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/models.rst +0 -0
  76. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/ARCO-ERA5.ipynb +0 -0
  77. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/AircraftPerformance.ipynb +0 -0
  78. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/Cache.ipynb +0 -0
  79. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/CoCiP.ipynb +0 -0
  80. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/CoCiPGrid.ipynb +0 -0
  81. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/ECMWF.ipynb +0 -0
  82. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/Flight.ipynb +0 -0
  83. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/GFS.ipynb +0 -0
  84. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/GOES.ipynb +0 -0
  85. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/ISSR.ipynb +0 -0
  86. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/Landsat.ipynb +0 -0
  87. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/Meteorology.ipynb +0 -0
  88. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/SAC.ipynb +0 -0
  89. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/Sentinel.ipynb +0 -0
  90. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/advection.ipynb +0 -0
  91. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/airports.ipynb +0 -0
  92. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/.gitignore +0 -0
  93. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/flight-ap.csv +0 -0
  94. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/flight-cocip.csv +0 -0
  95. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/flight-fdr.csv +0 -0
  96. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/flight-noisy.csv +0 -0
  97. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/flight.csv +0 -0
  98. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/iagos-flight-landsat.csv +0 -0
  99. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/data/iagos-flight-sentinel.csv +0 -0
  100. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/flightplan.ipynb +0 -0
  101. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/model-levels.ipynb +0 -0
  102. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/run-cocip-on-flight.ipynb +0 -0
  103. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/run-cocip-with-fdr.ipynb +0 -0
  104. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks/specific-humidity-interpolation.ipynb +0 -0
  105. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/notebooks.rst +0 -0
  106. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/observations.rst +0 -0
  107. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/tutorials.rst +0 -0
  108. {pycontrails-0.54.7 → pycontrails-0.54.9}/docs/utilities.rst +0 -0
  109. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/__init__.py +0 -0
  110. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/__init__.py +0 -0
  111. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/airports.py +0 -0
  112. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/coordinates.py +0 -0
  113. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/fleet.py +0 -0
  114. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/flight.py +0 -0
  115. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/fuel.py +0 -0
  116. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/interpolation.py +0 -0
  117. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/met_var.py +0 -0
  118. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/polygon.py +0 -0
  119. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/core/rgi_cython.pyx +0 -0
  120. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/__init__.py +0 -0
  121. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/_leo_utils/search.py +0 -0
  122. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/_leo_utils/static/bq_roi_query.sql +0 -0
  123. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/_leo_utils/vis.py +0 -0
  124. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/_met_utils/metsource.py +0 -0
  125. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/__init__.py +0 -0
  126. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/arco_era5.py +0 -0
  127. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/common.py +0 -0
  128. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/era5.py +0 -0
  129. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/era5_model_level.py +0 -0
  130. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/hres.py +0 -0
  131. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/hres_model_level.py +0 -0
  132. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/ifs.py +0 -0
  133. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/model_levels.py +0 -0
  134. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +0 -0
  135. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/ecmwf/variables.py +0 -0
  136. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/gfs/__init__.py +0 -0
  137. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/gfs/gfs.py +0 -0
  138. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/gfs/variables.py +0 -0
  139. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/landsat.py +0 -0
  140. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/sentinel.py +0 -0
  141. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/spire/__init__.py +0 -0
  142. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/datalib/spire/exceptions.py +0 -0
  143. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/ext/bada.py +0 -0
  144. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/ext/cirium.py +0 -0
  145. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/ext/empirical_grid.py +0 -0
  146. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/__init__.py +0 -0
  147. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/accf.py +0 -0
  148. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/apcemm/__init__.py +0 -0
  149. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/apcemm/apcemm.py +0 -0
  150. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/apcemm/inputs.py +0 -0
  151. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +0 -0
  152. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/apcemm/utils.py +0 -0
  153. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/__init__.py +0 -0
  154. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/cocip_params.py +0 -0
  155. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/cocip_uncertainty.py +0 -0
  156. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/radiative_heating.py +0 -0
  157. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/unterstrasser_wake_vortex.py +0 -0
  158. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/wake_vortex.py +0 -0
  159. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocip/wind_shear.py +0 -0
  160. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocipgrid/__init__.py +0 -0
  161. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/cocipgrid/cocip_grid_params.py +0 -0
  162. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/dry_advection.py +0 -0
  163. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/emissions/__init__.py +0 -0
  164. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/emissions/black_carbon.py +0 -0
  165. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/emissions/emissions.py +0 -0
  166. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/emissions/ffm2.py +0 -0
  167. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/emissions/static/default-engine-uids.csv +0 -0
  168. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +0 -0
  169. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +0 -0
  170. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/humidity_scaling/__init__.py +0 -0
  171. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
  172. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
  173. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/issr.py +0 -0
  174. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/pcc.py +0 -0
  175. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/pcr.py +0 -0
  176. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/ps_model/__init__.py +0 -0
  177. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/ps_model/ps_operational_limits.py +0 -0
  178. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/models/sac.py +0 -0
  179. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/physics/__init__.py +0 -0
  180. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/physics/constants.py +0 -0
  181. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/physics/geo.py +0 -0
  182. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/physics/thermo.py +0 -0
  183. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/physics/units.py +0 -0
  184. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/py.typed +0 -0
  185. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/utils/__init__.py +0 -0
  186. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/utils/dependencies.py +0 -0
  187. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/utils/iteration.py +0 -0
  188. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/utils/json.py +0 -0
  189. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/utils/temp.py +0 -0
  190. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails/utils/types.py +0 -0
  191. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails.egg-info/dependency_links.txt +0 -0
  192. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails.egg-info/requires.txt +0 -0
  193. {pycontrails-0.54.7 → pycontrails-0.54.9}/pycontrails.egg-info/top_level.txt +0 -0
  194. {pycontrails-0.54.7 → pycontrails-0.54.9}/pyproject.toml +0 -0
  195. {pycontrails-0.54.7 → pycontrails-0.54.9}/setup.cfg +0 -0
  196. {pycontrails-0.54.7 → pycontrails-0.54.9}/setup.py +0 -0
  197. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/__init__.py +0 -0
  198. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/_deprecated.py +0 -0
  199. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip/Makefile +0 -0
  200. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip/README.md +0 -0
  201. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip/benchmark.py +0 -0
  202. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip/compare.py +0 -0
  203. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip/data.md +0 -0
  204. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip/output.py +0 -0
  205. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip/review.ipynb +0 -0
  206. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/cocip-fortran/README.md +0 -0
  207. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/north-atlantic-study/.gcloudignore +0 -0
  208. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/north-atlantic-study/README.md +0 -0
  209. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/north-atlantic-study/support.py +0 -0
  210. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/benchmark/north-atlantic-study/validate.py +0 -0
  211. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/fixtures/cocip-met.py +0 -0
  212. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/fixtures/cocip-met2.py +0 -0
  213. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/fixtures/ecmwf-met.py +0 -0
  214. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/fixtures/gfs-met.py +0 -0
  215. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/__init__.py +0 -0
  216. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/conftest.py +0 -0
  217. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/NOAA_Solar_Calculations_day.csv +0 -0
  218. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/cocip-contrail-output.json +0 -0
  219. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/cocip-contrail-output2.json +0 -0
  220. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/cocip-flight-output.json +0 -0
  221. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/cocip-flight-output2.json +0 -0
  222. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/cocip-output-contrail-edges.json +0 -0
  223. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/cocip-output-flts-20190101-eu.pq +0 -0
  224. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/flight-cocip2.csv +0 -0
  225. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/flight-meridian.csv +0 -0
  226. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/flight-metadata.json +0 -0
  227. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/flight-spire-data-cleaning.pq +0 -0
  228. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/flight.csv +0 -0
  229. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/flt-wypts-20190101-eu.pq +0 -0
  230. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-20190101-eu.nc +0 -0
  231. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-accf-pl.nc +0 -0
  232. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-accf-sl.nc +0 -0
  233. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-ecmwf-lnsp.nc +0 -0
  234. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-ecmwf-ml.nc +0 -0
  235. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-ecmwf-pl.nc +0 -0
  236. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-ecmwf-sl.nc +0 -0
  237. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-era5-cocip1.nc +0 -0
  238. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-era5-cocip2.nc +0 -0
  239. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/met-gfs.nc +0 -0
  240. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/polygon-bug.nc +0 -0
  241. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/rad-20190101-eu.nc +0 -0
  242. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/rad-era5-cocip1.nc +0 -0
  243. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/rad-era5-cocip2.nc +0 -0
  244. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/static/rad-gfs.nc +0 -0
  245. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_accf.py +0 -0
  246. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_airports.py +0 -0
  247. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_apcemm.py +0 -0
  248. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_cache.py +0 -0
  249. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_cocip.py +0 -0
  250. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_cocip_grid.py +0 -0
  251. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_cocip_radiative_forcing.py +0 -0
  252. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_cocip_uncertainty.py +0 -0
  253. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_coordinates.py +0 -0
  254. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_datalib_metsource.py +0 -0
  255. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_dry_advection.py +0 -0
  256. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_dtypes.py +0 -0
  257. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_ecmwf.py +0 -0
  258. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_emissions.py +0 -0
  259. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_fleet.py +0 -0
  260. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_fuel.py +0 -0
  261. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_geo.py +0 -0
  262. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_gfs.py +0 -0
  263. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_init.py +0 -0
  264. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_interpolation.py +0 -0
  265. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_leo.py +0 -0
  266. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_met.py +0 -0
  267. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_met_cache.py +0 -0
  268. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_models.py +0 -0
  269. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_pcc.py +0 -0
  270. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_polygons.py +0 -0
  271. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_sac_issr.py +0 -0
  272. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_spire.py +0 -0
  273. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_tau_cirrus.py +0 -0
  274. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_thermo_sac.py +0 -0
  275. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_units.py +0 -0
  276. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_unterstrasser_wake_vortex.py +0 -0
  277. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_utils.py +0 -0
  278. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_vector.py +0 -0
  279. {pycontrails-0.54.7 → pycontrails-0.54.9}/tests/unit/test_zarr.py +0 -0
@@ -40,7 +40,7 @@ jobs:
40
40
 
41
41
  # https://cibuildwheel.readthedocs.io/en/stable/options/#testing
42
42
  - name: Build wheels
43
- uses: pypa/cibuildwheel@v2.22
43
+ uses: pypa/cibuildwheel@v2.23
44
44
  env:
45
45
  CIBW_BUILD: cp310-* cp311-* cp312-* cp313-*
46
46
  CIBW_SKIP: '*-win32 *-manylinux_i686 *-musllinux*'
@@ -145,3 +145,21 @@ jobs:
145
145
 
146
146
  - name: Publish distribution 📦 to PyPI
147
147
  uses: pypa/gh-action-pypi-publish@release/v1
148
+
149
+ run-pycontrails-bada-tests:
150
+ # Run the test workflow in pycontrails-bada after publishing to PyPI
151
+ if: ${{ github.event_name == 'release'}}
152
+ needs:
153
+ - publish-to-pypi
154
+
155
+ runs-on: ubuntu-latest
156
+ steps:
157
+ - name: Trigger pycontrails-bada tests
158
+ run: |
159
+ gh api \
160
+ --method POST \
161
+ -H "Accept: application/vnd.github.v3+json" \
162
+ /repos/contrailcirrus/pycontrails-bada/dispatches \
163
+ -f event_type="pycontrails-release"
164
+ env:
165
+ GH_TOKEN: ${{ secrets.GH_ROBOT_USER_PAT }}
@@ -30,7 +30,7 @@ jobs:
30
30
  - uses: actions/checkout@v4
31
31
 
32
32
  - name: Run OpenSSF Security Scorecard
33
- uses: ossf/scorecard-action@v2.4.0
33
+ uses: ossf/scorecard-action@v2.4.1
34
34
  with:
35
35
  results_file: results.sarif
36
36
  results_format: sarif
@@ -70,8 +70,8 @@ jobs:
70
70
  - name: Set up Cloud SDK
71
71
  uses: google-github-actions/setup-gcloud@v2
72
72
 
73
- # download BADA files for testing
74
- - name: BADA files
73
+ - name: Download BADA files
74
+ timeout-minutes: 5 # `gcloud storage cp` occasionally hangs on windows
75
75
  run: |
76
76
  mkdir -p ${{ env.BADA_CACHE_DIR }}
77
77
  gcloud storage cp -r gs://contrails-301217-bada/bada/bada3 ${{ env.BADA_CACHE_DIR }}
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.54.9
4
+
5
+ ### Features
6
+
7
+ - Include new `goes.correct_parallax` function in the `GOES` datalib to correct for parallax artifacts in GOES imagery. This function can be used to better superimpose flight and contrail data over GOES imagery.
8
+
9
+ ### Breaking changes
10
+
11
+ - Air temperature is now an optional met variable in `PSFlight`. Code that uses `PSFlight.met_variables` may need to be updated.
12
+ - The `ensure_true_airspeed_on_source` method of the `AircraftPerformance` class now operates fully in-place and no longer returns a value. Code that relies on a return value may need to be updated.
13
+ - The `PSFlight.eval_flight` method now retrieves all inputs to performance calculations from the `Flight` parameter rather than the `PSFlight` model source. Code may need to be updated if constants for `aircraft_mass`, `thrust`, `engine_efficiency`, or `fuel_flow` were stored as attributes in a `Fleet`, as these attributes are lost when a `Fleet` is converted to a `Flight` list prior to calling `eval_flight`.
14
+
15
+ ### Internals
16
+
17
+ - Define `default_parameters`, `met_variables`, and `optional_met_variables` for the `AircraftPerformance` abstract base class.
18
+ - Remove the definitions of `met_variables` and `optional_met_variables` from `PSFlight`. These are now inherited from `AircraftPerformance`.
19
+ - Retrieve aircraft mass, thrust, engine efficiency, and fuel flow from `Flight` parameter rather than model source in `PSFlight.eval_flight`.
20
+ - Automatically run the [pycontrails-bada test](https://github.com/contrailcirrus/pycontrails-bada/actions/workflows/test.yml) workflow after publishing pycontrails release to PyPI.
21
+
22
+ ## 0.54.8
23
+
24
+ ### Features
25
+
26
+ - Update the Poll-Schumann Aircraft Performance model:
27
+ - Support the Support Boeing 737 MAX 10 aircraft type.
28
+ - Update aircraft maximum landing weight, maximum zero fuel weight, operating empty weight, and maximum payload within the static CSVs for existing aircraft types as recommended by Ian Poll.
29
+ - Add `ExponentialBoostLatitudeCorrectionHumidityScaling` calibrated for model-level ERA5 data.
30
+
31
+ ### Internals
32
+
33
+ - Update the `pycontrails.physics.static` CSV files to include newly released global and regional passenger and cargo load factor data from IATA (Oct-2024 to Dec-2024).
34
+ - Attach `n_ice_per_m_0` and `f_surv` to the downwash flight computed in the `Cocip` runtime. This data is now saved as part of the `Cocip` output.
35
+ - Rename and modify `contrail_properties.ice_particle_number` to `contrail_properties.initial_ice_particle_number`.
36
+ - Rename `ValidateTrajectoryHandler.CRUISE_ROCD_THRESHOLD_FPS` -> `ValidateTrajectoryHandler.ROCD_THRESHOLD_FPS`. Update its value from 4.2 ft/sec -> 83.25 ft/sec.
37
+ - Remove the altitude filter on the `ValidateTrajectoryHandler` ROCD check. Now all waypoints are checked for ROCD violations.
38
+ - Correctly parse "DOF" (departure date) field from flight plan in the `flightplan` module.
39
+
3
40
  ## v0.54.7
4
41
 
5
42
  ### Features
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pycontrails
3
- Version: 0.54.7
3
+ Version: 0.54.9
4
4
  Summary: Python library for modeling aviation climate impacts
5
5
  Author-email: "Contrails.org" <py@contrails.org>
6
6
  License: Apache-2.0
@@ -111,6 +111,7 @@ Provides-Extra: zarr
111
111
  Requires-Dist: fsspec>=2022.7.1; extra == "zarr"
112
112
  Requires-Dist: gcsfs>=2022.7.1; extra == "zarr"
113
113
  Requires-Dist: zarr>=2.12; extra == "zarr"
114
+ Dynamic: license-file
114
115
 
115
116
  # pycontrails
116
117
 
@@ -4,7 +4,7 @@ pycontrails
4
4
 
5
5
  *Python library for modeling contrails and other aviation climate impacts.*
6
6
 
7
- Learn more on `contrails.org <https://contrails.org>`_.
7
+ Learn more at `Contrails.org <https://contrails.org>`_.
8
8
 
9
9
  .. list-table::
10
10
  :widths: 30 70
@@ -1,8 +1,13 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
3
6
  TYPE_CHECKING = False
4
7
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
8
+ from typing import Tuple
9
+ from typing import Union
10
+
6
11
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
12
  else:
8
13
  VERSION_TUPLE = object
@@ -12,5 +17,5 @@ __version__: str
12
17
  __version_tuple__: VERSION_TUPLE
13
18
  version_tuple: VERSION_TUPLE
14
19
 
15
- __version__ = version = '0.54.7'
16
- __version_tuple__ = version_tuple = (0, 54, 7)
20
+ __version__ = version = '0.54.9'
21
+ __version_tuple__ = version_tuple = (0, 54, 9)
@@ -4,15 +4,9 @@ from __future__ import annotations
4
4
 
5
5
  import abc
6
6
  import dataclasses
7
- import sys
8
7
  import warnings
9
8
  from typing import Any, Generic, NoReturn, overload
10
9
 
11
- if sys.version_info >= (3, 12):
12
- from typing import override
13
- else:
14
- from typing_extensions import override
15
-
16
10
  import numpy as np
17
11
  import numpy.typing as npt
18
12
 
@@ -20,6 +14,7 @@ from pycontrails.core import flight, fuel
20
14
  from pycontrails.core.fleet import Fleet
21
15
  from pycontrails.core.flight import Flight
22
16
  from pycontrails.core.met import MetDataset
17
+ from pycontrails.core.met_var import AirTemperature, EastwardWind, MetVariable, NorthwardWind
23
18
  from pycontrails.core.models import Model, ModelParams, interpolate_met
24
19
  from pycontrails.core.vector import GeoVectorDataset
25
20
  from pycontrails.physics import jet
@@ -97,6 +92,9 @@ class AircraftPerformance(Model):
97
92
  """
98
93
 
99
94
  source: Flight
95
+ met_variables: tuple[MetVariable, ...] = ()
96
+ optional_met_variables: tuple[MetVariable, ...] = (AirTemperature, EastwardWind, NorthwardWind)
97
+ default_params = AircraftPerformanceParams
100
98
 
101
99
  @overload
102
100
  def eval(self, source: Fleet, **params: Any) -> Fleet: ...
@@ -129,7 +127,8 @@ class AircraftPerformance(Model):
129
127
  self.set_source_met()
130
128
  self._cleanup_indices()
131
129
 
132
- # Calculate true airspeed if not included on source
130
+ # Calculate temperature and true airspeed if not included on source
131
+ self.ensure_air_temperature_on_source()
133
132
  self.ensure_true_airspeed_on_source()
134
133
 
135
134
  if isinstance(self.source, Fleet):
@@ -162,23 +161,6 @@ class AircraftPerformance(Model):
162
161
  - ``total_fuel_burn``: total fuel burn, [:math:`kg`]
163
162
  """
164
163
 
165
- @override
166
- def set_source_met(self, *args: Any, **kwargs: Any) -> None:
167
- fill_with_isa = self.params["fill_low_altitude_with_isa_temperature"]
168
- if fill_with_isa and (self.met is None or "air_temperature" not in self.met):
169
- if "air_temperature" in self.source:
170
- _fill_low_altitude_with_isa_temperature(self.source, 0.0)
171
- else:
172
- self.source["air_temperature"] = self.source.T_isa()
173
- fill_with_isa = False # we've just filled it
174
-
175
- super().set_source_met(*args, **kwargs)
176
- if not fill_with_isa:
177
- return
178
-
179
- met_level_0 = self.met.data["level"][-1].item() # type: ignore[union-attr]
180
- _fill_low_altitude_with_isa_temperature(self.source, met_level_0)
181
-
182
164
  def simulate_fuel_and_performance(
183
165
  self,
184
166
  *,
@@ -491,25 +473,57 @@ class AircraftPerformance(Model):
491
473
  Derived performance metrics at each waypoint.
492
474
  """
493
475
 
494
- def ensure_true_airspeed_on_source(self) -> npt.NDArray[np.floating]:
476
+ def ensure_air_temperature_on_source(self) -> None:
477
+ """Add ``air_temperature`` field to :attr:`source` data if not already present.
478
+
479
+ This function operates in-place. If ``air_temperature`` is not already present
480
+ on :attr:`source`, it is calculated by interpolation from met data.
481
+ """
482
+ fill_with_isa = self.params["fill_low_altitude_with_isa_temperature"]
483
+
484
+ if "air_temperature" in self.source:
485
+ if not fill_with_isa:
486
+ return
487
+ _fill_low_altitude_with_isa_temperature(self.source, 0.0)
488
+ return
489
+
490
+ temp_available = self.met is not None and "air_temperature" in self.met
491
+
492
+ if not temp_available:
493
+ if fill_with_isa:
494
+ self.source["air_temperature"] = self.source.T_isa()
495
+ return
496
+ msg = (
497
+ "Cannot compute air temperature without providing met data that includes an "
498
+ "'air_temperature' variable. Either include met data with 'air_temperature' "
499
+ "in the model constructor, define 'air_temperature' data on the flight, or set "
500
+ "'fill_low_altitude_with_isa_temperature' to True."
501
+ )
502
+ raise ValueError(msg)
503
+
504
+ interpolate_met(self.met, self.source, "air_temperature", **self.interp_kwargs)
505
+
506
+ if not fill_with_isa:
507
+ return
508
+
509
+ met_level_0 = self.met.data["level"][-1].item() # type: ignore[union-attr]
510
+ _fill_low_altitude_with_isa_temperature(self.source, met_level_0)
511
+
512
+ def ensure_true_airspeed_on_source(self) -> None:
495
513
  """Add ``true_airspeed`` field to :attr:`source` data if not already present.
496
514
 
497
- Returns
498
- -------
499
- npt.NDArray[np.floating]
500
- True airspeed, [:math:`m s^{-1}`]. If ``true_airspeed`` is already present
501
- on :attr:`source`, this is returned directly. Otherwise, it is calculated
502
- using :meth:`Flight.segment_true_airspeed`.
515
+ This function operates in-place. If ``true_airspeed`` is not already present
516
+ on :attr:`source`, it is calculated using :meth:`Flight.segment_true_airspeed`.
503
517
  """
504
518
  tas = self.source.get("true_airspeed")
505
519
  fill_with_groundspeed = self.params["fill_low_altitude_with_zero_wind"]
506
520
 
507
521
  if tas is not None:
508
522
  if not fill_with_groundspeed:
509
- return tas
523
+ return
510
524
  cond = np.isnan(tas)
511
525
  tas[cond] = self.source.segment_groundspeed()[cond]
512
- return tas
526
+ return
513
527
 
514
528
  # Use current cocip convention: eastward_wind on met, u_wind on source
515
529
  wind_available = ("u_wind" in self.source and "v_wind" in self.source) or (
@@ -520,7 +534,7 @@ class AircraftPerformance(Model):
520
534
  if fill_with_groundspeed:
521
535
  tas = self.source.segment_groundspeed()
522
536
  self.source["true_airspeed"] = tas
523
- return tas
537
+ return
524
538
  msg = (
525
539
  "Cannot compute 'true_airspeed' without 'eastward_wind' and 'northward_wind' "
526
540
  "met data. Either include met data in the model constructor, define "
@@ -545,7 +559,6 @@ class AircraftPerformance(Model):
545
559
 
546
560
  out = self.source.segment_true_airspeed(u, v)
547
561
  self.source["true_airspeed"] = out
548
- return out
549
562
 
550
563
 
551
564
  @dataclasses.dataclass
@@ -266,6 +266,8 @@ class DiskCacheStore(CacheStore):
266
266
  >>> # put a file directly
267
267
  >>> disk_cache.put("README.md", "test/file.md")
268
268
  'test/file.md'
269
+
270
+ >>> disk_cache.clear() # cleanup
269
271
  """
270
272
 
271
273
  if not pathlib.Path(data_path).is_file():
@@ -312,6 +314,8 @@ class DiskCacheStore(CacheStore):
312
314
  >>> # returns a path
313
315
  >>> disk_cache.get("test/file.md")
314
316
  'cache/test/file.md'
317
+
318
+ >>> disk_cache.clear() # cleanup
315
319
  """
316
320
  return self.path(cache_path)
317
321
 
@@ -38,10 +38,13 @@ def to_atc_plan(plan: dict[str, Any]) -> str:
38
38
  if "second_alt_icao" in plan:
39
39
  ret += f" {plan['second_alt_icao']}"
40
40
  ret += "\n"
41
- ret += f"-{plan['other_info']})\n"
41
+ ret += f"-{plan['other_info']}"
42
42
  if "supplementary_info" in plan:
43
+ ret += "\n-"
43
44
  ret += " ".join([f"{i[0]}/{i[1]}" for i in plan["supplementary_info"].items()])
44
45
 
46
+ ret += ")"
47
+
45
48
  if ret[-1] == "\n":
46
49
  ret = ret[:-1]
47
50
 
@@ -194,7 +197,12 @@ def parse_atc_plan(atc_plan: str) -> dict[str, str]:
194
197
 
195
198
  # Other info
196
199
  if len(basic) > 8:
197
- flightplan["other_info"] = basic[8]
200
+ info = basic[8]
201
+ idx = info.find("DOF")
202
+ if idx != -1:
203
+ flightplan["departure_date"] = info[idx + 4 : idx + 10]
204
+
205
+ flightplan["other_info"] = info.strip()
198
206
 
199
207
  # Supl. Info
200
208
  if len(basic) > 9:
@@ -2643,19 +2643,24 @@ def downselect(data: XArrayType, bbox: tuple[float, ...]) -> XArrayType:
2643
2643
  "or length 6 [west, south, min-level, east, north, max-level]"
2644
2644
  )
2645
2645
 
2646
+ if west <= east:
2647
+ # Return a view of the data
2648
+ # If data is lazy, this will not load the data
2649
+ return data.sel(
2650
+ longitude=slice(west, east),
2651
+ latitude=slice(south, north),
2652
+ level=slice(level_min, level_max),
2653
+ )
2654
+
2655
+ # In this case, the bbox spans the antimeridian
2656
+ # If data is lazy, this will load the data (data.where is not lazy AFAIK)
2646
2657
  cond = (
2647
2658
  (data["latitude"] >= south)
2648
2659
  & (data["latitude"] <= north)
2649
2660
  & (data["level"] >= level_min)
2650
2661
  & (data["level"] <= level_max)
2662
+ & ((data["longitude"] >= west) | (data["longitude"] <= east))
2651
2663
  )
2652
-
2653
- # wrapping longitude
2654
- if west <= east:
2655
- cond = cond & (data["longitude"] >= west) & (data["longitude"] <= east)
2656
- else:
2657
- cond = cond & ((data["longitude"] >= west) | (data["longitude"] <= east))
2658
-
2659
2664
  return data.where(cond, drop=True)
2660
2665
 
2661
2666
 
@@ -706,17 +706,20 @@ class Model(ABC):
706
706
  # https://github.com/python/cpython/blob/618b7a8260bb40290d6551f24885931077309590/Lib/collections/__init__.py#L231
707
707
  __marker = object()
708
708
 
709
- def get_source_param(self, key: str, default: Any = __marker, *, set_attr: bool = True) -> Any:
710
- """Get source data with default set by parameter key.
709
+ def get_data_param(
710
+ self, other: SourceType, key: str, default: Any = __marker, *, set_attr: bool = True
711
+ ) -> Any:
712
+ """Get data from other source-compatible object with default set by model parameter key.
711
713
 
712
714
  Retrieves data with the following hierarchy:
713
715
 
714
- 1. :attr:`source.data[key]`. Returns ``np.ndarray | xr.DataArray``.
715
- 2. :attr:`source.attrs[key]`
716
+ 1. :attr:`other.data[key]`. Returns ``np.ndarray | xr.DataArray``.
717
+ 2. :attr:`other.attrs[key]`
716
718
  3. :attr:`params[key]`
717
719
  4. ``default``
718
720
 
719
- In case 3., the value of :attr:`params[key]` is attached to :attr:`source.attrs[key]`.
721
+ In case 3., the value of :attr:`params[key]` is attached to :attr:`other.attrs[key]`
722
+ unless ``set_attr`` is set to False.
720
723
 
721
724
  Parameters
722
725
  ----------
@@ -731,31 +734,33 @@ class Model(ABC):
731
734
  Returns
732
735
  -------
733
736
  Any
734
- Value(s) found for key in source data, source attrs, or model params
737
+ Value(s) found for key in ``other`` data, ``other`` attrs, or model params
735
738
 
736
739
  Raises
737
740
  ------
738
741
  KeyError
739
742
  Raises KeyError if key is not found in any location and ``default`` is not provided.
740
743
 
744
+
741
745
  See Also
742
746
  --------
747
+ - get_source_param
743
748
  - GeoVectorDataset.get_data_or_attr
744
749
  """
745
750
  marker = self.__marker
746
751
 
747
- out = self.source.data.get(key, marker)
752
+ out = other.data.get(key, marker)
748
753
  if out is not marker:
749
754
  return out
750
755
 
751
- out = self.source.attrs.get(key, marker)
756
+ out = other.attrs.get(key, marker)
752
757
  if out is not marker:
753
758
  return out
754
759
 
755
760
  out = self.params.get(key, marker)
756
761
  if out is not marker:
757
762
  if set_attr:
758
- self.source.attrs[key] = out
763
+ other.attrs[key] = out
759
764
 
760
765
  return out
761
766
 
@@ -765,6 +770,46 @@ class Model(ABC):
765
770
  msg = f"Key '{key}' not found in source data, attrs, or model params"
766
771
  raise KeyError(msg)
767
772
 
773
+ def get_source_param(self, key: str, default: Any = __marker, *, set_attr: bool = True) -> Any:
774
+ """Get source data with default set by parameter key.
775
+
776
+ Retrieves data with the following hierarchy:
777
+
778
+ 1. :attr:`source.data[key]`. Returns ``np.ndarray | xr.DataArray``.
779
+ 2. :attr:`source.attrs[key]`
780
+ 3. :attr:`params[key]`
781
+ 4. ``default``
782
+
783
+ In case 3., the value of :attr:`params[key]` is attached to :attr:`source.attrs[key]`
784
+ unless ``set_attr`` is set to False.
785
+
786
+ Parameters
787
+ ----------
788
+ key : str
789
+ Key to retrieve
790
+ default : Any, optional
791
+ Default value if key is not found.
792
+ set_attr : bool, optional
793
+ If True (default), set :attr:`source.attrs[key]` to :attr:`params[key]` if found.
794
+ This allows for better post model evaluation tracking.
795
+
796
+ Returns
797
+ -------
798
+ Any
799
+ Value(s) found for key in source data, source attrs, or model params
800
+
801
+ Raises
802
+ ------
803
+ KeyError
804
+ Raises KeyError if key is not found in any location and ``default`` is not provided.
805
+
806
+ See Also
807
+ --------
808
+ - get_data_param
809
+ - GeoVectorDataset.get_data_or_attr
810
+ """
811
+ return self.get_data_param(self.source, key, default, set_attr=set_attr)
812
+
768
813
  def _cleanup_indices(self) -> None:
769
814
  """Cleanup indices artifacts if ``params["interpolation_use_indices"]`` is True."""
770
815
  if self.params["interpolation_use_indices"] and isinstance(self.source, GeoVectorDataset):