pycontrails 0.54.4__tar.gz → 0.54.6__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 (276) hide show
  1. {pycontrails-0.54.4 → pycontrails-0.54.6}/CHANGELOG.md +48 -1
  2. {pycontrails-0.54.4/pycontrails.egg-info → pycontrails-0.54.6}/PKG-INFO +3 -4
  3. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/ECMWF.ipynb +8 -9
  4. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/_version.py +2 -2
  5. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/aircraft_performance.py +34 -16
  6. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/airports.py +3 -4
  7. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/fleet.py +30 -9
  8. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/flight.py +8 -5
  9. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/flightplan.py +11 -11
  10. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/interpolation.py +7 -4
  11. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/met.py +145 -86
  12. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/met_var.py +62 -0
  13. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/models.py +3 -2
  14. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/rgi_cython.c +192 -192
  15. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/vector.py +97 -74
  16. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/_met_utils/metsource.py +1 -1
  17. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/era5.py +5 -6
  18. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/era5_model_level.py +4 -5
  19. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/ifs.py +1 -3
  20. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/gfs/gfs.py +1 -3
  21. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/apcemm/apcemm.py +2 -2
  22. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/apcemm/utils.py +1 -1
  23. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/cocip.py +86 -27
  24. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/output_formats.py +1 -0
  25. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocipgrid/cocip_grid.py +8 -73
  26. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/dry_advection.py +99 -31
  27. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/emissions/emissions.py +2 -2
  28. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/humidity_scaling/humidity_scaling.py +1 -1
  29. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/issr.py +2 -2
  30. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/pcc.py +1 -2
  31. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/ps_model/ps_grid.py +2 -2
  32. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/ps_model/ps_model.py +4 -32
  33. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/ps_model/ps_operational_limits.py +2 -6
  34. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/tau_cirrus.py +13 -6
  35. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/geo.py +3 -3
  36. {pycontrails-0.54.4 → pycontrails-0.54.6/pycontrails.egg-info}/PKG-INFO +3 -4
  37. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails.egg-info/requires.txt +1 -2
  38. {pycontrails-0.54.4 → pycontrails-0.54.6}/pyproject.toml +2 -3
  39. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip/benchmark.py +2 -6
  40. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/north-atlantic-study/validate.py +3 -3
  41. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/conftest.py +61 -0
  42. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_cache.py +1 -1
  43. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_cocip.py +127 -18
  44. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_cocip_grid.py +88 -22
  45. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_dry_advection.py +38 -0
  46. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_sac_issr.py +4 -10
  47. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_vector.py +0 -4
  48. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  49. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  50. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/dependabot.yaml +0 -0
  51. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/pull_request_template.md +0 -0
  52. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/workflows/docs.yaml +0 -0
  53. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/workflows/doctest.yaml +0 -0
  54. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/workflows/release.yaml +0 -0
  55. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/workflows/scorecard.yaml +0 -0
  56. {pycontrails-0.54.4 → pycontrails-0.54.6}/.github/workflows/test.yaml +0 -0
  57. {pycontrails-0.54.4 → pycontrails-0.54.6}/.gitignore +0 -0
  58. {pycontrails-0.54.4 → pycontrails-0.54.6}/.pre-commit-config.yaml +0 -0
  59. {pycontrails-0.54.4 → pycontrails-0.54.6}/.zenodo.json +0 -0
  60. {pycontrails-0.54.4 → pycontrails-0.54.6}/CONTRIBUTING.md +0 -0
  61. {pycontrails-0.54.4 → pycontrails-0.54.6}/LICENSE +0 -0
  62. {pycontrails-0.54.4 → pycontrails-0.54.6}/Makefile +0 -0
  63. {pycontrails-0.54.4 → pycontrails-0.54.6}/NOTICE +0 -0
  64. {pycontrails-0.54.4 → pycontrails-0.54.6}/README.md +0 -0
  65. {pycontrails-0.54.4 → pycontrails-0.54.6}/RELEASE.md +0 -0
  66. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/_static/css/style.css +0 -0
  67. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/_static/img/colab.png +0 -0
  68. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/_static/img/favicon.png +0 -0
  69. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/_static/img/logo-dark.png +0 -0
  70. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/_static/img/logo.png +0 -0
  71. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/_static/pycontrails.bib +0 -0
  72. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/api.rst +0 -0
  73. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/changelog.rst +0 -0
  74. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/conf.py +0 -0
  75. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/contributing.rst +0 -0
  76. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/develop.rst +0 -0
  77. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/flight.rst +0 -0
  78. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/index.rst +0 -0
  79. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/install.rst +0 -0
  80. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/integrations/ACCF.ipynb +0 -0
  81. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/integrations/APCEMM.ipynb +0 -0
  82. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/literature.rst +0 -0
  83. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/meteorology.rst +0 -0
  84. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/models.rst +0 -0
  85. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/ARCO-ERA5.ipynb +0 -0
  86. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/AircraftPerformance.ipynb +0 -0
  87. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/Cache.ipynb +0 -0
  88. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/CoCiP.ipynb +0 -0
  89. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/CoCiPGrid.ipynb +0 -0
  90. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/Flight.ipynb +0 -0
  91. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/GFS.ipynb +0 -0
  92. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/GOES.ipynb +0 -0
  93. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/ISSR.ipynb +0 -0
  94. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/Landsat.ipynb +0 -0
  95. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/Meteorology.ipynb +0 -0
  96. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/SAC.ipynb +0 -0
  97. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/Sentinel.ipynb +0 -0
  98. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/advection.ipynb +0 -0
  99. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/airports.ipynb +0 -0
  100. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/.gitignore +0 -0
  101. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/flight-ap.csv +0 -0
  102. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/flight-cocip.csv +0 -0
  103. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/flight-fdr.csv +0 -0
  104. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/flight-noisy.csv +0 -0
  105. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/flight.csv +0 -0
  106. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/iagos-flight-landsat.csv +0 -0
  107. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/data/iagos-flight-sentinel.csv +0 -0
  108. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/flightplan.ipynb +0 -0
  109. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/model-levels.ipynb +0 -0
  110. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/run-cocip-on-flight.ipynb +0 -0
  111. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/run-cocip-with-fdr.ipynb +0 -0
  112. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks/specific-humidity-interpolation.ipynb +0 -0
  113. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/notebooks.rst +0 -0
  114. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/observations.rst +0 -0
  115. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/tutorials.rst +0 -0
  116. {pycontrails-0.54.4 → pycontrails-0.54.6}/docs/utilities.rst +0 -0
  117. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/__init__.py +0 -0
  118. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/__init__.py +0 -0
  119. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/cache.py +0 -0
  120. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/coordinates.py +0 -0
  121. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/fuel.py +0 -0
  122. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/polygon.py +0 -0
  123. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/core/rgi_cython.pyx +0 -0
  124. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/__init__.py +0 -0
  125. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/_leo_utils/search.py +0 -0
  126. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/_leo_utils/static/bq_roi_query.sql +0 -0
  127. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/_leo_utils/vis.py +0 -0
  128. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/__init__.py +0 -0
  129. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/arco_era5.py +0 -0
  130. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/common.py +0 -0
  131. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/hres.py +0 -0
  132. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/hres_model_level.py +0 -0
  133. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/model_levels.py +0 -0
  134. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +0 -0
  135. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/ecmwf/variables.py +0 -0
  136. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/gfs/__init__.py +0 -0
  137. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/gfs/variables.py +0 -0
  138. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/goes.py +0 -0
  139. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/landsat.py +0 -0
  140. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/sentinel.py +0 -0
  141. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/datalib/spire.py +0 -0
  142. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/ext/bada.py +0 -0
  143. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/ext/cirium.py +0 -0
  144. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/ext/empirical_grid.py +0 -0
  145. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/ext/synthetic_flight.py +0 -0
  146. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/__init__.py +0 -0
  147. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/accf.py +0 -0
  148. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/apcemm/__init__.py +0 -0
  149. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/apcemm/inputs.py +0 -0
  150. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +0 -0
  151. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/__init__.py +0 -0
  152. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/cocip_params.py +0 -0
  153. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/cocip_uncertainty.py +0 -0
  154. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/contrail_properties.py +0 -0
  155. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/radiative_forcing.py +0 -0
  156. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/radiative_heating.py +0 -0
  157. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/unterstrasser_wake_vortex.py +0 -0
  158. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/wake_vortex.py +0 -0
  159. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocip/wind_shear.py +0 -0
  160. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocipgrid/__init__.py +0 -0
  161. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/cocipgrid/cocip_grid_params.py +0 -0
  162. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/emissions/__init__.py +0 -0
  163. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/emissions/black_carbon.py +0 -0
  164. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/emissions/ffm2.py +0 -0
  165. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/emissions/static/default-engine-uids.csv +0 -0
  166. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +0 -0
  167. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +0 -0
  168. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/humidity_scaling/__init__.py +0 -0
  169. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
  170. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
  171. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/pcr.py +0 -0
  172. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/ps_model/__init__.py +0 -0
  173. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/ps_model/ps_aircraft_params.py +0 -0
  174. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/ps_model/static/ps-aircraft-params-20240524.csv +0 -0
  175. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/ps_model/static/ps-synonym-list-20240524.csv +0 -0
  176. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/models/sac.py +0 -0
  177. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/__init__.py +0 -0
  178. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/constants.py +0 -0
  179. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/jet.py +0 -0
  180. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/static/iata-cargo-load-factors-20241115.csv +0 -0
  181. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/static/iata-passenger-load-factors-20241115.csv +0 -0
  182. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/thermo.py +0 -0
  183. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/physics/units.py +0 -0
  184. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/py.typed +0 -0
  185. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/utils/__init__.py +0 -0
  186. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/utils/dependencies.py +0 -0
  187. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/utils/iteration.py +0 -0
  188. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/utils/json.py +0 -0
  189. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/utils/temp.py +0 -0
  190. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails/utils/types.py +0 -0
  191. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails.egg-info/SOURCES.txt +0 -0
  192. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails.egg-info/dependency_links.txt +0 -0
  193. {pycontrails-0.54.4 → pycontrails-0.54.6}/pycontrails.egg-info/top_level.txt +0 -0
  194. {pycontrails-0.54.4 → pycontrails-0.54.6}/setup.cfg +0 -0
  195. {pycontrails-0.54.4 → pycontrails-0.54.6}/setup.py +0 -0
  196. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/__init__.py +0 -0
  197. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/_deprecated.py +0 -0
  198. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip/Makefile +0 -0
  199. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip/README.md +0 -0
  200. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip/compare.py +0 -0
  201. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip/data.md +0 -0
  202. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip/output.py +0 -0
  203. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip/review.ipynb +0 -0
  204. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/cocip-fortran/README.md +0 -0
  205. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/north-atlantic-study/.gcloudignore +0 -0
  206. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/north-atlantic-study/README.md +0 -0
  207. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/benchmark/north-atlantic-study/support.py +0 -0
  208. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/fixtures/cocip-met.py +0 -0
  209. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/fixtures/cocip-met2.py +0 -0
  210. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/fixtures/ecmwf-met.py +0 -0
  211. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/fixtures/gfs-met.py +0 -0
  212. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/__init__.py +0 -0
  213. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/NOAA_Solar_Calculations_day.csv +0 -0
  214. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/cocip-contrail-output.json +0 -0
  215. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/cocip-contrail-output2.json +0 -0
  216. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/cocip-flight-output.json +0 -0
  217. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/cocip-flight-output2.json +0 -0
  218. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/cocip-output-contrail-edges.json +0 -0
  219. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/cocip-output-flts-20190101-eu.pq +0 -0
  220. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/flight-cocip2.csv +0 -0
  221. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/flight-meridian.csv +0 -0
  222. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/flight-metadata.json +0 -0
  223. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/flight-spire-data-cleaning.pq +0 -0
  224. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/flight.csv +0 -0
  225. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/flt-wypts-20190101-eu.pq +0 -0
  226. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-20190101-eu.nc +0 -0
  227. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-accf-pl.nc +0 -0
  228. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-accf-sl.nc +0 -0
  229. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-ecmwf-lnsp.nc +0 -0
  230. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-ecmwf-ml.nc +0 -0
  231. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-ecmwf-pl.nc +0 -0
  232. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-ecmwf-sl.nc +0 -0
  233. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-era5-cocip1.nc +0 -0
  234. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-era5-cocip2.nc +0 -0
  235. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/met-gfs.nc +0 -0
  236. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/polygon-bug.nc +0 -0
  237. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/rad-20190101-eu.nc +0 -0
  238. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/rad-era5-cocip1.nc +0 -0
  239. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/rad-era5-cocip2.nc +0 -0
  240. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/static/rad-gfs.nc +0 -0
  241. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_accf.py +0 -0
  242. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_airports.py +0 -0
  243. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_apcemm.py +0 -0
  244. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_cocip_grid_parity.py +0 -0
  245. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_cocip_radiative_forcing.py +0 -0
  246. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_cocip_uncertainty.py +0 -0
  247. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_coordinates.py +0 -0
  248. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_datalib_metsource.py +0 -0
  249. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_dtypes.py +0 -0
  250. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_ecmwf.py +0 -0
  251. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_emissions.py +0 -0
  252. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_fleet.py +0 -0
  253. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_flight.py +0 -0
  254. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_flightplan.py +0 -0
  255. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_fuel.py +0 -0
  256. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_geo.py +0 -0
  257. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_gfs.py +0 -0
  258. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_goes.py +0 -0
  259. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_grid_to_netcdf.py +0 -0
  260. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_humidity_scaling.py +0 -0
  261. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_init.py +0 -0
  262. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_interpolation.py +0 -0
  263. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_leo.py +0 -0
  264. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_met.py +0 -0
  265. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_met_cache.py +0 -0
  266. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_models.py +0 -0
  267. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_pcc.py +0 -0
  268. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_polygons.py +0 -0
  269. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_ps_model.py +0 -0
  270. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_spire.py +0 -0
  271. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_tau_cirrus.py +0 -0
  272. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_thermo_sac.py +0 -0
  273. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_units.py +0 -0
  274. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_unterstrasser_wake_vortex.py +0 -0
  275. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_utils.py +0 -0
  276. {pycontrails-0.54.4 → pycontrails-0.54.6}/tests/unit/test_zarr.py +0 -0
