pycontrails 0.54.8__tar.gz → 0.54.10__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 (278) hide show
  1. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/workflows/release.yaml +18 -0
  2. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/workflows/test.yaml +2 -2
  3. {pycontrails-0.54.8 → pycontrails-0.54.10}/CHANGELOG.md +34 -0
  4. {pycontrails-0.54.8/pycontrails.egg-info → pycontrails-0.54.10}/PKG-INFO +1 -1
  5. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/_version.py +2 -2
  6. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/aircraft_performance.py +48 -35
  7. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/models.py +56 -11
  8. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/rgi_cython.c +10499 -10872
  9. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/goes.py +193 -9
  10. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/ext/synthetic_flight.py +1 -1
  11. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/dry_advection.py +9 -0
  12. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/ps_model/ps_model.py +4 -7
  13. {pycontrails-0.54.8 → pycontrails-0.54.10/pycontrails.egg-info}/PKG-INFO +1 -1
  14. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_dry_advection.py +36 -1
  15. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_goes.py +93 -0
  16. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_ps_model.py +37 -5
  17. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  18. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  19. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/dependabot.yaml +0 -0
  20. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/pull_request_template.md +0 -0
  21. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/workflows/docs.yaml +0 -0
  22. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/workflows/doctest.yaml +0 -0
  23. {pycontrails-0.54.8 → pycontrails-0.54.10}/.github/workflows/scorecard.yaml +0 -0
  24. {pycontrails-0.54.8 → pycontrails-0.54.10}/.gitignore +0 -0
  25. {pycontrails-0.54.8 → pycontrails-0.54.10}/.pre-commit-config.yaml +0 -0
  26. {pycontrails-0.54.8 → pycontrails-0.54.10}/.zenodo.json +0 -0
  27. {pycontrails-0.54.8 → pycontrails-0.54.10}/CONTRIBUTING.md +0 -0
  28. {pycontrails-0.54.8 → pycontrails-0.54.10}/LICENSE +0 -0
  29. {pycontrails-0.54.8 → pycontrails-0.54.10}/Makefile +0 -0
  30. {pycontrails-0.54.8 → pycontrails-0.54.10}/NOTICE +0 -0
  31. {pycontrails-0.54.8 → pycontrails-0.54.10}/README.md +0 -0
  32. {pycontrails-0.54.8 → pycontrails-0.54.10}/RELEASE.md +0 -0
  33. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/_static/css/style.css +0 -0
  34. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/_static/img/colab.png +0 -0
  35. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/_static/img/favicon.png +0 -0
  36. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/_static/img/logo-dark.png +0 -0
  37. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/_static/img/logo.png +0 -0
  38. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/_static/pycontrails.bib +0 -0
  39. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/api.rst +0 -0
  40. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/changelog.rst +0 -0
  41. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/conf.py +0 -0
  42. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/contributing.rst +0 -0
  43. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/develop.rst +0 -0
  44. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/flight.rst +0 -0
  45. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/index.rst +0 -0
  46. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/install.rst +0 -0
  47. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/integrations/ACCF.ipynb +0 -0
  48. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/integrations/APCEMM.ipynb +0 -0
  49. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/literature.rst +0 -0
  50. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/meteorology.rst +0 -0
  51. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/models.rst +0 -0
  52. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/ARCO-ERA5.ipynb +0 -0
  53. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/AircraftPerformance.ipynb +0 -0
  54. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/Cache.ipynb +0 -0
  55. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/CoCiP.ipynb +0 -0
  56. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/CoCiPGrid.ipynb +0 -0
  57. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/ECMWF.ipynb +0 -0
  58. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/Flight.ipynb +0 -0
  59. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/GFS.ipynb +0 -0
  60. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/GOES.ipynb +0 -0
  61. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/ISSR.ipynb +0 -0
  62. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/Landsat.ipynb +0 -0
  63. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/Meteorology.ipynb +0 -0
  64. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/SAC.ipynb +0 -0
  65. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/Sentinel.ipynb +0 -0
  66. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/advection.ipynb +0 -0
  67. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/airports.ipynb +0 -0
  68. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/.gitignore +0 -0
  69. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/flight-ap.csv +0 -0
  70. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/flight-cocip.csv +0 -0
  71. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/flight-fdr.csv +0 -0
  72. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/flight-noisy.csv +0 -0
  73. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/flight.csv +0 -0
  74. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/iagos-flight-landsat.csv +0 -0
  75. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/data/iagos-flight-sentinel.csv +0 -0
  76. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/flightplan.ipynb +0 -0
  77. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/model-levels.ipynb +0 -0
  78. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/run-cocip-on-flight.ipynb +0 -0
  79. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/run-cocip-with-fdr.ipynb +0 -0
  80. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks/specific-humidity-interpolation.ipynb +0 -0
  81. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/notebooks.rst +0 -0
  82. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/observations.rst +0 -0
  83. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/tutorials.rst +0 -0
  84. {pycontrails-0.54.8 → pycontrails-0.54.10}/docs/utilities.rst +0 -0
  85. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/__init__.py +0 -0
  86. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/__init__.py +0 -0
  87. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/airports.py +0 -0
  88. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/cache.py +0 -0
  89. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/coordinates.py +0 -0
  90. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/fleet.py +0 -0
  91. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/flight.py +0 -0
  92. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/flightplan.py +0 -0
  93. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/fuel.py +0 -0
  94. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/interpolation.py +0 -0
  95. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/met.py +0 -0
  96. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/met_var.py +0 -0
  97. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/polygon.py +0 -0
  98. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/rgi_cython.pyx +0 -0
  99. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/core/vector.py +0 -0
  100. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/__init__.py +0 -0
  101. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/_leo_utils/search.py +0 -0
  102. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/_leo_utils/static/bq_roi_query.sql +0 -0
  103. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/_leo_utils/vis.py +0 -0
  104. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/_met_utils/metsource.py +0 -0
  105. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/__init__.py +0 -0
  106. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/arco_era5.py +0 -0
  107. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/common.py +0 -0
  108. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/era5.py +0 -0
  109. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/era5_model_level.py +0 -0
  110. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/hres.py +0 -0
  111. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/hres_model_level.py +0 -0
  112. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/ifs.py +0 -0
  113. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/model_levels.py +0 -0
  114. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +0 -0
  115. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/ecmwf/variables.py +0 -0
  116. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/gfs/__init__.py +0 -0
  117. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/gfs/gfs.py +0 -0
  118. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/gfs/variables.py +0 -0
  119. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/landsat.py +0 -0
  120. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/sentinel.py +0 -0
  121. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/spire/__init__.py +0 -0
  122. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/spire/exceptions.py +0 -0
  123. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/datalib/spire/spire.py +0 -0
  124. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/ext/bada.py +0 -0
  125. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/ext/cirium.py +0 -0
  126. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/ext/empirical_grid.py +0 -0
  127. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/__init__.py +0 -0
  128. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/accf.py +0 -0
  129. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/apcemm/__init__.py +0 -0
  130. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/apcemm/apcemm.py +0 -0
  131. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/apcemm/inputs.py +0 -0
  132. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +0 -0
  133. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/apcemm/utils.py +0 -0
  134. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/__init__.py +0 -0
  135. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/cocip.py +0 -0
  136. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/cocip_params.py +0 -0
  137. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/cocip_uncertainty.py +0 -0
  138. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/contrail_properties.py +0 -0
  139. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/output_formats.py +0 -0
  140. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/radiative_forcing.py +0 -0
  141. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/radiative_heating.py +0 -0
  142. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/unterstrasser_wake_vortex.py +0 -0
  143. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/wake_vortex.py +0 -0
  144. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocip/wind_shear.py +0 -0
  145. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocipgrid/__init__.py +0 -0
  146. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocipgrid/cocip_grid.py +0 -0
  147. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/cocipgrid/cocip_grid_params.py +0 -0
  148. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/emissions/__init__.py +0 -0
  149. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/emissions/black_carbon.py +0 -0
  150. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/emissions/emissions.py +0 -0
  151. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/emissions/ffm2.py +0 -0
  152. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/emissions/static/default-engine-uids.csv +0 -0
  153. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +0 -0
  154. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +0 -0
  155. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/humidity_scaling/__init__.py +0 -0
  156. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/humidity_scaling/humidity_scaling.py +0 -0
  157. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
  158. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
  159. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/issr.py +0 -0
  160. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/pcc.py +0 -0
  161. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/pcr.py +0 -0
  162. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/ps_model/__init__.py +0 -0
  163. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/ps_model/ps_aircraft_params.py +0 -0
  164. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/ps_model/ps_grid.py +0 -0
  165. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/ps_model/ps_operational_limits.py +0 -0
  166. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/ps_model/static/ps-aircraft-params-20250328.csv +0 -0
  167. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/ps_model/static/ps-synonym-list-20250328.csv +0 -0
  168. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/sac.py +0 -0
  169. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/models/tau_cirrus.py +0 -0
  170. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/__init__.py +0 -0
  171. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/constants.py +0 -0
  172. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/geo.py +0 -0
  173. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/jet.py +0 -0
  174. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/static/iata-cargo-load-factors-20250221.csv +0 -0
  175. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/static/iata-passenger-load-factors-20250221.csv +0 -0
  176. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/thermo.py +0 -0
  177. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/physics/units.py +0 -0
  178. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/py.typed +0 -0
  179. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/utils/__init__.py +0 -0
  180. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/utils/dependencies.py +0 -0
  181. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/utils/iteration.py +0 -0
  182. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/utils/json.py +0 -0
  183. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/utils/temp.py +0 -0
  184. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails/utils/types.py +0 -0
  185. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails.egg-info/SOURCES.txt +0 -0
  186. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails.egg-info/dependency_links.txt +0 -0
  187. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails.egg-info/requires.txt +0 -0
  188. {pycontrails-0.54.8 → pycontrails-0.54.10}/pycontrails.egg-info/top_level.txt +0 -0
  189. {pycontrails-0.54.8 → pycontrails-0.54.10}/pyproject.toml +0 -0
  190. {pycontrails-0.54.8 → pycontrails-0.54.10}/setup.cfg +0 -0
  191. {pycontrails-0.54.8 → pycontrails-0.54.10}/setup.py +0 -0
  192. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/__init__.py +0 -0
  193. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/_deprecated.py +0 -0
  194. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip/Makefile +0 -0
  195. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip/README.md +0 -0
  196. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip/benchmark.py +0 -0
  197. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip/compare.py +0 -0
  198. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip/data.md +0 -0
  199. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip/output.py +0 -0
  200. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip/review.ipynb +0 -0
  201. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/cocip-fortran/README.md +0 -0
  202. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/north-atlantic-study/.gcloudignore +0 -0
  203. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/north-atlantic-study/README.md +0 -0
  204. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/north-atlantic-study/support.py +0 -0
  205. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/benchmark/north-atlantic-study/validate.py +0 -0
  206. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/fixtures/cocip-met.py +0 -0
  207. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/fixtures/cocip-met2.py +0 -0
  208. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/fixtures/ecmwf-met.py +0 -0
  209. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/fixtures/gfs-met.py +0 -0
  210. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/__init__.py +0 -0
  211. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/conftest.py +0 -0
  212. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/NOAA_Solar_Calculations_day.csv +0 -0
  213. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/cocip-contrail-output.json +0 -0
  214. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/cocip-contrail-output2.json +0 -0
  215. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/cocip-flight-output.json +0 -0
  216. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/cocip-flight-output2.json +0 -0
  217. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/cocip-output-contrail-edges.json +0 -0
  218. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/cocip-output-flts-20190101-eu.pq +0 -0
  219. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/flight-cocip2.csv +0 -0
  220. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/flight-meridian.csv +0 -0
  221. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/flight-metadata.json +0 -0
  222. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/flight-spire-data-cleaning.pq +0 -0
  223. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/flight.csv +0 -0
  224. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/flt-wypts-20190101-eu.pq +0 -0
  225. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-20190101-eu.nc +0 -0
  226. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-accf-pl.nc +0 -0
  227. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-accf-sl.nc +0 -0
  228. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-ecmwf-lnsp.nc +0 -0
  229. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-ecmwf-ml.nc +0 -0
  230. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-ecmwf-pl.nc +0 -0
  231. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-ecmwf-sl.nc +0 -0
  232. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-era5-cocip1.nc +0 -0
  233. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-era5-cocip2.nc +0 -0
  234. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/met-gfs.nc +0 -0
  235. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/polygon-bug.nc +0 -0
  236. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/rad-20190101-eu.nc +0 -0
  237. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/rad-era5-cocip1.nc +0 -0
  238. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/rad-era5-cocip2.nc +0 -0
  239. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/static/rad-gfs.nc +0 -0
  240. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_accf.py +0 -0
  241. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_airports.py +0 -0
  242. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_apcemm.py +0 -0
  243. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_cache.py +0 -0
  244. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_cocip.py +0 -0
  245. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_cocip_grid.py +0 -0
  246. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_cocip_grid_parity.py +0 -0
  247. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_cocip_radiative_forcing.py +0 -0
  248. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_cocip_uncertainty.py +0 -0
  249. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_coordinates.py +0 -0
  250. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_datalib_metsource.py +0 -0
  251. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_dtypes.py +0 -0
  252. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_ecmwf.py +0 -0
  253. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_emissions.py +0 -0
  254. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_fleet.py +0 -0
  255. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_flight.py +0 -0
  256. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_flightplan.py +0 -0
  257. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_fuel.py +0 -0
  258. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_geo.py +0 -0
  259. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_gfs.py +0 -0
  260. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_grid_to_netcdf.py +0 -0
  261. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_humidity_scaling.py +0 -0
  262. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_init.py +0 -0
  263. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_interpolation.py +0 -0
  264. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_leo.py +0 -0
  265. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_met.py +0 -0
  266. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_met_cache.py +0 -0
  267. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_models.py +0 -0
  268. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_pcc.py +0 -0
  269. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_polygons.py +0 -0
  270. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_sac_issr.py +0 -0
  271. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_spire.py +0 -0
  272. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_tau_cirrus.py +0 -0
  273. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_thermo_sac.py +0 -0
  274. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_units.py +0 -0
  275. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_unterstrasser_wake_vortex.py +0 -0
  276. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_utils.py +0 -0
  277. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_vector.py +0 -0
  278. {pycontrails-0.54.8 → pycontrails-0.54.10}/tests/unit/test_zarr.py +0 -0
