pycontrails 0.57.0__tar.gz → 0.58.0__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 (290) hide show
  1. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/workflows/release.yaml +2 -2
  2. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/workflows/test.yaml +1 -1
  3. {pycontrails-0.57.0 → pycontrails-0.58.0}/CHANGELOG.md +16 -0
  4. {pycontrails-0.57.0/pycontrails.egg-info → pycontrails-0.58.0}/PKG-INFO +5 -5
  5. {pycontrails-0.57.0 → pycontrails-0.58.0}/README.md +1 -1
  6. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/api.rst +4 -2
  7. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/install.rst +3 -2
  8. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/GOES.ipynb +4 -4
  9. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/_version.py +3 -3
  10. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/aircraft_performance.py +1 -1
  11. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/cache.py +2 -2
  12. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/fleet.py +2 -7
  13. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/flight.py +2 -7
  14. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/interpolation.py +42 -64
  15. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/met.py +36 -16
  16. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/polygon.py +3 -3
  17. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/rgi_cython.c +419 -1985
  18. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/rgi_cython.pyx +0 -144
  19. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/vector.py +3 -8
  20. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/_met_utils/metsource.py +4 -7
  21. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/common.py +2 -2
  22. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/hres.py +2 -2
  23. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/ifs.py +1 -1
  24. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/gfs/gfs.py +1 -1
  25. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/himawari/header_struct.py +1 -1
  26. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/himawari/himawari.py +20 -7
  27. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/leo_utils/sentinel_metadata.py +9 -9
  28. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/ext/synthetic_flight.py +2 -2
  29. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/cocip_uncertainty.py +1 -1
  30. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/contrail_properties.py +1 -1
  31. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/output_formats.py +1 -1
  32. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocipgrid/cocip_grid.py +3 -3
  33. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/dry_advection.py +1 -1
  34. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/extended_k15.py +4 -4
  35. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/humidity_scaling/humidity_scaling.py +2 -2
  36. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/ps_model/ps_grid.py +2 -2
  37. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/sac.py +1 -1
  38. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/tau_cirrus.py +1 -1
  39. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/thermo.py +1 -1
  40. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/utils/iteration.py +1 -1
  41. {pycontrails-0.57.0 → pycontrails-0.58.0/pycontrails.egg-info}/PKG-INFO +5 -5
  42. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails.egg-info/requires.txt +1 -1
  43. {pycontrails-0.57.0 → pycontrails-0.58.0}/pyproject.toml +23 -8
  44. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_dtypes.py +2 -2
  45. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_grid_to_netcdf.py +1 -1
  46. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_interpolation.py +7 -9
  47. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_met.py +20 -0
  48. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  49. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  50. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/dependabot.yaml +0 -0
  51. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/pull_request_template.md +0 -0
  52. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/workflows/docs.yaml +0 -0
  53. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/workflows/doctest.yaml +0 -0
  54. {pycontrails-0.57.0 → pycontrails-0.58.0}/.github/workflows/scorecard.yaml +0 -0
  55. {pycontrails-0.57.0 → pycontrails-0.58.0}/.gitignore +0 -0
  56. {pycontrails-0.57.0 → pycontrails-0.58.0}/.pre-commit-config.yaml +0 -0
  57. {pycontrails-0.57.0 → pycontrails-0.58.0}/.zenodo.json +0 -0
  58. {pycontrails-0.57.0 → pycontrails-0.58.0}/CONTRIBUTING.md +0 -0
  59. {pycontrails-0.57.0 → pycontrails-0.58.0}/LICENSE +0 -0
  60. {pycontrails-0.57.0 → pycontrails-0.58.0}/Makefile +0 -0
  61. {pycontrails-0.57.0 → pycontrails-0.58.0}/NOTICE +0 -0
  62. {pycontrails-0.57.0 → pycontrails-0.58.0}/RELEASE.md +0 -0
  63. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/_static/css/style.css +0 -0
  64. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/_static/img/colab.png +0 -0
  65. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/_static/img/favicon.png +0 -0
  66. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/_static/img/logo-dark.png +0 -0
  67. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/_static/img/logo.png +0 -0
  68. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/_static/pycontrails.bib +0 -0
  69. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/changelog.rst +0 -0
  70. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/conf.py +0 -0
  71. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/contributing.rst +0 -0
  72. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/develop.rst +0 -0
  73. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/flight.rst +0 -0
  74. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/index.rst +0 -0
  75. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/integrations/ACCF.ipynb +0 -0
  76. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/integrations/APCEMM.ipynb +0 -0
  77. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/literature.rst +0 -0
  78. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/meteorology.rst +0 -0
  79. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/models.rst +0 -0
  80. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/ARCO-ERA5.ipynb +0 -0
  81. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/AircraftPerformance.ipynb +0 -0
  82. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/Cache.ipynb +0 -0
  83. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/CoCiP.ipynb +0 -0
  84. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/CoCiPGrid.ipynb +0 -0
  85. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/ECMWF.ipynb +0 -0
  86. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/Flight.ipynb +0 -0
  87. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/GFS.ipynb +0 -0
  88. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/Himawari.ipynb +0 -0
  89. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/ISSR.ipynb +0 -0
  90. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/Landsat.ipynb +0 -0
  91. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/Meteorology.ipynb +0 -0
  92. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/SAC.ipynb +0 -0
  93. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/Sentinel.ipynb +0 -0
  94. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/advection.ipynb +0 -0
  95. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/airports.ipynb +0 -0
  96. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/.gitignore +0 -0
  97. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/flight-ap.csv +0 -0
  98. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/flight-cocip.csv +0 -0
  99. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/flight-fdr.csv +0 -0
  100. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/flight-noisy.csv +0 -0
  101. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/flight.csv +0 -0
  102. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/iagos-flight-landsat.csv +0 -0
  103. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/data/iagos-flight-sentinel.csv +0 -0
  104. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/flightplan.ipynb +0 -0
  105. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/model-levels.ipynb +0 -0
  106. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/run-cocip-on-flight.ipynb +0 -0
  107. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/run-cocip-with-fdr.ipynb +0 -0
  108. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks/specific-humidity-interpolation.ipynb +0 -0
  109. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/notebooks.rst +0 -0
  110. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/observations.rst +0 -0
  111. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/tutorials.rst +0 -0
  112. {pycontrails-0.57.0 → pycontrails-0.58.0}/docs/utilities.rst +0 -0
  113. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/__init__.py +0 -0
  114. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/__init__.py +0 -0
  115. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/airports.py +0 -0
  116. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/coordinates.py +0 -0
  117. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/flightplan.py +0 -0
  118. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/fuel.py +0 -0
  119. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/met_var.py +0 -0
  120. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/core/models.py +0 -0
  121. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/__init__.py +0 -0
  122. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/__init__.py +0 -0
  123. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/arco_era5.py +0 -0
  124. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/era5.py +0 -0
  125. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/era5_model_level.py +0 -0
  126. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/hres_model_level.py +0 -0
  127. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/model_levels.py +0 -0
  128. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +0 -0
  129. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/ecmwf/variables.py +0 -0
  130. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/geo_utils.py +0 -0
  131. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/gfs/__init__.py +0 -0
  132. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/gfs/variables.py +0 -0
  133. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/goes.py +0 -0
  134. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/himawari/__init__.py +0 -0
  135. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/landsat.py +0 -0
  136. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/leo_utils/__init__.py +0 -0
  137. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/leo_utils/correction.py +0 -0
  138. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/leo_utils/landsat_metadata.py +0 -0
  139. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/leo_utils/search.py +0 -0
  140. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/leo_utils/static/bq_roi_query.sql +0 -0
  141. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/leo_utils/vis.py +0 -0
  142. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/sentinel.py +0 -0
  143. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/spire/__init__.py +0 -0
  144. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/spire/exceptions.py +0 -0
  145. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/datalib/spire/spire.py +0 -0
  146. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/ext/bada.py +0 -0
  147. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/ext/cirium.py +0 -0
  148. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/ext/empirical_grid.py +0 -0
  149. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/__init__.py +0 -0
  150. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/accf.py +0 -0
  151. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/apcemm/__init__.py +0 -0
  152. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/apcemm/apcemm.py +0 -0
  153. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/apcemm/inputs.py +0 -0
  154. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +0 -0
  155. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/apcemm/utils.py +0 -0
  156. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/__init__.py +0 -0
  157. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/cocip.py +0 -0
  158. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/cocip_params.py +0 -0
  159. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/radiative_forcing.py +0 -0
  160. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/radiative_heating.py +0 -0
  161. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/unterstrasser_wake_vortex.py +0 -0
  162. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/wake_vortex.py +0 -0
  163. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocip/wind_shear.py +0 -0
  164. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocipgrid/__init__.py +0 -0
  165. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/cocipgrid/cocip_grid_params.py +0 -0
  166. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/emissions/__init__.py +0 -0
  167. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/emissions/black_carbon.py +0 -0
  168. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/emissions/emissions.py +0 -0
  169. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/emissions/ffm2.py +0 -0
  170. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/emissions/static/default-engine-uids.csv +0 -0
  171. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +0 -0
  172. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +0 -0
  173. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/humidity_scaling/__init__.py +0 -0
  174. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
  175. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
  176. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/issr.py +0 -0
  177. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/pcc.py +0 -0
  178. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/pcr.py +0 -0
  179. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/ps_model/__init__.py +0 -0
  180. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/ps_model/ps_aircraft_params.py +0 -0
  181. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/ps_model/ps_model.py +0 -0
  182. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/ps_model/ps_operational_limits.py +0 -0
  183. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/ps_model/static/ps-aircraft-params-20250328.csv +0 -0
  184. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/models/ps_model/static/ps-synonym-list-20250328.csv +0 -0
  185. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/__init__.py +0 -0
  186. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/constants.py +0 -0
  187. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/geo.py +0 -0
  188. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/jet.py +0 -0
  189. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/static/iata-cargo-load-factors-20250221.csv +0 -0
  190. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/static/iata-passenger-load-factors-20250221.csv +0 -0
  191. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/physics/units.py +0 -0
  192. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/py.typed +0 -0
  193. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/utils/__init__.py +0 -0
  194. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/utils/dependencies.py +0 -0
  195. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/utils/json.py +0 -0
  196. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/utils/temp.py +0 -0
  197. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails/utils/types.py +0 -0
  198. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails.egg-info/SOURCES.txt +0 -0
  199. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails.egg-info/dependency_links.txt +0 -0
  200. {pycontrails-0.57.0 → pycontrails-0.58.0}/pycontrails.egg-info/top_level.txt +0 -0
  201. {pycontrails-0.57.0 → pycontrails-0.58.0}/setup.cfg +0 -0
  202. {pycontrails-0.57.0 → pycontrails-0.58.0}/setup.py +0 -0
  203. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/__init__.py +0 -0
  204. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/_deprecated.py +0 -0
  205. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip/Makefile +0 -0
  206. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip/README.md +0 -0
  207. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip/benchmark.py +0 -0
  208. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip/compare.py +0 -0
  209. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip/data.md +0 -0
  210. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip/output.py +0 -0
  211. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip/review.ipynb +0 -0
  212. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/cocip-fortran/README.md +0 -0
  213. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/north-atlantic-study/.gcloudignore +0 -0
  214. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/north-atlantic-study/README.md +0 -0
  215. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/north-atlantic-study/support.py +0 -0
  216. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/benchmark/north-atlantic-study/validate.py +0 -0
  217. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/fixtures/cocip-met.py +0 -0
  218. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/fixtures/cocip-met2.py +0 -0
  219. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/fixtures/ecmwf-met.py +0 -0
  220. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/fixtures/gfs-met.py +0 -0
  221. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/__init__.py +0 -0
  222. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/conftest.py +0 -0
  223. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/NOAA_Solar_Calculations_day.csv +0 -0
  224. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/cocip-contrail-output.json +0 -0
  225. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/cocip-contrail-output2.json +0 -0
  226. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/cocip-flight-output.json +0 -0
  227. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/cocip-flight-output2.json +0 -0
  228. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/cocip-output-contrail-edges.json +0 -0
  229. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/cocip-output-flts-20190101-eu.pq +0 -0
  230. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/flight-cocip2.csv +0 -0
  231. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/flight-meridian.csv +0 -0
  232. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/flight-metadata.json +0 -0
  233. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/flight-spire-data-cleaning.pq +0 -0
  234. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/flight.csv +0 -0
  235. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/flt-wypts-20190101-eu.pq +0 -0
  236. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-20190101-eu.nc +0 -0
  237. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-accf-pl.nc +0 -0
  238. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-accf-sl.nc +0 -0
  239. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-ecmwf-lnsp.nc +0 -0
  240. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-ecmwf-ml.nc +0 -0
  241. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-ecmwf-pl.nc +0 -0
  242. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-ecmwf-sl.nc +0 -0
  243. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-era5-cocip1.nc +0 -0
  244. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-era5-cocip2.nc +0 -0
  245. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/met-gfs.nc +0 -0
  246. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/polygon-bug.nc +0 -0
  247. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/rad-20190101-eu.nc +0 -0
  248. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/rad-era5-cocip1.nc +0 -0
  249. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/rad-era5-cocip2.nc +0 -0
  250. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/static/rad-gfs.nc +0 -0
  251. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_accf.py +0 -0
  252. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_airports.py +0 -0
  253. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_apcemm.py +0 -0
  254. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_cache.py +0 -0
  255. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_cocip.py +0 -0
  256. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_cocip_grid.py +0 -0
  257. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_cocip_grid_parity.py +0 -0
  258. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_cocip_radiative_forcing.py +0 -0
  259. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_cocip_uncertainty.py +0 -0
  260. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_coordinates.py +0 -0
  261. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_datalib_metsource.py +0 -0
  262. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_dry_advection.py +0 -0
  263. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_ecmwf.py +0 -0
  264. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_emissions.py +0 -0
  265. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_fleet.py +0 -0
  266. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_flight.py +0 -0
  267. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_flightplan.py +0 -0
  268. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_fuel.py +0 -0
  269. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_geo.py +0 -0
  270. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_gfs.py +0 -0
  271. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_goes.py +0 -0
  272. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_himawari.py +0 -0
  273. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_humidity_scaling.py +0 -0
  274. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_init.py +0 -0
  275. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_leo.py +0 -0
  276. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_met_cache.py +0 -0
  277. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_models.py +0 -0
  278. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_pcc.py +0 -0
  279. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_polygons.py +0 -0
  280. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_ps_model.py +0 -0
  281. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_sac_issr.py +0 -0
  282. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_spire.py +0 -0
  283. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_tau_cirrus.py +0 -0
  284. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_thermo_sac.py +0 -0
  285. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_units.py +0 -0
  286. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_unterstrasser_wake_vortex.py +0 -0
  287. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_utils.py +0 -0
  288. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_vector.py +0 -0
  289. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_vpm.py +0 -0
  290. {pycontrails-0.57.0 → pycontrails-0.58.0}/tests/unit/test_zarr.py +0 -0