@@ -1,5 +1,52 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.54.6
4
+
5
+ ### Features
6
+
7
+ - Add support for generic (model-agnostic) meteorology data to `Cocip` and `CocipGrid`.
8
+
9
+ - Add two new parameters to the `DryAdvection` model.
10
+ - If the `verbose_outputs` parameter is enabled, additional wind-shear data is included in the output.
11
+ - If the `include_source_in_output` parameter is enabled, the source data with any of the intermediate artifacts (e.g., interpolated met data, wind-shear data, etc.) is included in the output.
12
+
13
+ Both parameters are disabled by default.
14
+
15
+ ### Fixes
16
+
17
+ - Update the CDS URL referenced throughout pycontrails from ``https://cds-beta.climate.copernicus.eu`` to ``https://cds.climate.copernicus.eu``.
18
+
19
+ ### Internals
20
+
21
+ - Suppress mypy `return-value` errors for functions in `geo.py` where mypy fails to correctly infer return types of numpy ufuncs applied to xarray objects.
22
+ - Change `AircraftPerformance` and downstream implementations for better support in running over `Fleet` sources. The runtime of `PSFlight` remains the same.
23
+
24
+ ## v0.54.5
25
+
26
+ ### Features
27
+
28
+ - This release brings a number of very minor performance improvements to the low-level pycontrails data structures (`VectorDataset` and `MetDataset`). Cumulatively, these changes should bring in a small but nontrivial speedup (~5%) when running a model such as `Cocip` or `DryAdvection` on a single `Flight` source.
29
+ - Core `Flight` methods such as `copy`, `filter`, and `downselect_met` are now ~10x faster for typical use cases.
30
+ - Converting between `Fleet` and `Flight` instances via `Fleet.from_seq` and `Fleet.to_flight_list` are also ~5x faster.
31
+ - Implement low-memory met-downselection logic in `DryAdvection`. This is the same logic used in `CocipGrid` to reduce memory consumption by only loading the necessary time slices of the `met` data into memory. If `met` is already loaded into memory, this change will have no effect.
32
+
33
+ ### Breaking Changes
34
+
35
+ - Remove the `copy` parameter from `GeovectorDataset.downselect_met`. This method always returns a view of the original dataset.
36
+ - Remove the `validate` parameter in the `MetDataArray` constructor. Input data is now always validated.
37
+
38
+ ### Fixes
39
+
40
+ - Make slightly more explicit when data is copied in the `VectorDataset` constructor: data is now always shallow-copied, and the `copy` parameter governs whether to copy the underlying arrays.
41
+ - Call `downselect_met` in `DryAdvection.eval`. (This was previously forgotten.)
42
+ - Fix minor bug in `CocipGrid` downselect met logic introduced in v0.54.4. This bug may have caused some met slices to be reloaded when running `CocipGrid.eval` with lazily-loaded `met` and `rad` data.
43
+
44
+ ### Internals
45
+
46
+ - Add internal `VectorDataset._from_fastpath` and `MetDataset._from_fastpath` class methods to skip data validation.
47
+ - Define `__slots__` on `MetBase`, `MetDataset`, `MetDataArray`, and `AttrDict`.
48
+ - When `MetDataset` and `MetDataArray` shared a common implementation, move the implementation to `MetBase`. This was the case for the `copy`, `downselect`, and `wrap_longitude` methods.
49
+
3
50
  ## v0.54.4
