pycontrails 0.52.2__tar.gz → 0.53.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.
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/workflows/doctest.yaml +2 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/workflows/release.yaml +3 -3
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/workflows/test.yaml +2 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/CHANGELOG.md +34 -0
- {pycontrails-0.52.2/pycontrails.egg-info → pycontrails-0.53.0}/PKG-INFO +6 -6
- {pycontrails-0.52.2 → pycontrails-0.53.0}/README.md +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/api.rst +11 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/install.rst +3 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/_version.py +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/cache.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/flight.py +8 -5
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/flightplan.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/interpolation.py +3 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/met.py +190 -15
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/met_var.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/models.py +5 -5
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/rgi_cython.c +1209 -1193
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/vector.py +5 -5
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/_leo_utils/vis.py +10 -11
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/_met_utils/metsource.py +13 -11
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/era5.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/era5_model_level.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/hres_model_level.py +3 -3
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/variables.py +3 -3
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/gfs/gfs.py +4 -3
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/landsat.py +10 -9
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/ext/synthetic_flight.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/accf.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/apcemm/apcemm.py +5 -5
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/cocip.py +98 -24
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/cocip_params.py +21 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/output_formats.py +13 -4
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/radiative_forcing.py +3 -3
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocipgrid/cocip_grid.py +4 -4
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/ps_model/ps_model.py +4 -4
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/sac.py +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/physics/thermo.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/utils/json.py +16 -18
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/utils/types.py +7 -6
- {pycontrails-0.52.2 → pycontrails-0.53.0/pycontrails.egg-info}/PKG-INFO +6 -6
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails.egg-info/requires.txt +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pyproject.toml +8 -7
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/_deprecated.py +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_cocip.py +140 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_fleet.py +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_flight.py +3 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_interpolation.py +122 -16
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_met.py +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_models.py +3 -3
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_ps_model.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_sac_issr.py +4 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_tau_cirrus.py +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_units.py +2 -2
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_vector.py +1 -1
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/dependabot.yaml +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/pull_request_template.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/workflows/docs.yaml +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.github/workflows/scorecard.yaml +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.gitignore +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.pre-commit-config.yaml +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/.zenodo.json +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/CONTRIBUTING.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/LICENSE +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/Makefile +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/NOTICE +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/RELEASE.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/_static/css/style.css +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/_static/img/colab.png +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/_static/img/favicon.png +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/_static/img/logo-dark.png +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/_static/img/logo.png +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/_static/pycontrails.bib +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/changelog.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/conf.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/contributing.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/develop.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/flight.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/index.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/integrations/ACCF.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/integrations/APCEMM.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/literature.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/meteorology.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/models.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/ARCO-ERA5.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/AircraftPerformance.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/Cache.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/CoCiP.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/ECMWF.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/Flight.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/GFS.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/GOES.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/ISSR.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/Landsat.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/Meteorology.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/SAC.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/Sentinel.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/advection.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/airports.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/.gitignore +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/flight-ap.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/flight-cocip.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/flight-fdr.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/flight-noisy.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/flight.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/iagos-flight-landsat.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/data/iagos-flight-sentinel.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/flightplan.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/model-levels.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/run-cocip-on-flight.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/run-cocip-with-fdr.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks/specific-humidity-interpolation.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/notebooks.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/observations.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/tutorials.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/docs/utilities.rst +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/aircraft_performance.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/airports.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/coordinates.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/fleet.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/fuel.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/polygon.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/core/rgi_cython.pyx +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/_leo_utils/search.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/_leo_utils/static/bq_roi_query.sql +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/arco_era5.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/common.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/hres.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/ifs.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/model_levels.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/ecmwf/static/model_level_dataframe_v20240418.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/gfs/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/gfs/variables.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/goes.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/sentinel.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/datalib/spire.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/ext/bada.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/ext/cirium.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/ext/empirical_grid.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/apcemm/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/apcemm/inputs.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/apcemm/static/apcemm_yaml_template.yaml +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/apcemm/utils.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/cocip_uncertainty.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/contrail_properties.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/radiative_heating.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/unterstrasser_wake_vortex.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/wake_vortex.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocip/wind_shear.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocipgrid/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/cocipgrid/cocip_grid_params.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/dry_advection.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/emissions/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/emissions/black_carbon.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/emissions/emissions.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/emissions/ffm2.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/emissions/static/default-engine-uids.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/emissions/static/edb-gaseous-v29b-engines.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/emissions/static/edb-nvpm-v29b-engines.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/humidity_scaling/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/humidity_scaling/humidity_scaling.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/humidity_scaling/quantiles/era5-model-level-quantiles.pq +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/humidity_scaling/quantiles/era5-pressure-level-quantiles.pq +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/issr.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/pcc.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/pcr.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/ps_model/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/ps_model/ps_aircraft_params.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/ps_model/ps_grid.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/ps_model/ps_operational_limits.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/ps_model/static/ps-aircraft-params-20240524.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/ps_model/static/ps-synonym-list-20240524.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/models/tau_cirrus.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/physics/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/physics/constants.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/physics/geo.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/physics/jet.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/physics/units.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/py.typed +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/utils/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/utils/dependencies.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/utils/iteration.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails/utils/temp.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails.egg-info/SOURCES.txt +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails.egg-info/dependency_links.txt +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/pycontrails.egg-info/top_level.txt +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/setup.cfg +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/setup.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip/Makefile +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip/README.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip/benchmark.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip/compare.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip/data.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip/output.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip/review.ipynb +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/cocip-fortran/README.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/north-atlantic-study/.gcloudignore +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/north-atlantic-study/README.md +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/north-atlantic-study/support.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/benchmark/north-atlantic-study/validate.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/fixtures/cocip-met.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/fixtures/cocip-met2.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/fixtures/ecmwf-met.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/fixtures/gfs-met.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/__init__.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/conftest.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/NOAA_Solar_Calculations_day.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/cocip-contrail-output.json +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/cocip-contrail-output2.json +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/cocip-flight-output.json +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/cocip-flight-output2.json +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/cocip-output-contrail-edges.json +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/cocip-output-flts-20190101-eu.pq +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/flight-cocip2.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/flight-meridian.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/flight-metadata.json +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/flight-spire-data-cleaning.pq +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/flight.csv +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/flt-wypts-20190101-eu.pq +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-20190101-eu.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-accf-pl.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-accf-sl.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-ecmwf-pl.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-ecmwf-sl.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-era5-cocip1.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-era5-cocip2.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/met-gfs.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/polygon-bug.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/rad-20190101-eu.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/rad-era5-cocip1.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/rad-era5-cocip2.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/static/rad-gfs.nc +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_accf.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_airports.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_apcemm.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_cache.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_cocip_grid.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_cocip_grid_parity.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_cocip_radiative_forcing.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_cocip_uncertainty.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_coordinates.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_datalib_metsource.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_dry_advection.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_dtypes.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_ecmwf.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_emissions.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_flightplan.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_fuel.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_geo.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_gfs.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_goes.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_grid_to_netcdf.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_humidity_scaling.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_init.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_leo.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_met_cache.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_pcc.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_polygons.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_spire.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_thermo_sac.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_unterstrasser_wake_vortex.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_utils.py +0 -0
- {pycontrails-0.52.2 → pycontrails-0.53.0}/tests/unit/test_zarr.py +0 -0
|
@@ -40,13 +40,13 @@ jobs:
|
|
|
40
40
|
|
|
41
41
|
# https://cibuildwheel.readthedocs.io/en/stable/options/#testing
|
|
42
42
|
- name: Build wheels
|
|
43
|
-
uses: pypa/cibuildwheel@v2.
|
|
43
|
+
uses: pypa/cibuildwheel@v2.20
|
|
44
44
|
env:
|
|
45
|
-
CIBW_BUILD:
|
|
45
|
+
CIBW_BUILD: cp310-* cp311-* cp312-* cp313-*
|
|
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 cp313-*'
|
|
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,8 @@ jobs:
|
|
|
38
38
|
fail-fast: false
|
|
39
39
|
matrix:
|
|
40
40
|
os: [ubuntu-latest, windows-latest]
|
|
41
|
-
|
|
41
|
+
# TODO(Fall 2024): Add 3.13 once all dependencies are available
|
|
42
|
+
pyversion: ['3.10', '3.11', '3.12']
|
|
42
43
|
runs-on: ${{ matrix.os }}
|
|
43
44
|
|
|
44
45
|
steps:
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.53.0
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- Drop python 3.9 support per [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html).
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- Build wheels for [python 3.13](https://peps.python.org/pep-0719/). (These wheels are available on PyPI, but other pycontrails dependencies may not yet support python 3.13.)
|
|
12
|
+
|
|
13
|
+
### Fixes
|
|
14
|
+
|
|
15
|
+
- Fix `PycontrailsRegularGridInterpolator` for compatibility with the latest scipy version.
|
|
16
|
+
|
|
17
|
+
### Internals
|
|
18
|
+
|
|
19
|
+
- Defer import of `skimage` and `rasterio`.
|
|
20
|
+
|
|
21
|
+
## v0.52.3
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- Add experimental `preprocess_lowmem` parameter to `Cocip`. When set to `True`, `Cocip` will attempt to reduce memory consumption during flight preprocessing and initial formation/persistence calculations by using an alternate implementation of `MetDataArray.interpolate` (see below).
|
|
26
|
+
- Add `lowmem` keyword-only argument to `MetDataArray.interpolate`. When `True`, attempt to reduce memory consumption by using an alternative interpolation strategy that loads at most two time steps of meteorology data into memory at a time.
|
|
27
|
+
|
|
28
|
+
### Fixes
|
|
29
|
+
|
|
30
|
+
- Defer import of `matplotlib` in `models.cocip.output_formats`.
|
|
31
|
+
- Fix bug in `PycontrailsRegularGridInterpolator` that caused errors when dispatching to 1-d linear interpolation from in `rgi_cython.pyx`.
|
|
32
|
+
|
|
33
|
+
### Internals
|
|
34
|
+
|
|
35
|
+
- Implement low-memory paths in `Cocip.eval` and `MetDataArray.interpolate`.
|
|
36
|
+
|
|
3
37
|
## v0.52.2
|
|
4
38
|
|
|
5
39
|
### Breaking changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pycontrails
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.53.0
|
|
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
|
|
@@ -14,16 +14,16 @@ Classifier: Intended Audience :: Science/Research
|
|
|
14
14
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
21
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
23
|
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
24
24
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
25
25
|
Classifier: Typing :: Typed
|
|
26
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
License-File: NOTICE
|
|
@@ -36,7 +36,7 @@ Requires-Dist: xarray>=2022.3
|
|
|
36
36
|
Provides-Extra: complete
|
|
37
37
|
Requires-Dist: pycontrails[ecmwf,gcp,gfs,jupyter,pyproj,sat,vis,zarr]; extra == "complete"
|
|
38
38
|
Provides-Extra: dev
|
|
39
|
-
Requires-Dist: black[jupyter]==24.
|
|
39
|
+
Requires-Dist: black[jupyter]==24.8.0; extra == "dev"
|
|
40
40
|
Requires-Dist: dep_license; extra == "dev"
|
|
41
41
|
Requires-Dist: fastparquet>=0.8; extra == "dev"
|
|
42
42
|
Requires-Dist: ipdb>=0.13; extra == "dev"
|
|
@@ -50,7 +50,7 @@ Requires-Dist: pyarrow>=5.0; extra == "dev"
|
|
|
50
50
|
Requires-Dist: pytest>=8.2; extra == "dev"
|
|
51
51
|
Requires-Dist: pytest-cov>=2.11; extra == "dev"
|
|
52
52
|
Requires-Dist: requests>=2.25; extra == "dev"
|
|
53
|
-
Requires-Dist: ruff==0.5.
|
|
53
|
+
Requires-Dist: ruff==0.5.7; extra == "dev"
|
|
54
54
|
Requires-Dist: setuptools; extra == "dev"
|
|
55
55
|
Provides-Extra: docs
|
|
56
56
|
Requires-Dist: doc8>=1.1; extra == "docs"
|
|
@@ -141,7 +141,7 @@ Documentation and examples available at [py.contrails.org](https://py.contrails.
|
|
|
141
141
|
|
|
142
142
|
### Install with pip
|
|
143
143
|
|
|
144
|
-
You can install pycontrails from PyPI with `pip` (Python 3.
|
|
144
|
+
You can install pycontrails from PyPI with `pip` (Python 3.10 or later required):
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
147
|
$ 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.
|
|
28
|
+
You can install pycontrails from PyPI with `pip` (Python 3.10 or later required):
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
$ pip install pycontrails
|
|
@@ -134,6 +134,7 @@ CoCiP
|
|
|
134
134
|
|
|
135
135
|
models.cocip.Cocip
|
|
136
136
|
models.cocip.CocipParams
|
|
137
|
+
models.cocip.CocipFlightParams
|
|
137
138
|
models.cocip.contrail_properties
|
|
138
139
|
models.cocip.radiative_forcing
|
|
139
140
|
models.cocip.wake_vortex
|
|
@@ -150,6 +151,16 @@ Gridded CoCiP
|
|
|
150
151
|
models.cocipgrid.CocipGridParams
|
|
151
152
|
|
|
152
153
|
|
|
154
|
+
Dry Advection
|
|
155
|
+
"""""""""""""
|
|
156
|
+
|
|
157
|
+
.. autosummary::
|
|
158
|
+
:toctree: api/
|
|
159
|
+
|
|
160
|
+
models.dry_advection.DryAdvection
|
|
161
|
+
models.dry_advection.DryAdvectionParams
|
|
162
|
+
|
|
163
|
+
|
|
153
164
|
ACCF
|
|
154
165
|
""""
|
|
155
166
|
|
|
@@ -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.
|
|
20
|
+
With Python 3.10 or later, install the latest release from PyPI using ``pip``:
|
|
21
21
|
|
|
22
22
|
.. code-block:: bash
|
|
23
23
|
|
|
@@ -27,6 +27,8 @@ With Python 3.9 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 for python 3.10 - 3.13 on Linux, macOS, and Windows. The python 3.13
|
|
31
|
+
wheels are not yet tested in CI/CD and not all runtime dependencies are available for python 3.13.
|
|
30
32
|
|
|
31
33
|
Install the latest development version directly from GitHub:
|
|
32
34
|
|
|
@@ -146,7 +146,7 @@ class CacheStore(ABC):
|
|
|
146
146
|
"""
|
|
147
147
|
|
|
148
148
|
# TODO: run in parallel?
|
|
149
|
-
return [self.put(d, cp) for d, cp in zip(data_path, cache_path)]
|
|
149
|
+
return [self.put(d, cp) for d, cp in zip(data_path, cache_path, strict=True)]
|
|
150
150
|
|
|
151
151
|
# In the three methods below, child classes have a complete docstring.
|
|
152
152
|
|
|
@@ -1356,7 +1356,7 @@ class Flight(GeoVectorDataset):
|
|
|
1356
1356
|
# NOTE: geod.npts does not return the initial or terminal points
|
|
1357
1357
|
lonlats: list[tuple[float, float]] = geod.npts(lon0, lat0, lon1, lat1, n_steps)
|
|
1358
1358
|
|
|
1359
|
-
lons, lats = zip(*lonlats)
|
|
1359
|
+
lons, lats = zip(*lonlats, strict=True)
|
|
1360
1360
|
longitudes.extend(lons)
|
|
1361
1361
|
latitudes.extend(lats)
|
|
1362
1362
|
|
|
@@ -1657,10 +1657,11 @@ def _return_linestring(data: dict[str, npt.NDArray[np.float64]]) -> list[list[fl
|
|
|
1657
1657
|
The list of coordinates
|
|
1658
1658
|
"""
|
|
1659
1659
|
# rounding to reduce the size of resultant json arrays
|
|
1660
|
-
points = zip(
|
|
1660
|
+
points = zip(
|
|
1661
1661
|
np.round(data["longitude"], decimals=4),
|
|
1662
1662
|
np.round(data["latitude"], decimals=4),
|
|
1663
1663
|
np.round(data["altitude"], decimals=4),
|
|
1664
|
+
strict=True,
|
|
1664
1665
|
)
|
|
1665
1666
|
return [list(p) for p in points]
|
|
1666
1667
|
|
|
@@ -1949,7 +1950,9 @@ def _altitude_interpolation_climb_descend_middle(
|
|
|
1949
1950
|
# Form array of cumulative altitude values if the flight were to climb
|
|
1950
1951
|
# at nominal_rocd over each group of nan
|
|
1951
1952
|
cumalt_list = []
|
|
1952
|
-
for start_na_idx, end_na_idx, size in zip(
|
|
1953
|
+
for start_na_idx, end_na_idx, size in zip(
|
|
1954
|
+
start_na_idxs, end_na_idxs, na_group_size, strict=True
|
|
1955
|
+
):
|
|
1953
1956
|
if s[start_na_idx] <= s[end_na_idx]:
|
|
1954
1957
|
cumalt_list.append(np.arange(1, size, dtype=float))
|
|
1955
1958
|
else:
|
|
@@ -2053,7 +2056,7 @@ def filter_altitude(
|
|
|
2053
2056
|
--------
|
|
2054
2057
|
:meth:`traffic.core.flight.Flight.filter`
|
|
2055
2058
|
:func:`scipy.signal.medfilt`
|
|
2056
|
-
"""
|
|
2059
|
+
"""
|
|
2057
2060
|
if not len(altitude_ft):
|
|
2058
2061
|
raise ValueError("Altitude must have non-zero length to filter")
|
|
2059
2062
|
|
|
@@ -2114,7 +2117,7 @@ def filter_altitude(
|
|
|
2114
2117
|
|
|
2115
2118
|
result = np.copy(altitude_ft)
|
|
2116
2119
|
if np.any(start_idxs):
|
|
2117
|
-
for i0, i1 in zip(start_idxs, end_idxs):
|
|
2120
|
+
for i0, i1 in zip(start_idxs, end_idxs, strict=True):
|
|
2118
2121
|
result[i0:i1] = altitude_filt[i0:i1]
|
|
2119
2122
|
|
|
2120
2123
|
# reapply Savitzky-Golay filter to smooth climb and descent
|
|
@@ -76,6 +76,7 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
|
|
|
76
76
|
self.method = _pick_method(scipy.__version__, method)
|
|
77
77
|
self.bounds_error = bounds_error
|
|
78
78
|
self.fill_value = fill_value
|
|
79
|
+
self._spline = None
|
|
79
80
|
|
|
80
81
|
def _prepare_xi_simple(self, xi: npt.NDArray[np.float64]) -> npt.NDArray[np.bool_]:
|
|
81
82
|
"""Run looser version of :meth:`_prepare_xi`.
|
|
@@ -215,7 +216,8 @@ class PycontrailsRegularGridInterpolator(scipy.interpolate.RegularGridInterpolat
|
|
|
215
216
|
|
|
216
217
|
if ndim == 1:
|
|
217
218
|
# np.interp could be better ... although that may also promote the dtype
|
|
218
|
-
|
|
219
|
+
# 1-d view is required for evaluate_linear_1d
|
|
220
|
+
return rgi_cython.evaluate_linear_1d(values, indices[0, :], norm_distances[0, :], out)
|
|
219
221
|
|
|
220
222
|
msg = f"Invalid number of dimensions: {ndim}"
|
|
221
223
|
raise ValueError(msg)
|
|
@@ -9,7 +9,15 @@ import pathlib
|
|
|
9
9
|
import typing
|
|
10
10
|
import warnings
|
|
11
11
|
from abc import ABC, abstractmethod
|
|
12
|
-
from collections.abc import
|
|
12
|
+
from collections.abc import (
|
|
13
|
+
Generator,
|
|
14
|
+
Hashable,
|
|
15
|
+
Iterable,
|
|
16
|
+
Iterator,
|
|
17
|
+
Mapping,
|
|
18
|
+
MutableMapping,
|
|
19
|
+
Sequence,
|
|
20
|
+
)
|
|
13
21
|
from contextlib import ExitStack
|
|
14
22
|
from datetime import datetime
|
|
15
23
|
from typing import (
|
|
@@ -62,12 +70,12 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
62
70
|
cachestore: CacheStore | None
|
|
63
71
|
|
|
64
72
|
#: Default dimension order for DataArray or Dataset (x, y, z, t)
|
|
65
|
-
dim_order:
|
|
73
|
+
dim_order: tuple[Hashable, Hashable, Hashable, Hashable] = (
|
|
66
74
|
"longitude",
|
|
67
75
|
"latitude",
|
|
68
76
|
"level",
|
|
69
77
|
"time",
|
|
70
|
-
|
|
78
|
+
)
|
|
71
79
|
|
|
72
80
|
def __repr__(self) -> str:
|
|
73
81
|
data = getattr(self, "data", None)
|
|
@@ -192,10 +200,8 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
192
200
|
def _validate_transpose(self) -> None:
|
|
193
201
|
"""Check that data is transposed according to :attr:`dim_order`."""
|
|
194
202
|
|
|
195
|
-
dims_tuple = tuple(self.dim_order)
|
|
196
|
-
|
|
197
203
|
def _check_da(da: xr.DataArray, key: Hashable | None = None) -> None:
|
|
198
|
-
if da.dims !=
|
|
204
|
+
if da.dims != self.dim_order:
|
|
199
205
|
if key is not None:
|
|
200
206
|
msg = (
|
|
201
207
|
f"Data dimension not transposed on variable '{key}'. Initiate with"
|
|
@@ -263,7 +269,7 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
263
269
|
self.data["time"] = self.data["time"].astype("datetime64[ns]", copy=False)
|
|
264
270
|
|
|
265
271
|
# sortby to ensure each coordinate has ascending order
|
|
266
|
-
self.data = self.data.sortby(self.dim_order, ascending=True)
|
|
272
|
+
self.data = self.data.sortby(list(self.dim_order), ascending=True)
|
|
267
273
|
|
|
268
274
|
if not self.is_wrapped:
|
|
269
275
|
# Ensure longitude is contained in interval [-180, 180)
|
|
@@ -285,7 +291,7 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
285
291
|
self._validate_latitude()
|
|
286
292
|
|
|
287
293
|
# transpose to have ordering (x, y, z, t, ...)
|
|
288
|
-
dim_order = self.dim_order
|
|
294
|
+
dim_order = [*self.dim_order, *(d for d in self.data.dims if d not in self.dim_order)]
|
|
289
295
|
self.data = self.data.transpose(*dim_order)
|
|
290
296
|
|
|
291
297
|
# single level data
|
|
@@ -481,7 +487,7 @@ class MetBase(ABC, Generic[XArrayType]):
|
|
|
481
487
|
self.cachestore = self.cachestore or DiskCacheStore()
|
|
482
488
|
|
|
483
489
|
# group by hour and save one dataset for each hour to temp file
|
|
484
|
-
times, datasets = zip(*dataset.groupby("time", squeeze=False))
|
|
490
|
+
times, datasets = zip(*dataset.groupby("time", squeeze=False), strict=True)
|
|
485
491
|
|
|
486
492
|
# Open ExitStack to control temp_file context manager
|
|
487
493
|
with ExitStack() as stack:
|
|
@@ -912,7 +918,7 @@ class MetDataset(MetBase):
|
|
|
912
918
|
KeyError
|
|
913
919
|
Raises when dataset does not contain variable in ``vars``
|
|
914
920
|
"""
|
|
915
|
-
if isinstance(vars,
|
|
921
|
+
if isinstance(vars, MetVariable | str):
|
|
916
922
|
vars = (vars,)
|
|
917
923
|
|
|
918
924
|
met_keys: list[str] = []
|
|
@@ -1014,7 +1020,7 @@ class MetDataset(MetBase):
|
|
|
1014
1020
|
|
|
1015
1021
|
@overrides
|
|
1016
1022
|
def broadcast_coords(self, name: str) -> xr.DataArray:
|
|
1017
|
-
da = xr.ones_like(self.data[
|
|
1023
|
+
da = xr.ones_like(self.data[next(iter(self.data.keys()))]) * self.data[name]
|
|
1018
1024
|
da.name = name
|
|
1019
1025
|
|
|
1020
1026
|
return da
|
|
@@ -1066,7 +1072,7 @@ class MetDataset(MetBase):
|
|
|
1066
1072
|
coords_vals = [indexes[key].values for key in coords_keys]
|
|
1067
1073
|
coords_meshes = np.meshgrid(*coords_vals, indexing="ij")
|
|
1068
1074
|
raveled_coords = (mesh.ravel() for mesh in coords_meshes)
|
|
1069
|
-
data = dict(zip(coords_keys, raveled_coords))
|
|
1075
|
+
data = dict(zip(coords_keys, raveled_coords, strict=True))
|
|
1070
1076
|
|
|
1071
1077
|
out = vector_module.GeoVectorDataset(data, copy=False)
|
|
1072
1078
|
for key, da in self.data.items():
|
|
@@ -1502,6 +1508,7 @@ class MetDataArray(MetBase):
|
|
|
1502
1508
|
bounds_error: bool = ...,
|
|
1503
1509
|
fill_value: float | np.float64 | None = ...,
|
|
1504
1510
|
localize: bool = ...,
|
|
1511
|
+
lowmem: bool = ...,
|
|
1505
1512
|
indices: interpolation.RGIArtifacts | None = ...,
|
|
1506
1513
|
return_indices: Literal[False] = ...,
|
|
1507
1514
|
) -> npt.NDArray[np.float64]: ...
|
|
@@ -1518,6 +1525,7 @@ class MetDataArray(MetBase):
|
|
|
1518
1525
|
bounds_error: bool = ...,
|
|
1519
1526
|
fill_value: float | np.float64 | None = ...,
|
|
1520
1527
|
localize: bool = ...,
|
|
1528
|
+
lowmem: bool = ...,
|
|
1521
1529
|
indices: interpolation.RGIArtifacts | None = ...,
|
|
1522
1530
|
return_indices: Literal[True],
|
|
1523
1531
|
) -> tuple[npt.NDArray[np.float64], interpolation.RGIArtifacts]: ...
|
|
@@ -1533,6 +1541,7 @@ class MetDataArray(MetBase):
|
|
|
1533
1541
|
bounds_error: bool = False,
|
|
1534
1542
|
fill_value: float | np.float64 | None = np.nan,
|
|
1535
1543
|
localize: bool = False,
|
|
1544
|
+
lowmem: bool = False,
|
|
1536
1545
|
indices: interpolation.RGIArtifacts | None = None,
|
|
1537
1546
|
return_indices: bool = False,
|
|
1538
1547
|
) -> npt.NDArray[np.float64] | tuple[npt.NDArray[np.float64], interpolation.RGIArtifacts]:
|
|
@@ -1540,7 +1549,9 @@ class MetDataArray(MetBase):
|
|
|
1540
1549
|
|
|
1541
1550
|
Zero dimensional coordinates are reshaped to 1D arrays.
|
|
1542
1551
|
|
|
1543
|
-
|
|
1552
|
+
If ``lowmem == False``, method automatically loads underlying :attr:`data` into
|
|
1553
|
+
memory. Otherwise, method iterates through smaller subsets of :attr:`data` and releases
|
|
1554
|
+
subsets from memory once interpolation against each subset is finished.
|
|
1544
1555
|
|
|
1545
1556
|
If ``method == "nearest"``, the out array will have the same ``dtype`` as
|
|
1546
1557
|
the underlying :attr:`data`.
|
|
@@ -1586,10 +1597,18 @@ class MetDataArray(MetBase):
|
|
|
1586
1597
|
localize: bool, optional
|
|
1587
1598
|
Experimental. If True, downselect gridded data to smallest bounding box containing
|
|
1588
1599
|
all points. By default False.
|
|
1600
|
+
lowmem: bool, optional
|
|
1601
|
+
Experimental. If True, iterate through points binned by the time coordinate of the
|
|
1602
|
+
grided data, and downselect gridded data to the smallest bounding box containing
|
|
1603
|
+
each binned set of point *before loading into memory*. This can significantly reduce
|
|
1604
|
+
memory consumption with large numbers of points at the cost of increased runtime.
|
|
1605
|
+
By default False.
|
|
1589
1606
|
indices: tuple | None, optional
|
|
1590
1607
|
Experimental. See :func:`interpolation.interp`. None by default.
|
|
1591
1608
|
return_indices: bool, optional
|
|
1592
1609
|
Experimental. See :func:`interpolation.interp`. False by default.
|
|
1610
|
+
Note that values returned differ when ``lowmem=True`` and ``lowmem=False``,
|
|
1611
|
+
so output should only be re-used in calls with the same ``lowmem`` value.
|
|
1593
1612
|
|
|
1594
1613
|
Returns
|
|
1595
1614
|
-------
|
|
@@ -1632,10 +1651,29 @@ class MetDataArray(MetBase):
|
|
|
1632
1651
|
>>> level = np.linspace(200, 300, 10)
|
|
1633
1652
|
>>> time = pd.date_range("2022-03-01T14", periods=10, freq="5min")
|
|
1634
1653
|
>>> mda.interpolate(longitude, latitude, level, time)
|
|
1654
|
+
array([220.44347694, 223.08900738, 225.74338924, 228.41642088,
|
|
1655
|
+
231.10858599, 233.54857391, 235.71504913, 237.86478872,
|
|
1656
|
+
239.99274623, 242.10792167])
|
|
1657
|
+
|
|
1658
|
+
>>> # Can easily switch to alternative low-memory implementation
|
|
1659
|
+
>>> mda.interpolate(longitude, latitude, level, time, lowmem=True)
|
|
1635
1660
|
array([220.44347694, 223.08900738, 225.74338924, 228.41642088,
|
|
1636
1661
|
231.10858599, 233.54857391, 235.71504913, 237.86478872,
|
|
1637
1662
|
239.99274623, 242.10792167])
|
|
1638
1663
|
"""
|
|
1664
|
+
if lowmem:
|
|
1665
|
+
return self._interp_lowmem(
|
|
1666
|
+
longitude,
|
|
1667
|
+
latitude,
|
|
1668
|
+
level,
|
|
1669
|
+
time,
|
|
1670
|
+
method=method,
|
|
1671
|
+
bounds_error=bounds_error,
|
|
1672
|
+
fill_value=fill_value,
|
|
1673
|
+
indices=indices,
|
|
1674
|
+
return_indices=return_indices,
|
|
1675
|
+
)
|
|
1676
|
+
|
|
1639
1677
|
# Load if necessary
|
|
1640
1678
|
if not self.in_memory:
|
|
1641
1679
|
self._check_memory("Interpolation over")
|
|
@@ -1660,6 +1698,100 @@ class MetDataArray(MetBase):
|
|
|
1660
1698
|
return_indices=return_indices,
|
|
1661
1699
|
)
|
|
1662
1700
|
|
|
1701
|
+
def _interp_lowmem(
|
|
1702
|
+
self,
|
|
1703
|
+
longitude: float | npt.NDArray[np.float64],
|
|
1704
|
+
latitude: float | npt.NDArray[np.float64],
|
|
1705
|
+
level: float | npt.NDArray[np.float64],
|
|
1706
|
+
time: np.datetime64 | npt.NDArray[np.datetime64],
|
|
1707
|
+
*,
|
|
1708
|
+
method: str = "linear",
|
|
1709
|
+
bounds_error: bool = False,
|
|
1710
|
+
fill_value: float | np.float64 | None = np.nan,
|
|
1711
|
+
minimize_memory: bool = False,
|
|
1712
|
+
indices: interpolation.RGIArtifacts | None = None,
|
|
1713
|
+
return_indices: bool = False,
|
|
1714
|
+
) -> npt.NDArray[np.float64] | tuple[npt.NDArray[np.float64], interpolation.RGIArtifacts]:
|
|
1715
|
+
"""Interpolate values against underlying DataArray.
|
|
1716
|
+
|
|
1717
|
+
This method is used by :meth:`interpolate` when ``lowmem=True``.
|
|
1718
|
+
Parameters and return types are identical to :meth:`interpolate`, except
|
|
1719
|
+
that the ``localize`` keyword argument is omitted.
|
|
1720
|
+
"""
|
|
1721
|
+
# Convert all inputs to 1d arrays
|
|
1722
|
+
# Not validating against ndim >= 2
|
|
1723
|
+
longitude, latitude, level, time = np.atleast_1d(longitude, latitude, level, time)
|
|
1724
|
+
|
|
1725
|
+
if bounds_error:
|
|
1726
|
+
_lowmem_boundscheck(time, self.data)
|
|
1727
|
+
|
|
1728
|
+
# Create buffers for holding interpolation output
|
|
1729
|
+
# Use np.full rather than np.empty so points not covered
|
|
1730
|
+
# by masks are filled with correct out-of-bounds values.
|
|
1731
|
+
out = np.full(longitude.shape, fill_value, dtype=self.data.dtype)
|
|
1732
|
+
if return_indices:
|
|
1733
|
+
rgi_artifacts = interpolation.RGIArtifacts(
|
|
1734
|
+
xi_indices=np.full((4, longitude.size), -1, dtype=np.int64),
|
|
1735
|
+
norm_distances=np.full((4, longitude.size), np.nan, dtype=np.float64),
|
|
1736
|
+
out_of_bounds=np.full((longitude.size,), True, dtype=np.bool_),
|
|
1737
|
+
)
|
|
1738
|
+
|
|
1739
|
+
# Iterate over portions of points between adjacent time steps in gridded data
|
|
1740
|
+
for mask in _lowmem_masks(time, self.data["time"].values):
|
|
1741
|
+
if mask is None or not np.any(mask):
|
|
1742
|
+
continue
|
|
1743
|
+
|
|
1744
|
+
lon_sl = longitude[mask]
|
|
1745
|
+
lat_sl = latitude[mask]
|
|
1746
|
+
lev_sl = level[mask]
|
|
1747
|
+
t_sl = time[mask]
|
|
1748
|
+
if indices is not None:
|
|
1749
|
+
indices_sl = interpolation.RGIArtifacts(
|
|
1750
|
+
xi_indices=indices.xi_indices[:, mask],
|
|
1751
|
+
norm_distances=indices.norm_distances[:, mask],
|
|
1752
|
+
out_of_bounds=indices.out_of_bounds[mask],
|
|
1753
|
+
)
|
|
1754
|
+
else:
|
|
1755
|
+
indices_sl = None
|
|
1756
|
+
|
|
1757
|
+
coords = {"longitude": lon_sl, "latitude": lat_sl, "level": lev_sl, "time": t_sl}
|
|
1758
|
+
if any(np.all(np.isnan(coord)) for coord in coords.values()):
|
|
1759
|
+
continue
|
|
1760
|
+
da = interpolation._localize(self.data, coords)
|
|
1761
|
+
if not da._in_memory:
|
|
1762
|
+
logger.debug(
|
|
1763
|
+
"Loading %s MB subset of %s into memory.",
|
|
1764
|
+
round(da.nbytes / 1_000_000, 2),
|
|
1765
|
+
da.name,
|
|
1766
|
+
)
|
|
1767
|
+
da.load()
|
|
1768
|
+
|
|
1769
|
+
tmp = interpolation.interp(
|
|
1770
|
+
longitude=lon_sl,
|
|
1771
|
+
latitude=lat_sl,
|
|
1772
|
+
level=lev_sl,
|
|
1773
|
+
time=t_sl,
|
|
1774
|
+
da=da,
|
|
1775
|
+
method=method,
|
|
1776
|
+
bounds_error=bounds_error,
|
|
1777
|
+
fill_value=fill_value,
|
|
1778
|
+
localize=False, # would be no-op; da is localized already
|
|
1779
|
+
indices=indices_sl,
|
|
1780
|
+
return_indices=return_indices,
|
|
1781
|
+
)
|
|
1782
|
+
|
|
1783
|
+
if return_indices:
|
|
1784
|
+
out[mask], rgi_sl = tmp
|
|
1785
|
+
rgi_artifacts.xi_indices[:, mask] = rgi_sl.xi_indices
|
|
1786
|
+
rgi_artifacts.norm_distances[:, mask] = rgi_sl.norm_distances
|
|
1787
|
+
rgi_artifacts.out_of_bounds[mask] = rgi_sl.out_of_bounds
|
|
1788
|
+
else:
|
|
1789
|
+
out[mask] = tmp
|
|
1790
|
+
|
|
1791
|
+
if return_indices:
|
|
1792
|
+
return out, rgi_artifacts
|
|
1793
|
+
return out
|
|
1794
|
+
|
|
1663
1795
|
def _check_memory(self, msg_start: str) -> None:
|
|
1664
1796
|
"""Check the memory usage of the underlying data.
|
|
1665
1797
|
|
|
@@ -1731,7 +1863,7 @@ class MetDataArray(MetBase):
|
|
|
1731
1863
|
cachestore = cachestore or DiskCacheStore()
|
|
1732
1864
|
chunks = chunks or {}
|
|
1733
1865
|
data = _load(hash, cachestore, chunks)
|
|
1734
|
-
return cls(data[
|
|
1866
|
+
return cls(data[next(iter(data.data_vars))])
|
|
1735
1867
|
|
|
1736
1868
|
@property
|
|
1737
1869
|
def proportion(self) -> float:
|
|
@@ -2124,7 +2256,7 @@ class MetDataArray(MetBase):
|
|
|
2124
2256
|
-----
|
|
2125
2257
|
Uses the `scikit-image Marching Cubes <https://scikit-image.org/docs/dev/auto_examples/edges/plot_marching_cubes.html>`_
|
|
2126
2258
|
algorithm to reconstruct a surface from the point-cloud like arrays.
|
|
2127
|
-
"""
|
|
2259
|
+
"""
|
|
2128
2260
|
try:
|
|
2129
2261
|
from skimage import measure
|
|
2130
2262
|
except ModuleNotFoundError as e:
|
|
@@ -2656,3 +2788,46 @@ def _add_vertical_coords(data: XArrayType) -> XArrayType:
|
|
|
2656
2788
|
data.coords["altitude"] = data.coords["altitude"].astype(dtype, copy=False)
|
|
2657
2789
|
|
|
2658
2790
|
return data
|
|
2791
|
+
|
|
2792
|
+
|
|
2793
|
+
def _lowmem_boundscheck(time: npt.NDArray[np.datetime64], da: xr.DataArray) -> None:
|
|
2794
|
+
"""Extra bounds check required with low-memory interpolation strategy.
|
|
2795
|
+
|
|
2796
|
+
Because the main loop in `_interp_lowmem` processes points between time steps
|
|
2797
|
+
in gridded data, it will never encounter points that are out-of-bounds in time
|
|
2798
|
+
and may fail to produce requested out-of-bounds errors.
|
|
2799
|
+
"""
|
|
2800
|
+
da_time = da["time"].to_numpy()
|
|
2801
|
+
if not np.all((time >= da_time.min()) & (time <= da_time.max())):
|
|
2802
|
+
axis = da.get_axis_num("time")
|
|
2803
|
+
msg = f"One of the requested xi is out of bounds in dimension {axis}"
|
|
2804
|
+
raise ValueError(msg)
|
|
2805
|
+
|
|
2806
|
+
|
|
2807
|
+
def _lowmem_masks(
|
|
2808
|
+
time: npt.NDArray[np.datetime64], t_met: npt.NDArray[np.datetime64]
|
|
2809
|
+
) -> Generator[npt.NDArray[np.bool_], None, None]:
|
|
2810
|
+
"""Generate sequence of masks for low-memory interpolation."""
|
|
2811
|
+
t_met_max = t_met.max()
|
|
2812
|
+
t_met_min = t_met.min()
|
|
2813
|
+
inbounds = (time >= t_met_min) & (time <= t_met_max)
|
|
2814
|
+
if not np.any(inbounds):
|
|
2815
|
+
return
|
|
2816
|
+
|
|
2817
|
+
earliest = np.nanmin(time)
|
|
2818
|
+
istart = 0 if earliest < t_met_min else np.flatnonzero(t_met <= earliest).max()
|
|
2819
|
+
latest = np.nanmax(time)
|
|
2820
|
+
iend = t_met.size - 1 if latest > t_met_max else np.flatnonzero(t_met >= latest).min()
|
|
2821
|
+
if istart == iend:
|
|
2822
|
+
yield inbounds
|
|
2823
|
+
return
|
|
2824
|
+
|
|
2825
|
+
# Sequence of masks covers elements in time in the interval [t_met[istart], t_met[iend]].
|
|
2826
|
+
# The first iteration masks elements in the interval [t_met[istart], t_met[istart+1]]
|
|
2827
|
+
# (inclusive of both endpoints).
|
|
2828
|
+
# Subsequent iterations mask elements in the interval (t_met[i], t_met[i+1]]
|
|
2829
|
+
# (inclusive of right endpoint only).
|
|
2830
|
+
for i in range(istart, iend):
|
|
2831
|
+
mask = ((time >= t_met[i]) if i == istart else (time > t_met[i])) & (time <= t_met[i + 1])
|
|
2832
|
+
if np.any(mask):
|
|
2833
|
+
yield mask
|
|
@@ -22,7 +22,7 @@ class MetVariable:
|
|
|
22
22
|
- `NCEP Grib v2 Code Table <https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-2.shtml>`_
|
|
23
23
|
|
|
24
24
|
Used for defining support parameters in a grib-like fashion.
|
|
25
|
-
"""
|
|
25
|
+
"""
|
|
26
26
|
|
|
27
27
|
#: Short variable name.
|
|
28
28
|
#: Chosen for greatest consistency between data sources.
|
|
@@ -11,7 +11,7 @@ import warnings
|
|
|
11
11
|
from abc import ABC, abstractmethod
|
|
12
12
|
from collections.abc import Sequence
|
|
13
13
|
from dataclasses import dataclass, fields
|
|
14
|
-
from typing import Any, NoReturn, TypeVar,
|
|
14
|
+
from typing import Any, NoReturn, TypeVar, overload
|
|
15
15
|
|
|
16
16
|
import numpy as np
|
|
17
17
|
import numpy.typing as npt
|
|
@@ -30,13 +30,13 @@ from pycontrails.utils.types import type_guard
|
|
|
30
30
|
logger = logging.getLogger(__name__)
|
|
31
31
|
|
|
32
32
|
#: Model input source types
|
|
33
|
-
ModelInput =
|
|
33
|
+
ModelInput = MetDataset | GeoVectorDataset | Flight | Sequence[Flight] | None
|
|
34
34
|
|
|
35
35
|
#: Model output source types
|
|
36
|
-
ModelOutput =
|
|
36
|
+
ModelOutput = MetDataArray | MetDataset | GeoVectorDataset | Flight | list[Flight]
|
|
37
37
|
|
|
38
38
|
#: Model attribute source types
|
|
39
|
-
SourceType =
|
|
39
|
+
SourceType = MetDataset | GeoVectorDataset | Flight | Fleet
|
|
40
40
|
|
|
41
41
|
_Source = TypeVar("_Source")
|
|
42
42
|
|
|
@@ -453,7 +453,7 @@ class Model(ABC):
|
|
|
453
453
|
return Fleet.from_seq(source)
|
|
454
454
|
|
|
455
455
|
# Raise error if source is not a MetDataset or GeoVectorDataset
|
|
456
|
-
if not isinstance(source,
|
|
456
|
+
if not isinstance(source, MetDataset | GeoVectorDataset):
|
|
457
457
|
msg = f"Unknown source type: {type(source)}"
|
|
458
458
|
raise TypeError(msg)
|
|
459
459
|
|