@@ -42,11 +42,11 @@ jobs:
42
42
  - name: Build wheels
43
43
  uses: pypa/cibuildwheel@v3.2
44
44
  env:
45
- CIBW_BUILD: cp310-* cp311-* cp312-* cp313-*
45
+ CIBW_BUILD: cp311-* cp312-* cp313-* cp314-*
46
46
  CIBW_SKIP: '*-win32 *-manylinux_i686 *-musllinux*'
47
47
  CIBW_BUILD_VERBOSITY: 3
48
48
  CIBW_ARCHS_MACOS: x86_64 arm64
49
- CIBW_TEST_SKIP: '*-macosx_arm64'
49
+ CIBW_TEST_SKIP: '*-macosx_arm64 cp314-*'
50
50
  # Completely isolate tests to prevent cibuildwheel from importing the
51
51
  # source instead of the wheel. This happens when tests/__init__.py is read.
52
52
  CIBW_TEST_EXTRAS: "complete,dev"
@@ -38,7 +38,7 @@ jobs:
38
38
  fail-fast: false
39
39
  matrix:
40
40
  os: [ubuntu-latest, windows-latest]
41
- pyversion: ['3.10', '3.11', '3.12', '3.13']
41
+ pyversion: ['3.11', '3.12', '3.13']
42
42
  runs-on: ${{ matrix.os }}