4
51
 
5
52
  ### Features
@@ -13,7 +60,7 @@
13
60
  1. If there is a shallow climb (ROCD < 500 ft/min), then always assume that the flight will climb at the next time step.
14
61
  1. If there is a shallow descent (-250 < ROCD < 0 ft/min), then always assume that the flight will descend at the final time step.
15
62
 
16
- Conditions (3) to (6) is based on the logic that the aircraft will generally prefer to climb to a higher altitude as early as possible, and descend to a lower altitude as late as possible, because a higher altitude can reduce drag and fuel consumption.
63
+ Conditions (3) to (6) are based on the logic that the aircraft will generally prefer to climb to a higher altitude as early as possible, and descend to a lower altitude as late as possible, because a higher altitude can reduce drag and fuel consumption.
17
64
 
18
65
  ### Breaking changes
19
66
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pycontrails
3
- Version: 0.54.4
3
+ Version: 0.54.6
4
4
  Summary: Python library for modeling aviation climate impacts
5
5
  Author-email: Breakthrough Energy <py@contrails.org>
6
6
  License: Apache-2.0
@@ -49,8 +49,7 @@ Requires-Dist: pyarrow>=5.0; extra == "dev"
49
49
  Requires-Dist: pytest>=8.2; extra == "dev"
50
50
  Requires-Dist: pytest-cov>=2.11; extra == "dev"