@@ -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 }}
@@ -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,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.54.10
4
+
5
+ ### Features
6
+
7
+ - Output from the `DryAdvection` model will include a `flight_id` column when run with a `Flight` or a `Fleet`.
8
+
9
+ ### Fixes
10
+
11
+ - GOES data download for GOES-East now supports the GOES-16 -> GOES-19 transition. The default GCS bucket is automatically selected based on the requested date (using 2025-04-04 as the cutoff). For pre-transition data, this change is backwards compatible with previous versions of pycontrails.
12
+ - Pass the `GOES.fs` instance to the `gcs_goes_path` function from the `GOES.gcs_goes_path` method to avoid repeated GCS file system client instantiation.
13
+
14
+ ### Internals
15
+
16
+ - Fix errors in "See Also" sections of `Model` docstrings.
17
+
18
+ ## 0.54.9
19
+
20
+ ### Features
21
+
22
+ - 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.
23
+
24
+ ### Breaking changes
25
+
26
+ - Air temperature is now an optional met variable in `PSFlight`. Code that uses `PSFlight.met_variables` may need to be updated.
27
+ - 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.
28
+ - 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`.
29
+
30
+ ### Internals
31
+
32
+ - Define `default_parameters`, `met_variables`, and `optional_met_variables` for the `AircraftPerformance` abstract base class.
33
+ - Remove the definitions of `met_variables` and `optional_met_variables` from `PSFlight`. These are now inherited from `AircraftPerformance`.
34
+ - Retrieve aircraft mass, thrust, engine efficiency, and fuel flow from `Flight` parameter rather than model source in `PSFlight.eval_flight`.
35
+ - Automatically run the [pycontrails-bada test](https://github.com/contrailcirrus/pycontrails-bada/actions/workflows/test.yml) workflow after publishing pycontrails release to PyPI.
36
+
3
37
  ## 0.54.8
4
38
 
5
39
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycontrails
3
- Version: 0.54.8
3
+ Version: 0.54.10
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
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.54.8'
21
- __version_tuple__ = version_tuple = (0, 54, 8)
20
+ __version__ = version = '0.54.10'
21
+ __version_tuple__ = version_tuple = (0, 54, 10)
@@ -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
@@ -543,7 +543,7 @@ class Model(ABC):
543
543
 
544
544
  See Also
545
545
  --------
546
- - :meth:`eval`
546
+ eval
547
547
  """
548
548
  self.source = self._get_source(source)
549
549
 
@@ -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
  --------
743
- - GeoVectorDataset.get_data_or_attr
747
+ get_source_param
748
+ pycontrails.core.vector.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
+ pycontrails.core.vector.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):