43
43
 
44
44
  steps:
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.58.0
4
+
5
+ ### Features
6
+
7
+ - Build wheels for python 3.14. These are not yet tested in the CI (not all dependencies support python 3.14 yet).
8
+
9
+ ### Breaking changes
10
+
11
+ - Drop support for python 3.10 per [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html).
12
+ - Require scipy >= 1.12 to better support the `PycontrailsRegularGridInterpolator` interface.
13
+
14
+ ### Fixes
15
+
16
+ - When instantiated with `copy=True`, `MetDataset` and `MetDataArray` now remove duplicate dimension values, preserving only the first occurrence of each. Previously, duplicates were silently retained (such duplicates are not expected with typical gridded weather data). With `copy=False`, a `ValueError` is raised if duplicate dimension values are present.
17
+ - Update `PycontrailsRegularGridInterpolator` for improved compatibility with `scipy.interpolate.RegularGridInterpolator`. All methods now delegate to SciPy’s implementation, except for `method="linear"`, which retains a fast-path optimized in `PycontrailsRegularGridInterpolator`.
18
+
3
19
  ## 0.57.0
4
20
 
5
21
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycontrails
3
- Version: 0.57.0
3
+ Version: 0.58.0
4
4
  Summary: Python library for modeling aviation climate impacts