51
51
  Requires-Dist: requests>=2.25; extra == "dev"
52
- Requires-Dist: ruff==0.8.0; extra == "dev"
53
- Requires-Dist: setuptools; extra == "dev"
52
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
54
53
  Provides-Extra: docs
55
54
  Requires-Dist: doc8>=1.1; extra == "docs"
56
55
  Requires-Dist: furo>=2023.3; extra == "docs"
@@ -16,7 +16,7 @@
16
16
  "\n",
17
17
  "Support provided for:\n",
18
18
  "\n",
19
- "- [ERA5](https://www.ecmwf.int/en/forecasts/dataset/ecmwf-reanalysis-v5) via the [Copernicus Data Store (CDS-Beta)](https://cds-beta.climate.copernicus.eu/) using [cdsapi](https://github.com/ecmwf/cdsapi) or user provided files\n",
19
+ "- [ERA5](https://www.ecmwf.int/en/forecasts/dataset/ecmwf-reanalysis-v5) via the [Copernicus Data Store](https://cds.climate.copernicus.eu/) using [cdsapi](https://github.com/ecmwf/cdsapi) or user provided files\n",
20
20
  "- [HRES](https://confluence.ecmwf.int/display/FUG/Section+2.1.1.2+Rationale+for+High+Resolution) and [ENS](https://confluence.ecmwf.int/display/FUG/Section+2.1.2.1+Medium+Range+Ensemble+forecasts) via [MARS](https://confluence.ecmwf.int/display/UDOC/MARS+user+documentation) using [ecmwf-api-client](https://github.com/ecmwf/ecmwf-api-client) or user provided files.\n",