5
5
  Author-email: "Contrails.org" <py@contrails.org>
6
6
  License-Expression: Apache-2.0
@@ -13,23 +13,23 @@ Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Intended Audience :: Science/Research
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Programming Language :: Python :: 3.12
19
18
  Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
20
  Classifier: Programming Language :: Python :: 3 :: Only
21
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
22
  Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
23
23
  Classifier: Topic :: Scientific/Engineering :: GIS
24
24
  Classifier: Typing :: Typed
25
- Requires-Python: >=3.10
25
+ Requires-Python: >=3.11
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  License-File: NOTICE
29
29
  Requires-Dist: dask>=2022.3
30
30
  Requires-Dist: numpy>=1.22
31
31
  Requires-Dist: pandas>=2.0
32
- Requires-Dist: scipy>=1.10
32
+ Requires-Dist: scipy>=1.12
33
33
  Requires-Dist: typing-extensions>=4.5; python_version < "3.12"
34
34
  Requires-Dist: xarray>=2022.3
35
35
  Provides-Extra: complete
@@ -140,7 +140,7 @@ Documentation and examples available at [py.contrails.org](https://py.contrails.
140
140
 
141
141
  ### Install with pip
142
142
 
143
- You can install pycontrails from PyPI with `pip` (Python 3.10 or later required):
143
+ You can install pycontrails from PyPI with `pip` (Python 3.11 or later required):
144
144
 
145
145
  ```bash
146
146
  $ pip install pycontrails
@@ -25,7 +25,7 @@ Documentation and examples available at [py.contrails.org](https://py.contrails.
25
25
 
26
26
  ### Install with pip
27
27
 
28
- You can install pycontrails from PyPI with `pip` (Python 3.10 or later required):
28
+ You can install pycontrails from PyPI with `pip` (Python 3.11 or later required):
29
29
 
30
30
  ```bash
31
31
  $ pip install pycontrails
@@ -83,13 +83,15 @@ ARCO ERA5
83
83
  datalib.ecmwf.arco_era5
84
84
 
85
85
 
86
- GOES
87
- """"
86
+ Geostationary Satellites
87
+ """"""""""""""""""""""""
88
88
 
89
89
  .. autosummary::
90
90
  :toctree: api/
91
91
 
92
92
  datalib.goes
93
+ datalib.himawari
94
+ datalib.geo_utils
93
95
 
94
96
 
95
97
  Low Earth Orbit Satellites
@@ -17,7 +17,7 @@ The conda-forge package includes all optional runtime dependencies.
17
17
  pip install
18
18
  -----------
19
19
 
20
- With Python 3.10 or later, install the latest release from PyPI using ``pip``:
20
+ With Python 3.11 or later, install the latest release from PyPI using ``pip``:
21
21
 
22
22
  .. code-block:: bash
23
23
 
@@ -27,7 +27,8 @@ With Python 3.10 or later, install the latest release from PyPI using ``pip``:
27
27
  # install with all optional dependencies
28
28
  $ pip install "pycontrails[complete]"
29
29
 
30
- Wheels are currently built and tested for python 3.10 - 3.13 on Linux, macOS, and Windows.
30
+ Wheels are currently built for python 3.11 - 3.14 and tested for
31
+ python 3.11 - 3.13 on Linux, macOS, and Windows.
31
32
 
32
33
  Install the latest development version directly from GitHub:
33
34
 
@@ -30,7 +30,7 @@
30
30
  "\n",
31
31
  "By default, any GOES data will be cached on disk. Set `cachestore=None` to disable caching when defining the `GOES` object.\n",
32
32
  "\n",
33
- "We download data for channels 1, 2, and 3. These are needed for creating a true color image."
33
+ "We download data for bands 1, 2, and 3. These are needed for creating a true color image."
34
34
  ]
35
35
  },
36
36
  {
@@ -692,7 +692,7 @@
692
692
  }
693
693
  ],
694
694
  "source": [
695
- "handler = goes.GOES(region=\"conus\", channels=(\"C01\", \"C02\", \"C03\"))\n",
695
+ "handler = goes.GOES(region=\"conus\", bands=(\"C01\", \"C02\", \"C03\"))\n",
696
696
  "\n",
697
697
  "# Download the data\n",
698
698
  "da = handler.get(\"2023-02-05T18:00:00\")\n",
@@ -3849,7 +3849,7 @@
3849
3849
  "\n",
3850
3850
  "The ash color scheme was originally developed to visualize volcanic ash. It is also useful for visualizing contrails.\n",
3851
3851
  "\n",
3852
- "We download data for channels 11, 14, and 15 to create an ash color image."
3852
+ "We download data for bands 11, 14, and 15 to create an ash color image."
3853
3853
  ]
3854
3854
  },
3855
3855
  {
@@ -3858,7 +3858,7 @@
3858
3858
  "metadata": {},
3859
3859
  "outputs": [],
3860
3860
  "source": [
3861
- "handler = goes.GOES(region=\"conus\", channels=(\"C11\", \"C14\", \"C15\"))\n",
3861
+ "handler = goes.GOES(region=\"conus\", bands=(\"C11\", \"C14\", \"C15\"))\n",
3862
3862
  "da = handler.get(\"2023-02-09T18:00:00\")\n",
3863
3863
  "\n",
3864
3864
  "rgb, src_crs, src_extent = goes.extract_visualization(da, color_scheme=\"ash\")"
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.57.0'
32
- __version_tuple__ = version_tuple = (0, 57, 0)
31
+ __version__ = version = '0.58.0'
32
+ __version_tuple__ = version_tuple = (0, 58, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g7b8b60b87'
34
+ __commit_id__ = commit_id = 'g142ff7355'
@@ -550,7 +550,7 @@ class AircraftPerformance(Model):
550
550
  if self.met is None:
551
551
  cond = np.isnan(u) & np.isnan(v)
552
552
  else:
553
- met_level_max = self.met.data["level"][-1].item() # type: ignore[union-attr]
553
+ met_level_max = self.met.data["level"][-1].item()
554
554
  cond = self.source.level > met_level_max
555
555
 
556
556
  # We DON'T overwrite the original u and v arrays already attached to the source
@@ -189,7 +189,7 @@ class DiskCacheStore(CacheStore):
189
189
  self,
190
190
  cache_dir: str | pathlib.Path | None = None,
191
191
  allow_clear: bool = False,
192
- ):
192
+ ) -> None:
193
193
  if cache_dir is None:
194
194
  # Avoid unnecessary import of platformdirs (called in _get_user_cache_dir)
195
195
  cache_dir = os.getenv("PYCONTRAILS_CACHE_DIR") or _get_user_cache_dir()
@@ -461,7 +461,7 @@ class GCPCacheStore(CacheStore):
461
461
  timeout: int = 300,
462
462
  show_progress: bool = False,
463
463
  chunk_size: int = 64 * 262144,
464
- ):
464
+ ) -> None:
465
465
  try:
466
466
  from google.cloud import storage
467
467
  except ModuleNotFoundError as e:
@@ -5,12 +5,7 @@ from __future__ import annotations
5
5
  import sys
6
6
  import warnings
7
7
  from collections.abc import Iterable
8
- from typing import Any, NoReturn
9
-
10
- if sys.version_info >= (3, 11):
11
- from typing import Self
12
- else:
13
- from typing_extensions import Self
8
+ from typing import Any, NoReturn, Self
14
9
 
15
10
  if sys.version_info >= (3, 12):
16
11
  from typing import override
@@ -122,7 +117,7 @@ class Fleet(Flight):
122
117
  # Set default fl_attrs if not provided
123
118
  fl_attrs = fl_attrs or {}
124
119
  for flight_id in groups.index:
125
- fl_attrs.setdefault(flight_id, {}) # type: ignore[call-overload]
120
+ fl_attrs.setdefault(flight_id, {})
126
121
 
127
122
  extra = fl_attrs.keys() - groups.index
128
123
  if extra:
@@ -6,18 +6,13 @@ import enum
6
6
  import logging
7
7
  import sys
8
8
  import warnings
9
- from typing import TYPE_CHECKING, Any, NoReturn
9
+ from typing import TYPE_CHECKING, Any, NoReturn, Self
10
10
 
11
11
  if sys.version_info >= (3, 12):
12
12
  from typing import override
13
13
  else:
14
14
  from typing_extensions import override
15
15
 
16
- if sys.version_info >= (3, 11):
17
- from typing import Self
18
- else:
19
- from typing_extensions import Self
20
-
21
16
 
22
17
  import numpy as np
23
18
  import numpy.typing as npt
@@ -2138,7 +2133,7 @@ def segment_rocd(
2138
2133
  T_correction[:-1] = (air_temperature[:-1] + air_temperature[1:]) / (T_isa[:-1] + T_isa[1:])
2139
2134
  T_correction[-1] = np.nan
2140
2135
 
2141
- return T_correction * out # type: ignore[return-value]
2136
+ return T_correction * out
2142
2137
 
2143
2138
 
2144
2139
  def _resample_to_freq_or_time(
@@ -26,57 +26,74 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
26
26
 
27
27
  This class is a thin wrapper around the
28
28
  :class:`scipy.interpolate.RegularGridInterpolator` in order to make typical
29
- ``pycontrails`` use-cases more efficient.
29
+ ``pycontrails`` linear interpolation use-cases more performant:
30
30
 
31
- #. Avoid ``RegularGridInterpolator`` constructor validation. In :func:`interp`,
32
- parameters are carefully crafted to fit into the intended form, thereby making
33
- validation unnecessary.
31
+ #. Avoid ``RegularGridInterpolator`` constructor validation when `method="linear"`.
32
+ In :func:`interp`, parameters are carefully crafted to fit into the intended form,
33
+ thereby making validation unnecessary.
34
34
  #. Override the :meth:`_evaluate_linear` method with a faster implementation. See
35
- the :meth:`_evaluate_linear` docstring for more information.
35
+ the :meth:`_evaluate_linear` docstring for more information.
36
36
 
37
- This class should not be used directly. Instead, use the :func:`interp` function.
37
+ **This class should not be used directly. Instead, use the ``interp`` function.**
38
38
 
39
39
  .. versionchanged:: 0.40.0
40
40
 
41
41
  The :meth:`_evaluate_linear` method now uses a Cython implementation. The dtype
42
42
  of the output is now consistent with the dtype of the underlying :attr:`values`
43
43
 
44
+ .. versionchanged:: 0.58.0
45
+
46
+ Any ``method`` other than ``"linear"`` now uses the
47
+ :class:`scipy.interpolate.RegularGridInterpolator` implementation. This
48
+ allows for greater flexibility in the ``method`` parameter.
49
+
44
50
  Parameters
45
51
  ----------
46
52
  points : tuple[npt.NDArray[np.floating], ...]
47
53
  Coordinates of the grid points.
48
54
  values : npt.NDArray[np.floating]
49
55
  Grid values. The shape of this array must be compatible with the
50
- coordinates. An error is raised if the dtype is not ``np.float32``
51
- or ``np.float64``.
56
+ coordinates.
52
57
  method : str
53
58
  Passed into :class:`scipy.interpolate.RegularGridInterpolator`
54
59
  bounds_error : bool
55
60
  Passed into :class:`scipy.interpolate.RegularGridInterpolator`
56
61
  fill_value : float | np.float64 | None
57
62
  Passed into :class:`scipy.interpolate.RegularGridInterpolator`
63
+
64
+ See Also
65
+ --------
66
+ scipy.interpolate.RegularGridInterpolator
67
+ interp
58
68
  """
59
69
 
60
70
  def __init__(
61
71
  self,
62
72
  points: tuple[npt.NDArray[np.floating], ...],
63
73
  values: npt.NDArray[np.floating],
74
+ *,
64
75
  method: str,
65
76
  bounds_error: bool,
66
77
  fill_value: float | np.float64 | None,
67
- ):
68
- if values.dtype not in (np.float32, np.float64):
69
- msg = f"values must be a float array, not {values.dtype}"
70
- raise ValueError(msg)
71
-
78
+ ) -> None:
79
+ if method != "linear" or values.dtype not in (np.float32, np.float64):
80
+ # Slow path: use parent class
81
+ super().__init__(
82
+ points,
83
+ values,
84
+ method=method,
85
+ bounds_error=bounds_error,
86
+ fill_value=fill_value,
87
+ )
88
+ return
89
+
90
+ # Fast path: no validation
72
91
  self.grid = points