21
21
  "\n",
22
22
  "For both ERA5 and HRES, we provide interfaces for accessing \"pressure-level data\" (fields pre-interpolated to a fixed set of pressure levels) or \"model-level data\" (fields retrieved on the native vertical grid and [interpolated after retrieval to an arbitrary set of pressure levels](model-levels.ipynb)). We recommend using model-level data when possible, as the resolution of pressure-level data is coarse relative to the vertical scale of ice-supersaturated regions.\n",
@@ -32,8 +32,8 @@
32
32
  "\n",
33
33
  "### Access\n",
34
34
  "\n",
35
- "- Requires account with [Copernicus Data Portal](https://cds-beta.climate.copernicus.eu/)\n",
36
- "- Provide `url` and `key` credentials on input, or refer to the [CDS API Documentation](https://cds-beta.climate.copernicus.eu/how-to-api) for how to create `~/.cdsapirc` file to configure access.\n",
35
+ "- Requires account with [Copernicus Data Portal](https://cds.climate.copernicus.eu/)\n",
36
+ "- Provide `url` and `key` credentials on input, or refer to the [CDS API Documentation](https://cds.climate.copernicus.eu/how-to-api) for how to create `~/.cdsapirc` file to configure access.\n",
37
37
  "\n",
38
38
  "### Reference\n",
39
39
  "\n",
@@ -87,7 +87,7 @@
87
87
  " time=\"2022-03-01 00:00:00\",\n",
88
88
  " variables=[\"t\", \"q\", \"u\", \"v\", \"w\", \"ciwc\", \"z\", \"cc\"], # supports CF name or short names\n",
89
89
  " pressure_levels=[200, 250, 300],\n",
90
- " # url=\"https://cds-beta.climate.copernicus.eu/api\",\n",
90
+ " # url=\"https://cds.climate.copernicus.eu/api\",\n",
91
91
  " # key=\"<key>\"\n",
92
92
  ")\n",
93
93
  "era5"
@@ -132,7 +132,7 @@
132
132
  " \"cc\",\n",
133
133
  " ], # supports CF name or short names\n",
134
134
  " pressure_levels=[300, 250, 200],\n",
135
- " # url=\"https://cds-beta.climate.copernicus.eu/api\",\n",
135
+ " # url=\"https://cds.climate.copernicus.eu/api\",\n",
136
136
  " # key=\"<key>\"\n",
137
137
  ")\n",
138
138
  "era5"
@@ -1429,7 +1429,7 @@
1429
1429
  "era5 = ERA5(\n",
1430
1430
  " time=(\"2022-03-01 00:00:00\", \"2022-03-01 03:00:00\"),\n",
1431
1431
  " variables=[\"tsr\", \"ttr\"],\n",
1432
- " # url=\"https://cds-beta.climate.copernicus.eu/api\",\n",
1432
+ " # url=\"https://cds.climate.copernicus.eu/api\",\n",
1433
1433
  " # key=\"<key>\"\n",
1434
1434
  ")\n",
1435
1435
  "era5"
@@ -3242,8 +3242,7 @@
3242
3242
  "\n",
3243
3243
  "### Access\n",
3244
3244
  "\n",
3245
- "Users within ECMWF Member and Co-operating States may contact their Computing Representative to obtain access to MARS. \n",
3246
- "All other users may [request a username and password](https://accounts.ecmwf.int/auth/realms/ecmwf/protocol/openid-connect/registrations?client_id=apps&response_type=code&scope=openid%20email&redirect_uri=https://www.ecmwf.int) and then [get an api key](https://api.ecmwf.int/v1/key/).\n",
3245
+ "Users within ECMWF Member and Co-operating States may contact their Computing Representative to obtain access to MARS. All other users may [request a username and password](https://confluence.ecmwf.int/display/WEBAPI/Access+MARS) and then [get an api key](https://api.ecmwf.int/v1/key/).\n",
3247
3246
  "\n",
3248
3247
  "Provide `url`, `key`, and `email` credentials on input, or see [ECMWF API Client documentation](https://github.com/ecmwf/ecmwf-api-client#configure) to configure local `~/.ecmwfapirc` file:\n",
3249
3248
  "\n",
@@ -6072,7 +6071,7 @@
6072
6071
  " variables=variables,\n",
6073
6072
  " pressure_levels=[300, 250, 150],\n",
6074
6073
  " cachestore=gcp,\n",
6075
- " # url=\"https://cds-beta.climate.copernicus.eu/api\",\n",
6074
+ " # url=\"https://cds.climate.copernicus.eu/api\",\n",
6076
6075
  " # key=\"<key>\"\n",
6077
6076
  ")"
6078
6077
  ]
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.54.4'
16
- __version_tuple__ = version_tuple = (0, 54, 4)
15
+ __version__ = version = '0.54.6'
16
+ __version_tuple__ = version_tuple = (0, 54, 6)
@@ -96,22 +96,52 @@ class AircraftPerformance(Model):
96
96
 
97
97
  source: Flight
98
98
 
99
- @abc.abstractmethod
100
99
  @overload
101
100
  def eval(self, source: Fleet, **params: Any) -> Fleet: ...
102
101
 
103
- @abc.abstractmethod
104
102
  @overload
105
103
  def eval(self, source: Flight, **params: Any) -> Flight: ...
106
104
 
107
- @abc.abstractmethod
108
105
  @overload
109
106
  def eval(self, source: None = ..., **params: Any) -> NoReturn: ...
110
107
 
111
- @abc.abstractmethod
112
108
  def eval(self, source: Flight | None = None, **params: Any) -> Flight:
113
109
  """Evaluate the aircraft performance model.
114
110
 
111
+ Parameters
112
+ ----------
113
+ source : Flight
114
+ Flight trajectory to evaluate. Can be a :class:`Flight` or :class:`Fleet`.
115
+ params : Any
116
+ Override :attr:`params` with keyword arguments.
117
+
118
+ Returns
119
+ -------
120
+ Flight
121
+ Flight trajectory with aircraft performance data.
122
+ """
123
+ self.update_params(params)
124
+ self.set_source(source)
125
+ self.source = self.require_source_type(Flight)
126
+ self.downselect_met()
127
+ self.set_source_met()
128
+ self._cleanup_indices()
129
+
130
+ # Calculate true airspeed if not included on source
131
+ self.ensure_true_airspeed_on_source()
132
+
133
+ if isinstance(self.source, Fleet):
134
+ fls = [self.eval_flight(fl) for fl in self.source.to_flight_list()]
135
+ self.source = Fleet.from_seq(fls, attrs=self.source.attrs, broadcast_numeric=False)
136
+ return self.source
137
+
138
+ self.source = self.eval_flight(self.source)
139
+ return self.source
140
+
141
+ @abc.abstractmethod
142
+ def eval_flight(self, fl: Flight) -> Flight:
143
+ """Evaluate the aircraft performance model on a single flight trajectory.
144
+
115
145
  The implementing model adds the following fields to the source flight:
116
146
 
117
147
  - ``aircraft_mass``: aircraft mass at each waypoint, [:math:`kg`]
@@ -128,18 +158,6 @@ class AircraftPerformance(Model):
128
158
  - ``max_mach``: maximum Mach number
129
159
  - ``max_altitude``: maximum altitude, [:math:`m`]
130
160
  - ``total_fuel_burn``: total fuel burn, [:math:`kg`]
131
-
132
- Parameters
133
- ----------
134
- source : Flight
135
- Flight trajectory to evaluate.
136
- params : Any
137
- Override :attr:`params` with keyword arguments.
138
-
139
- Returns
140
- -------
141
- Flight
142
- Flight trajectory with aircraft performance data.
143
161
  """
144
162
 
145
163
  @override
@@ -162,7 +162,7 @@ def find_nearest_airport(
162
162
  ) & airports["latitude"].between((latitude - bbox), (latitude + bbox))
163
163
 
164
164
  # Find the nearest airport from largest to smallest airport type
165
- search_priority = ["large_airport", "medium_airport", "small_airport"]
165
+ search_priority = ("large_airport", "medium_airport", "small_airport")
166
166
 
167
167
  for airport_type in search_priority:
168
168
  is_airport_type = airports["type"] == airport_type