73
92
  self.values = values
74
- # TODO: consider supporting updated tensor-product spline methods
75
- # see https://github.com/scipy/scipy/releases/tag/v1.13.0
76
- self.method = _pick_method(scipy.__version__, method)
93
+ self.method = method
77
94
  self.bounds_error = bounds_error
78
95
  self.fill_value = fill_value
79
- self._spline = None
96
+ self._spline = None # XXX: setting private attribute on RGI
80
97
 
81
98
  def _prepare_xi_simple(self, xi: npt.NDArray[np.floating]) -> npt.NDArray[np.bool_]:
82
99
  """Run looser version of :meth:`_prepare_xi`.
@@ -103,7 +120,7 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
103
120
 
104
121
  return np.zeros(xi.shape[0], dtype=bool)
105
122
 
106
- return self._find_out_of_bounds(xi.T)
123
+ return self._find_out_of_bounds(xi.T) # XXX: calling private method on RGI
107
124
 
108
125
  def __call__(
109
126
  self, xi: npt.NDArray[np.floating], method: str | None = None
@@ -130,7 +147,7 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
130
147
  return super().__call__(xi, method)
131
148
 
132
149
  out_of_bounds = self._prepare_xi_simple(xi)
133
- xi_indices, norm_distances = rgi_cython.find_indices(self.grid, xi.T)
150
+ xi_indices, norm_distances = self._find_indices(xi.T) # XXX: calling private method on RGI
134
151
 
135
152
  out = self._evaluate_linear(xi_indices, norm_distances)
136
153
  return self._set_out_of_bounds(out, out_of_bounds)
@@ -223,45 +240,6 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
223
240
  raise ValueError(msg)
224
241
 
225
242
 
226
- def _pick_method(scipy_version: str, method: str) -> str:
227
- """Select an interpolation method.
228
-
229
- For scipy versions 1.13.0 and later, fall back on legacy implementations
230
- of tensor-product spline methods. The default implementations in 1.13.0
231
- and later are incompatible with this class.
232
-
233
- Parameters
234
- ----------
235
- scipy_version : str
236
- scipy version (major.minor.patch)
237
-
238
- method : str
239
- Interpolation method. Passed into :class:`scipy.interpolate.RegularGridInterpolator`
240
- as-is unless ``scipy_version`` is 1.13.0 or later and ``method`` is ``"slinear"``,
241
- ``"cubic"``, or ``"quintic"``. In this case, ``"_legacy"`` is appended to ``method``.
242
-
243
- Returns
244
- -------
245
- str
246
- Interpolation method adjusted for compatibility with this class.
247
- """
248
- if method == "linear":
249
- return method
250
-
251
- try:
252
- version = scipy_version.split(".")
253
- major = int(version[0])
254
- minor = int(version[1])
255
- except (IndexError, ValueError) as exc:
256
- msg = f"Failed to parse major and minor version from {scipy_version}"
257
- raise ValueError(msg) from exc
258
-
259
- reimplemented_methods = ["slinear", "cubic", "quintic"]
260
- if major > 1 or ((major == 1 and minor >= 13) and method in reimplemented_methods):
261
- return method + "_legacy"
262
- return method
263
-
264
-
265
243
  def _floatize_time(
266
244
  time: npt.NDArray[np.datetime64], offset: np.datetime64
267
245
  ) -> npt.NDArray[np.floating]:
@@ -431,7 +409,7 @@ def interp(
431
409
  Include ``indices`` and ``return_indices`` experimental parameters.
432
410
  Currently, nan values in ``longitude``, ``latitude``, ``level``, or ``time``
433
411
  are always propagated through to the output, regardless of ``bounds_error``.
434
- In other words, a ValueError for an out of bounds coordinate is only raised
412
+ In other words, a ``ValueError`` for an out of bounds coordinate is only raised
435
413
  if a non-nan value is out of bounds.
436
414
 
437
415
  .. versionchanged:: 0.40.0
@@ -480,9 +458,9 @@ def interp(
480
458
 
481
459
  See Also
482
460
  --------
483
- - :meth:`MetDataArray.interpolate`
484
- - :func:`scipy.interpolate.interpn`
485
- - :class:`scipy.interpolate.RegularGridInterpolator`
461
+ pycontrails.MetDataArray.interpolate
462
+ scipy.interpolate.interpn
463
+ scipy.interpolate.RegularGridInterpolator
486
464
  """