@@ -171,7 +171,7 @@ def find_nearest_airport(
171
171
  if len(nearest_airports) == 1:
172
172
  return nearest_airports["icao_code"].values[0]
173
173
 
174
- elif len(nearest_airports) > 1:
174
+ if len(nearest_airports) > 1:
175
175
  distance = distance_to_airports(
176
176
  nearest_airports,
177
177
  longitude,
@@ -181,8 +181,7 @@ def find_nearest_airport(
181
181
  i_nearest = np.argmin(distance)
182
182
  return nearest_airports["icao_code"].values[i_nearest]
183
183
 
184
- else:
185
- continue
184
+ continue
186
185
 
187
186
  return None
188
187
 
@@ -133,18 +133,19 @@ class Fleet(Flight):
133
133
 
134
134
  @override
135
135
  def copy(self, **kwargs: Any) -> Self:
136
- kwargs.setdefault("fuel", self.fuel)
137
136
  kwargs.setdefault("fl_attrs", self.fl_attrs)
137
+ kwargs.setdefault("final_waypoints", self.final_waypoints)
138
138
  return super().copy(**kwargs)
139
139
 
140
140
  @override
141
141
  def filter(self, mask: npt.NDArray[np.bool_], copy: bool = True, **kwargs: Any) -> Self:
142
- kwargs.setdefault("fuel", self.fuel)
143
-
144
142
  flight_ids = set(np.unique(self["flight_id"][mask]))
145
143
  fl_attrs = {k: v for k, v in self.fl_attrs.items() if k in flight_ids}
146
144
  kwargs.setdefault("fl_attrs", fl_attrs)
147
145
 
146
+ final_waypoints = np.array(self.final_waypoints[mask], copy=copy)
147
+ kwargs.setdefault("final_waypoints", final_waypoints)
148
+
148
149
  return super().filter(mask, copy=copy, **kwargs)
149
150
 
150
151
  @override
@@ -187,8 +188,9 @@ class Fleet(Flight):
187
188
  in ``seq``.
188
189
  """
189
190
 
191
+ # Create a shallow copy because we add additional keys in _validate_fl
190
192
  def _shallow_copy(fl: Flight) -> Flight:
191
- return Flight(VectorDataDict(fl.data), attrs=fl.attrs, copy=False, fuel=fl.fuel)
193
+ return Flight._from_fastpath(fl.data, fl.attrs, fuel=fl.fuel)
192
194
 
193
195
  def _maybe_warn(fl: Flight) -> Flight:
194
196
  if not fl:
@@ -217,7 +219,18 @@ class Fleet(Flight):
217
219
  )
218
220
 
219
221
  data = {var: np.concatenate([fl[var] for fl in seq]) for var in seq[0]}
220
- return cls(data=data, attrs=attrs, copy=False, fuel=fuel, fl_attrs=fl_attrs)
222
+
223
+ final_waypoints = np.zeros(data["time"].size, dtype=bool)
224
+ final_waypoint_indices = np.cumsum([fl.size for fl in seq]) - 1
225
+ final_waypoints[final_waypoint_indices] = True
226
+
227
+ return cls._from_fastpath(
228
+ data,
229
+ attrs,
230
+ fuel=fuel,
231
+ fl_attrs=fl_attrs,
232
+ final_waypoints=final_waypoints,
233
+ )
221
234
 
222
235
  @property
223
236
  def n_flights(self) -> int:
@@ -246,11 +259,19 @@ class Fleet(Flight):
246
259
  List of Flights in the same order as was passed into the ``Fleet`` instance.
247
260
  """
248
261
  indices = self.dataframe.groupby("flight_id", sort=False).indices
262
+ if copy:
263
+ return [
264
+ Flight._from_fastpath(
265
+ {k: v[idx] for k, v in self.data.items()},
266
+ self.fl_attrs[flight_id],
267
+ fuel=self.fuel,
268
+ ).copy()
269
+ for flight_id, idx in indices.items()
270
+ ]
249
271
  return [
250
- Flight(
251
- data=VectorDataDict({k: v[idx] for k, v in self.data.items()}),
252
- attrs=self.fl_attrs[flight_id],
253
- copy=copy,
272
+ Flight._from_fastpath(
273
+ {k: v[idx] for k, v in self.data.items()},
274
+ self.fl_attrs[flight_id],
254
275
  fuel=self.fuel,
255
276
  )
256
277
  for flight_id, idx in indices.items()
@@ -891,7 +891,7 @@ class Flight(GeoVectorDataset):
891
891
  """
892
892
  methods = "geodesic", "linear"
893
893
  if fill_method not in methods:
894
- raise ValueError(f'Unknown `fill_method`. Supported methods: {", ".join(methods)}')
894
+ raise ValueError(f"Unknown `fill_method`. Supported methods: {', '.join(methods)}")
895
895
 
896
896
  # STEP 0: If self is empty, return an empty flight
897
897
  if not self:
@@ -957,7 +957,12 @@ class Flight(GeoVectorDataset):
957
957
  msg = f"{msg} Pass 'keep_original_index=True' to keep the original index."
958
958
  warnings.warn(msg)
959
959
 
960
- return type(self)(data=df, attrs=self.attrs, fuel=self.fuel)
960
+ # Reorder columns (this is unimportant but makes the output more canonical)
961
+ coord_names = ("longitude", "latitude", "altitude", "time")
962
+ df = df[[*coord_names, *[c for c in df.columns if c not in set(coord_names)]]]
963
+
964
+ data = {k: v.to_numpy() for k, v in df.items()}
965
+ return type(self)._from_fastpath(data, attrs=self.attrs, fuel=self.fuel)
961
966
 
962
967
  def clean_and_resample(
963
968
  self,
@@ -1977,9 +1982,7 @@ def filter_altitude(
1977
1982
  result[i0:i1] = altitude_filt[i0:i1]
1978
1983
 
1979
1984
  # reapply Savitzky-Golay filter to smooth climb and descent
1980
- result = _sg_filter(result, window_length=kernel_size)
1981
-
1982
- return result
1985
+ return _sg_filter(result, window_length=kernel_size)
1983
1986
 
1984
1987
 
1985
1988
  def segment_duration(
@@ -21,24 +21,24 @@ def to_atc_plan(plan: dict[str, Any]) -> str:
21
21
  --------
22
22
  :func:`parse_atc_plan`
23
23
  """
24
- ret = f'(FPL-{plan["callsign"]}-{plan["flight_rules"]}'
25
- ret += f'{plan["type_of_flight"]}\n'
24
+ ret = f"(FPL-{plan['callsign']}-{plan['flight_rules']}"
25
+ ret += f"{plan['type_of_flight']}\n"
26
26
  ret += "-"
27
27
  if "number_aircraft" in plan and plan["number_aircraft"] <= 10:
28
28
  ret += plan["number_aircraft"]
29
- ret += f'{plan["type_of_aircraft"]}/{plan["wake_category"]}-'
30
- ret += f'{plan["equipment"]}/{plan["transponder"]}\n'
31
- ret += f'-{plan["departure_icao"]}{plan["time"]}\n'
32
- ret += f'-{plan["speed_type"]}{plan["speed"]}{plan["level_type"]}'
33
- ret += f'{plan["level"]} {plan["route"]}\n'
29
+ ret += f"{plan['type_of_aircraft']}/{plan['wake_category']}-"
30
+ ret += f"{plan['equipment']}/{plan['transponder']}\n"
31
+ ret += f"-{plan['departure_icao']}{plan['time']}\n"
32
+ ret += f"-{plan['speed_type']}{plan['speed']}{plan['level_type']}"
33
+ ret += f"{plan['level']} {plan['route']}\n"
34
34
  if "destination_icao" in plan and "duration" in plan:
35
- ret += f'-{plan["destination_icao"]}{plan["duration"]}'
35
+ ret += f"-{plan['destination_icao']}{plan['duration']}"
36
36
  if "alt_icao" in plan:
37
- ret += f' {plan["alt_icao"]}'
37
+ ret += f" {plan['alt_icao']}"
38
38
  if "second_alt_icao" in plan:
39
- ret += f' {plan["second_alt_icao"]}'
39
+ ret += f" {plan['second_alt_icao']}"
40
40
  ret += "\n"
41
- ret += f'-{plan["other_info"]})\n'
41
+ ret += f"-{plan['other_info']})\n"
42
42
  if "supplementary_info" in plan:
43
43
  ret += " ".join([f"{i[0]}/{i[1]}" for i in plan["supplementary_info"].items()])
44
44
 
@@ -245,6 +245,9 @@ def _pick_method(scipy_version: str, method: str) -> str:
245
245
  str
246
246
  Interpolation method adjusted for compatibility with this class.
247
247
  """
248
+ if method == "linear":
249
+ return method
250
+
248
251
  try:
249
252
  version = scipy_version.split(".")
250
253
  major = int(version[0])
@@ -486,15 +489,15 @@ def interp(
486
489
  da = _localize(da, coords)
487
490
 
488
491
  indexes = da._indexes
489
- x = indexes["longitude"].index.to_numpy() # type: ignore[attr-defined]
490
- y = indexes["latitude"].index.to_numpy() # type: ignore[attr-defined]
491
- z = indexes["level"].index.to_numpy() # type: ignore[attr-defined]
492
+ x = indexes["longitude"].index.values # type: ignore[attr-defined]
493
+ y = indexes["latitude"].index.values # type: ignore[attr-defined]
494
+ z = indexes["level"].index.values # type: ignore[attr-defined]
492
495
  if any(v.dtype != np.float64 for v in (x, y, z)):
493
496
  msg = "da must have float64 dtype for longitude, latitude, and level coordinates"
494
497
  raise ValueError(msg)
495
498
 
496
499
  # Convert t and time to float64
497
- t = indexes["time"].index.to_numpy() # type: ignore[attr-defined]
500
+ t = indexes["time"].index.values # type: ignore[attr-defined]
498
501
  offset = t[0]
499
502
  t = _floatize_time(t, offset)
500
503