487
465
  if localize:
488
466
  coords = {"longitude": longitude, "latitude": latitude, "level": level, "time": time}
@@ -579,7 +557,7 @@ def _linear_interp_with_indices(
579
557
  if indices is None:
580
558
  assert xi is not None, "xi must be provided if indices is None"
581
559
  out_of_bounds = interp._prepare_xi_simple(xi)
582
- xi_indices, norm_distances = rgi_cython.find_indices(interp.grid, xi.T)
560
+ xi_indices, norm_distances = interp._find_indices(xi.T)
583
561
  indices = RGIArtifacts(xi_indices, norm_distances, out_of_bounds)
584
562
 
585
563
  out = interp._evaluate_linear(indices.xi_indices, indices.norm_distances)
@@ -606,7 +584,7 @@ class EmissionsProfileInterpolator:
606
584
 
607
585
  This class simply wraps :func:`numpy.interp` with fixed values for the
608
586
  ``xp`` and ``fp`` arguments. Unlike :class:`xarray.DataArray` interpolation,
609
- the `numpy.interp` automatically clips values outside the range of the
587
+ the :func:`numpy.interp` automatically clips values outside the range of the
610
588
  ``xp`` array.
611
589
 
612
590
  Parameters
@@ -26,15 +26,11 @@ from typing import (
26
26
  Any,
27
27
  Generic,
28
28
  Literal,
29
+ Self,
29
30
  TypeVar,
30
31
  overload,
31
32
  )
32
33
 
33
- if sys.version_info >= (3, 11):
34
- from typing import Self
35
- else:
36
- from typing_extensions import Self
37
-
38
34
  if sys.version_info >= (3, 12):
39
35
  from typing import override
40
36
  else:
@@ -211,14 +207,22 @@ class MetBase(ABC, Generic[XArrayType]):
211
207
  Raises
212
208
  ------
213
209
  ValueError
214
- If one of the coordinates is not sorted.
210
+ If one of the coordinates is not sorted or contains duplicate values.
215
211
  """
216
212
  indexes = self.indexes
217
- if not np.all(np.diff(indexes["time"]) > np.timedelta64(0, "ns")):
218
- raise ValueError("Coordinate 'time' not sorted. Instantiate with 'copy=True'.")
219
- for coord in self.dim_order[:3]: # exclude time, the 4th dimension
220
- if not np.all(np.diff(indexes[coord]) > 0.0):
221
- raise ValueError(f"Coordinate '{coord}' not sorted. Instantiate with 'copy=True'.")
213
+ for coord in self.dim_order:
214
+ arr = indexes[coord]
215
+ d = np.diff(arr)
216
+ zero = np.zeros((), dtype=d.dtype) # ensure same dtype
217
+
218
+ if np.any(d <= zero):
219
+ if np.any(d == zero):
220
+ msg = f"Coordinate '{coord}' contains duplicate values."
221
+ else:
222
+ msg = f"Coordinate '{coord}' not sorted."
223
+
224
+ msg += " Instantiate with 'copy=True'."
225
+ raise ValueError(msg)
222
226
 
223
227
  def _validate_transpose(self) -> None:
224
228
  """Check that data is transposed according to :attr:`dim_order`."""
@@ -271,6 +275,10 @@ class MetBase(ABC, Generic[XArrayType]):
271
275
  Auxiliary coordinates (altitude and air_pressure) are now cast to the same
272
276
  dtype as the underlying grid data.
273
277
 
278
+ .. versionchanged:: 0.58.0
279
+
280
+ Duplicate dimension values are dropped, keeping the first occurrence.
281
+
274
282
 
275
283
  Parameters
276
284
  ----------
@@ -297,6 +305,18 @@ class MetBase(ABC, Generic[XArrayType]):
297
305
  # sortby to ensure each coordinate has ascending order
298
306
  self.data = self.data.sortby(list(self.dim_order), ascending=True)
299
307
 
308
+ # Drop any duplicated dimension values
309
+ indexes = self.indexes
310
+ for coord in self.dim_order:
311
+ arr = indexes[coord]
312
+ d = np.diff(arr)
313
+ zero = np.zeros((), dtype=d.dtype) # ensure same dtype
314
+
315
+ if np.any(d == zero):
316
+ # Remove duplicates
317
+ filt = np.r_[True, d > zero] # prepend True keeps the first occurrence
318
+ self.data = self.data.isel({coord: filt})
319
+
300
320
  if not self.is_wrapped:
301
321
  # Ensure longitude is contained in interval [-180, 180)
302
322
  # If longitude has value at 180, we might not want to shift it?
@@ -1087,7 +1107,7 @@ class MetDataset(MetBase):
1087
1107
  out[key] = da.values.ravel() # type: ignore[index]
1088
1108
 
1089
1109
  if transfer_attrs:
1090
- out.attrs.update(self.attrs) # type: ignore[arg-type]
1110
+ out.attrs.update(self.attrs)
1091
1111
 
1092
1112
  return out
1093
1113
 
@@ -1300,7 +1320,7 @@ class MetDataset(MetBase):
1300
1320
  coords: dict[str, np.ndarray] = {}
1301
1321
  for key, val in input_data.items():
1302
1322
  dtype = "datetime64[ns]" if key == "time" else COORD_DTYPE
1303
- arr: np.ndarray = np.asarray(val, dtype=dtype) # type: ignore[call-overload]
1323
+ arr: np.ndarray = np.asarray(val, dtype=dtype)
1304
1324
 
1305
1325
  if arr.ndim == 0:
1306
1326
  arr = arr.reshape(1)
@@ -1889,7 +1909,7 @@ class MetDataArray(MetBase):
1889
1909
  if not self.binary:
1890
1910
  raise NotImplementedError("proportion method is only implemented for binary fields")
1891
1911
 
1892
- return self.data.sum().values.item() / self.data.count().values.item() # type: ignore[operator]
1912
+ return self.data.sum().values.item() / self.data.count().values.item()
1893
1913
 
1894
1914
  def find_edges(self) -> Self:
1895
1915
  """Find edges of regions.
@@ -2598,9 +2618,9 @@ def _extract_2d_arr_and_altitude(
2598
2618
  except KeyError:
2599
2619
  altitude = None
2600
2620
  else:
2601
- altitude = round(altitude) # type: ignore[call-overload]
2621
+ altitude = round(altitude)
2602
2622
 
2603
- return arr, altitude # type: ignore[return-value]
2623
+ return arr, altitude
2604
2624
 
2605
2625
 
2606
2626
  def downselect(data: XArrayType, bbox: tuple[float, ...]) -> XArrayType:
@@ -238,7 +238,7 @@ def _contours_to_polygons(
238
238
  latitude=latitude,
239
239
  precision=precision,
240
240
  buffer=buffer,
241
- i=child_i, # type: ignore[arg-type]
241
+ i=child_i,
242
242
  )
243
243
 
244
244
  candidate = shapely.Polygon(polygon.exterior, [h.exterior for h in holes])
@@ -354,11 +354,11 @@ def find_multipolygon(
354
354
  return shapely.MultiPolygon()
355
355
 
356
356
  assert len(hierarchy) == 1
357
- hierarchy = hierarchy[0] # type: ignore[index]
357
+ hierarchy = hierarchy[0]
358
358
 
359
359
  polygons = _contours_to_polygons(
360
360
  contours, # type: ignore[arg-type]
361
- hierarchy, # type: ignore[arg-type]
361
+ hierarchy,
362
362
  min_area,
363
363
  convex_hull,
364
364
  epsilon,