polytope-python 2.0.1__tar.gz → 2.0.3__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.
- {polytope_python-2.0.1/polytope_python.egg-info → polytope_python-2.0.3}/PKG-INFO +5 -1
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/_version.py +1 -1
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/backends/fdb.py +2 -1
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_type_change/datacube_type_change.py +25 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/quadtree_slicer.py +9 -2
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/polytope.py +25 -4
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/shapes.py +20 -12
- {polytope_python-2.0.1 → polytope_python-2.0.3/polytope_python.egg-info}/PKG-INFO +5 -1
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_python.egg-info/SOURCES.txt +2 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_python.egg-info/requires.txt +6 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/pyproject.toml +8 -0
- polytope_python-2.0.3/rust/src/distance.rs +33 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/lib.rs +1 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/quadtree_mod.rs +44 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_lambert_lam_grid_unstructured_fdb.py +96 -1
- polytope_python-2.0.3/tests/test_shapes_volume.py +21 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_type_change_transformation.py +10 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.github/ci-config.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.github/ci-hpc-config.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.github/workflows/cd.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.github/workflows/downstream-ci.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.github/workflows/label-public-pr.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.github/workflows/test-pypi.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.gitignore +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.pre-commit-config.yaml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/.readthedocs.yaml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/ACKNOWLEDGEMENTS.rst +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/CONTRIBUTING.rst +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/LICENSE +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/Makefile +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/README.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/codecov.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/API.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/Axis_types.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/Datacube.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/Overview.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/Slicer.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/images/Polytope_APIs_3.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/images/polytope_components_5.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/images/slicing_process.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/shapes.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Overview/Overview.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Overview/Polytope_at_ECMWF.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Overview/images_overview/ecmwf_datacube.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Overview/images_overview/ecmwf_polytope.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/User_Guide/Building_Features.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/User_Guide/Example.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/User_Guide/Getting_started.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/User_Guide/Overview.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/User_Guide/images_users/shipping_route.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Data_Portfolio.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Design_doc.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/OpenData/od_boundingbox_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/OpenData/od_country_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/OpenData/od_polygon_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/OpenData/od_timeseries_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/OpenData/od_trajectory_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/OpenData/od_vertical_profile_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/boundingbox_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/country_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/examples.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/polygon_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/timeseries_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/trajectory_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Examples/vertical_profile_example.ipynb +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Features/boundingbox.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Features/feature.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Features/polygon.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Features/timeseries.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Features/trajectory.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Features/vertical_profile.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Installation.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Overview.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Service/Quick_Start.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/extra.css +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/flight_path.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/greece.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/logo.gif +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/polytope_feature.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/polytope_logo_new_animated_AdobeExpress_3.gif +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/timeseries.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/timeseries_example.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/images/timeseries_qs.png +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/index.md +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/docs/requirements.txt +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/3D_shipping_route.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/3D_shipping_route_wave_model.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/4D_flight_path.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/country_slicing.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/cyclic_route_around_earth.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shp +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shx +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/Shipping-Lanes-v1.shp +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/Shipping-Lanes-v1.shx +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/World_Countries__Generalized_.shp +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/World_Countries__Generalized_.shx +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/earth_image.jpg +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/map_earth_4k.jpg +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/mars_req_9km_wind.req +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/mars_req_levels.req +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/mars_req_timeseries.req +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/output4.grib +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/output4.req +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/output8.grib +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/output8.req +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/temp_model_levels.grib +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/timeseries_t2m.grib +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/data/winds.grib +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/healpix_grid_box_example.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/octahedral_grid_box_example.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/octahedral_grid_country_example.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/plotting_country_data.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/read_me_example.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/requirements_examples.txt +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/slicing_all_ecmwf_countries.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/timeseries_example.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/examples/wind_farms.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/mkdocs.yml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/fdb_performance.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/fdb_performance_3D.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/fdb_scalability_plot.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/fdb_slice_many_numbers_timeseries.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/performance_many_num_steps.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/plotting_scalability.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/scalability_test.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance/scalability_test_2.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance_unstructured/octahedral_vs_unstructured_slicing.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/performance_unstructured/plot_structured_vs_unstructured_slicing.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/backends/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/backends/catalogue_helper.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/backends/datacube.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/backends/mock.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/backends/xarray.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/datacube_axis.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/index_tree.proto +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/index_tree_pb2.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/quadtree/quad_tree.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/quadtree/quadtree_additional_operations.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/tensor_index_tree.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_cyclic/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/datacube_mappers.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/icon.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/lambert_conformal.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/unstructured.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/local_regular.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/octahedral.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_gaussian.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_ll.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/regular.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_merger/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_merger/datacube_merger.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_reverse/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_reverse/datacube_reverse.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_transformations.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/transformations/datacube_type_change/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/datacube/tree_encoding.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/engine.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/hullslicer.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/optimised_point_in_polygon_slicer.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/optimised_quadtree_slicer.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/point_in_polygon_slicer.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/engine/slicing_tools.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/options.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/utility/__init__.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/utility/combinatorics.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/utility/engine_tools.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/utility/exceptions.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/utility/geometry.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/utility/list_tools.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_feature/utility/profiling.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_python.egg-info/dependency_links.txt +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/polytope_python.egg-info/top_level.txt +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/Cargo.toml +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/healpix_nested.rs +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/lambert_conformal.rs +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/list_tools.rs +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/octahedral.rs +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/point_in_polygon.rs +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/rust/src/slicing_tools.rs +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/setup.cfg +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/setup.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/conftest.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/fdb_data/schema +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/helper_functions.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/profiled_quadtree.profile +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/quadtree_slicer_profiler.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_axis_mappers.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_bad_request_error.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_combinatorics.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_cyclic_axis_over_negative_vals.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_cyclic_axis_slicer_not_0.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_cyclic_axis_slicing.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_cyclic_nearest.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_cyclic_simple.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_cyclic_snapping.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_datacube_axes_init.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_datacube_mock.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_datacube_xarray.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_date_time_unmerged.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_ecmwf_oper_data_fdb.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_engine_slicer.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_fdb_datacube.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_fdb_unmap_tree.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_float_type.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_healpix_mapper.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_healpix_nested_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_hull_slicer.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_hullslicer_engine.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_icon_grid_unstructured.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_icon_grid_unstructured_fdb.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_incomplete_tree_fdb.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_lambert_lam_grid_unstructured_fdb_optimised_quadtree.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_local_grid_cyclic.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_local_regular_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_local_swiss_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_mappers.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_merge_cyclic_octahedral.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_merge_octahedral_one_axis.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_merge_transformation.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_multiple_param_fdb.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_octahedral_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_orca_irregular_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_orca_irregular_grid_optimised_point_in_polygon.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_orca_irregular_grid_point_in_polygon.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_override_md5_hash_options.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_point_nearest.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_point_shape.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_point_union.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_polytope_extract.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_polytope_extract_fdb.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_profiling_requesttree.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_quad_tree.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_quadtree_edge_cases.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_quadtree_indices.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_quadtree_optimisation.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_reduced_ll_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_regular_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_regular_reduced_grid.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_request_tree.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_request_trees_after_slicing.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_reverse_transformation.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_shapes.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slice_date_range_fdb.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slice_date_range_fdb_v2.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slice_fdb_box.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slicer_engine.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slicer_era5.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slicer_xarray.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slicing_unsliceable_axis.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slicing_xarray_3D.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_slicing_xarray_4D.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_snapping.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_snapping_real_data.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_tree_protobuf.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_tree_protobuf_encoding.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_tree_protobuf_encoding_fdb.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_union_gj.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_union_point_box.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_wave_spectra_data.py +0 -0
- {polytope_python-2.0.1 → polytope_python-2.0.3}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polytope-python
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: Polytope datacube feature extraction library
|
|
5
5
|
Author-email: "European Centre for Medium-Range Weather Forecasts (ECMWF)" <software.support@ecmwf.int>
|
|
6
6
|
Maintainer-email: James Hawkes <James.Hawkes@ecmwf.int>, Mathilde Leuridan <Mathilde.Leuridan@ecmwf.int>
|
|
@@ -41,6 +41,10 @@ Requires-Dist: h5py; extra == "tests"
|
|
|
41
41
|
Requires-Dist: earthkit-data; extra == "tests"
|
|
42
42
|
Requires-Dist: matplotlib; extra == "tests"
|
|
43
43
|
Requires-Dist: pyfdb; extra == "tests"
|
|
44
|
+
Provides-Extra: unstructured
|
|
45
|
+
Requires-Dist: eckit; extra == "unstructured"
|
|
46
|
+
Provides-Extra: catalogue
|
|
47
|
+
Requires-Dist: qubed; extra == "catalogue"
|
|
44
48
|
Dynamic: license-file
|
|
45
49
|
|
|
46
50
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# Do not change! Do not track in version control!
|
|
2
|
-
__version__ = "2.0.
|
|
2
|
+
__version__ = "2.0.3"
|
|
@@ -5,7 +5,6 @@ from itertools import product
|
|
|
5
5
|
|
|
6
6
|
from ...utility.exceptions import BadGridError, BadRequestError, GribJumpNoIndexError
|
|
7
7
|
from ...utility.geometry import nearest_pt
|
|
8
|
-
from .catalogue_helper import find_axes_from_qube
|
|
9
8
|
from .datacube import Datacube, TensorIndexTree
|
|
10
9
|
|
|
11
10
|
|
|
@@ -42,6 +41,8 @@ class FDBDatacube(Datacube):
|
|
|
42
41
|
self.gj = gj
|
|
43
42
|
if len(alternative_axes) == 0:
|
|
44
43
|
if self.use_catalogue:
|
|
44
|
+
from .catalogue_helper import find_axes_from_qube
|
|
45
|
+
|
|
45
46
|
logging.info("Find GribJump axes for %s from catalogue", context)
|
|
46
47
|
self.fdb_coordinates = find_axes_from_qube(partial_request)
|
|
47
48
|
logging.info("Retrieved available GribJump axes for %s", context)
|
|
@@ -78,6 +78,30 @@ class TypeChangeStrToInt(DatacubeAxisTypeChange):
|
|
|
78
78
|
return tuple(values)
|
|
79
79
|
|
|
80
80
|
|
|
81
|
+
class TypeChangeStrToFloat(DatacubeAxisTypeChange):
|
|
82
|
+
def __init__(self, axis_name, new_type):
|
|
83
|
+
self.axis_name = axis_name
|
|
84
|
+
self._new_type = new_type
|
|
85
|
+
|
|
86
|
+
def transform_type(self, value):
|
|
87
|
+
try:
|
|
88
|
+
return float(value)
|
|
89
|
+
except ValueError:
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
def make_str(self, value):
|
|
93
|
+
values = []
|
|
94
|
+
for val in value:
|
|
95
|
+
int_val = int(val)
|
|
96
|
+
if val == int_val:
|
|
97
|
+
# we return a str of the integer value
|
|
98
|
+
values.append(str(int_val))
|
|
99
|
+
else:
|
|
100
|
+
# we return a str of the float value
|
|
101
|
+
values.append(str(val))
|
|
102
|
+
return tuple(values)
|
|
103
|
+
|
|
104
|
+
|
|
81
105
|
class TypeChangeStrToTimestamp(DatacubeAxisTypeChange):
|
|
82
106
|
def __init__(self, axis_name, new_type):
|
|
83
107
|
self.axis_name = axis_name
|
|
@@ -195,6 +219,7 @@ _type_to_datacube_type_change_lookup = {
|
|
|
195
219
|
"int": "TypeChangeStrToInt",
|
|
196
220
|
"date": "TypeChangeStrToTimestamp",
|
|
197
221
|
"time": "TypeChangeStrToTimedelta",
|
|
222
|
+
"float": "TypeChangeStrToFloat",
|
|
198
223
|
"subhourly_step_compact": "TypeChangeSubHourlyTimeStepsCompact",
|
|
199
224
|
"subhourly_step": "TypeChangeSubHourlyTimeSteps",
|
|
200
225
|
}
|
|
@@ -26,9 +26,16 @@ class QuadTreeSlicer(Engine):
|
|
|
26
26
|
|
|
27
27
|
def extract_single(self, datacube, polytope):
|
|
28
28
|
# extract a single polygon
|
|
29
|
+
# if need to find nearest points, then take alternative slicing method using quadtree to find nearest point
|
|
29
30
|
if use_rust:
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
if len(datacube.nearest_search) == 0:
|
|
32
|
+
polytope_points = [tuple(point) for point in polytope.points]
|
|
33
|
+
polygon_points = self.quad_tree.query_polygon(self.points, 0, polytope_points)
|
|
34
|
+
else:
|
|
35
|
+
nn_points = [tuple(pt) for pt in datacube.nearest_search[tuple(polytope.axes())]]
|
|
36
|
+
polygon_points = []
|
|
37
|
+
for nn_pt in nn_points:
|
|
38
|
+
polygon_points.append(self.quad_tree.nearest_neighbor(nn_pt, self.points))
|
|
32
39
|
else:
|
|
33
40
|
polygon_points = self.quad_tree.query_polygon(polytope)
|
|
34
41
|
return polygon_points
|
|
@@ -10,7 +10,7 @@ from .engine.optimised_quadtree_slicer import OptimisedQuadTreeSlicer
|
|
|
10
10
|
from .engine.point_in_polygon_slicer import PointInPolygonSlicer
|
|
11
11
|
from .engine.quadtree_slicer import QuadTreeSlicer
|
|
12
12
|
from .options import PolytopeOptions
|
|
13
|
-
from .shapes import ConvexPolytope, Product
|
|
13
|
+
from .shapes import ConvexPolytope, Point, Product, Union
|
|
14
14
|
from .utility.combinatorics import group, tensor_product
|
|
15
15
|
from .utility.exceptions import AxisOverdefinedError
|
|
16
16
|
from .utility.list_tools import unique
|
|
@@ -122,6 +122,7 @@ class Polytope:
|
|
|
122
122
|
|
|
123
123
|
def slice(self, datacube, polytopes: List[ConvexPolytope]):
|
|
124
124
|
"""Low-level API which takes a polytope geometry object and uses it to slice the datacube"""
|
|
125
|
+
|
|
125
126
|
self.find_compressed_axes(datacube, polytopes)
|
|
126
127
|
|
|
127
128
|
self.remove_compressed_axis_in_union(polytopes)
|
|
@@ -176,17 +177,37 @@ class Polytope:
|
|
|
176
177
|
slicer_type = self.engine_options[ax.name]
|
|
177
178
|
return self.engines[slicer_type]
|
|
178
179
|
|
|
180
|
+
def switch_polytope_dim(self, request):
|
|
181
|
+
# If we see a 2-dim slicer on an axis
|
|
182
|
+
# then make sure that if the shape is a point, we set decompose_1D to False
|
|
183
|
+
for ax, slicer in self.engine_options.items():
|
|
184
|
+
if slicer == "quadtree":
|
|
185
|
+
for shp in request.shapes:
|
|
186
|
+
if ax in shp.axes() and isinstance(shp, Point):
|
|
187
|
+
shp.decompose_1D = False
|
|
188
|
+
elif isinstance(shp, Union):
|
|
189
|
+
for s in shp._shapes:
|
|
190
|
+
if ax in s.axes() and isinstance(s, Point):
|
|
191
|
+
s.decompose_1D = False
|
|
192
|
+
|
|
179
193
|
def retrieve(self, request: Request, method="standard"):
|
|
180
194
|
"""Higher-level API which takes a request and uses it to slice the datacube"""
|
|
181
195
|
logging.info("Starting request for %s ", self.context)
|
|
182
196
|
self.datacube.check_branching_axes(request)
|
|
197
|
+
self.switch_polytope_dim(request)
|
|
183
198
|
for polytope in request.polytopes():
|
|
184
199
|
method = polytope.method
|
|
185
200
|
if method == "nearest":
|
|
186
|
-
if
|
|
187
|
-
self.datacube.nearest_search
|
|
201
|
+
if polytope.is_flat:
|
|
202
|
+
if self.datacube.nearest_search.get(tuple(polytope.axes()), None) is None:
|
|
203
|
+
self.datacube.nearest_search[tuple(polytope.axes())] = polytope.values
|
|
204
|
+
else:
|
|
205
|
+
self.datacube.nearest_search[tuple(polytope.axes())].append(polytope.values[0])
|
|
188
206
|
else:
|
|
189
|
-
self.datacube.nearest_search
|
|
207
|
+
if self.datacube.nearest_search.get(tuple(polytope.axes()), None) is None:
|
|
208
|
+
self.datacube.nearest_search[tuple(polytope.axes())] = polytope.points
|
|
209
|
+
else:
|
|
210
|
+
self.datacube.nearest_search[tuple(polytope.axes())].append(polytope.points[0])
|
|
190
211
|
request_tree = self.slice(self.datacube, request.polytopes())
|
|
191
212
|
logging.info("Created request tree for %s ", self.context)
|
|
192
213
|
self.datacube.get(request_tree, self.context)
|
|
@@ -77,8 +77,12 @@ class Product(Shape):
|
|
|
77
77
|
assert len(self._axes) == len(all_axes)
|
|
78
78
|
|
|
79
79
|
self._polytopes = []
|
|
80
|
+
self.is_flat = True
|
|
80
81
|
for poly in polytopes:
|
|
81
82
|
self._polytopes.extend(poly.polytope())
|
|
83
|
+
for p in poly.polytope():
|
|
84
|
+
if len(p.axes()) > 1:
|
|
85
|
+
self.is_flat = False
|
|
82
86
|
|
|
83
87
|
self.is_in_union = False
|
|
84
88
|
self.method = method
|
|
@@ -128,6 +132,7 @@ class Point(Shape):
|
|
|
128
132
|
self._axes = axes
|
|
129
133
|
self.values = values
|
|
130
134
|
self.method = method
|
|
135
|
+
self.decompose_1D = True
|
|
131
136
|
assert len(values) == 1
|
|
132
137
|
|
|
133
138
|
def axes(self):
|
|
@@ -137,11 +142,15 @@ class Point(Shape):
|
|
|
137
142
|
# TODO: change this to use the Product instead and return a Product here of the two 1D selects
|
|
138
143
|
|
|
139
144
|
polytopes = []
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
+
if self.decompose_1D:
|
|
146
|
+
for point in self.values:
|
|
147
|
+
poly_to_mult = []
|
|
148
|
+
for i in range(len(self._axes)):
|
|
149
|
+
poly_to_mult.append(ConvexPolytope([self._axes[i]], [[point[i]]], self.method, is_orthogonal=True))
|
|
150
|
+
polytopes.append(Product(*poly_to_mult, method=self.method, value=[point]))
|
|
151
|
+
else:
|
|
152
|
+
for point in self.values:
|
|
153
|
+
polytopes.append(ConvexPolytope(self._axes, [point], self.method, is_orthogonal=True))
|
|
145
154
|
self.polytopes = polytopes
|
|
146
155
|
|
|
147
156
|
return self.polytopes
|
|
@@ -464,19 +473,18 @@ class Union(Shape):
|
|
|
464
473
|
self._axes = axes
|
|
465
474
|
for s in shapes:
|
|
466
475
|
assert s.axes() == self.axes()
|
|
467
|
-
|
|
468
|
-
self.polytopes = []
|
|
469
476
|
self._shapes = shapes
|
|
470
477
|
|
|
471
|
-
for s in shapes:
|
|
472
|
-
for poly in s.polytope():
|
|
473
|
-
poly.add_to_union()
|
|
474
|
-
self.polytopes.append(poly)
|
|
475
|
-
|
|
476
478
|
def axes(self):
|
|
477
479
|
return self._axes
|
|
478
480
|
|
|
479
481
|
def polytope(self):
|
|
482
|
+
self.polytopes = []
|
|
483
|
+
|
|
484
|
+
for s in self._shapes:
|
|
485
|
+
for poly in s.polytope():
|
|
486
|
+
poly.add_to_union()
|
|
487
|
+
self.polytopes.append(poly)
|
|
480
488
|
return self.polytopes
|
|
481
489
|
|
|
482
490
|
def __repr__(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polytope-python
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: Polytope datacube feature extraction library
|
|
5
5
|
Author-email: "European Centre for Medium-Range Weather Forecasts (ECMWF)" <software.support@ecmwf.int>
|
|
6
6
|
Maintainer-email: James Hawkes <James.Hawkes@ecmwf.int>, Mathilde Leuridan <Mathilde.Leuridan@ecmwf.int>
|
|
@@ -41,6 +41,10 @@ Requires-Dist: h5py; extra == "tests"
|
|
|
41
41
|
Requires-Dist: earthkit-data; extra == "tests"
|
|
42
42
|
Requires-Dist: matplotlib; extra == "tests"
|
|
43
43
|
Requires-Dist: pyfdb; extra == "tests"
|
|
44
|
+
Provides-Extra: unstructured
|
|
45
|
+
Requires-Dist: eckit; extra == "unstructured"
|
|
46
|
+
Provides-Extra: catalogue
|
|
47
|
+
Requires-Dist: qubed; extra == "catalogue"
|
|
44
48
|
Dynamic: license-file
|
|
45
49
|
|
|
46
50
|
|
|
@@ -177,6 +177,7 @@ polytope_python.egg-info/dependency_links.txt
|
|
|
177
177
|
polytope_python.egg-info/requires.txt
|
|
178
178
|
polytope_python.egg-info/top_level.txt
|
|
179
179
|
rust/Cargo.toml
|
|
180
|
+
rust/src/distance.rs
|
|
180
181
|
rust/src/healpix_nested.rs
|
|
181
182
|
rust/src/lambert_conformal.rs
|
|
182
183
|
rust/src/lib.rs
|
|
@@ -246,6 +247,7 @@ tests/test_request_tree.py
|
|
|
246
247
|
tests/test_request_trees_after_slicing.py
|
|
247
248
|
tests/test_reverse_transformation.py
|
|
248
249
|
tests/test_shapes.py
|
|
250
|
+
tests/test_shapes_volume.py
|
|
249
251
|
tests/test_slice_date_range_fdb.py
|
|
250
252
|
tests/test_slice_date_range_fdb_v2.py
|
|
251
253
|
tests/test_slice_fdb_box.py
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
pub fn dist2(a: (f64, f64), b: (f64, f64)) -> f64 {
|
|
2
|
+
let dx = a.0 - b.0;
|
|
3
|
+
let dy = a.1 - b.1;
|
|
4
|
+
dx * dx + dy * dy
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
pub fn box_dist2(center: (f64, f64), size: (f64, f64), point: (f64, f64)) -> f64 {
|
|
8
|
+
let half_w = size.0 / 2.0;
|
|
9
|
+
let half_h = size.1 / 2.0;
|
|
10
|
+
|
|
11
|
+
let min_x = center.0 - half_w;
|
|
12
|
+
let max_x = center.0 + half_w;
|
|
13
|
+
let min_y = center.1 - half_h;
|
|
14
|
+
let max_y = center.1 + half_h;
|
|
15
|
+
|
|
16
|
+
let dx = if point.0 < min_x {
|
|
17
|
+
min_x - point.0
|
|
18
|
+
} else if point.0 > max_x {
|
|
19
|
+
point.0 - max_x
|
|
20
|
+
} else {
|
|
21
|
+
0.0
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
let dy = if point.1 < min_y {
|
|
25
|
+
min_y - point.1
|
|
26
|
+
} else if point.1 > max_y {
|
|
27
|
+
point.1 - max_y
|
|
28
|
+
} else {
|
|
29
|
+
0.0
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
dx * dx + dy * dy
|
|
33
|
+
}
|
|
@@ -9,6 +9,7 @@ use pyo3::exceptions::PyRuntimeError;
|
|
|
9
9
|
// TODO: look at rust built in arena
|
|
10
10
|
|
|
11
11
|
use crate::slicing_tools::{is_contained_in, slice_in_two};
|
|
12
|
+
use crate::distance::{dist2, box_dist2};
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
|
|
@@ -54,6 +55,16 @@ impl QuadTree {
|
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
fn nearest_neighbor(&self, query: (f64, f64), quadtree_points: Vec<(f64, f64)>) -> Option<usize> {
|
|
59
|
+
if self.nodes.is_empty() {
|
|
60
|
+
return None;
|
|
61
|
+
}
|
|
62
|
+
let mut best_idx = None;
|
|
63
|
+
let mut best_dist2 = f64::INFINITY;
|
|
64
|
+
self.nn_search(0, query, &mut best_idx, &mut best_dist2, &quadtree_points);
|
|
65
|
+
best_idx
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
fn sizeof(&self) -> usize {
|
|
58
69
|
let mut size = size_of::<Self>();
|
|
59
70
|
let nodes_size: usize = self.nodes.len() * size_of::<QuadTreeNode>();
|
|
@@ -145,6 +156,39 @@ impl QuadTree {
|
|
|
145
156
|
points.into_iter().map(|(x, y)| [x,y]).collect()
|
|
146
157
|
}
|
|
147
158
|
|
|
159
|
+
fn nn_search(
|
|
160
|
+
&self,
|
|
161
|
+
node_idx: usize,
|
|
162
|
+
query: (f64, f64),
|
|
163
|
+
best_idx: &mut Option<usize>,
|
|
164
|
+
best_dist2: &mut f64,
|
|
165
|
+
quadtree_points: &Vec<(f64, f64)>
|
|
166
|
+
) {
|
|
167
|
+
let node = &self.nodes[node_idx];
|
|
168
|
+
|
|
169
|
+
// if this node is farther than the current best, ignore
|
|
170
|
+
if box_dist2(node.center, node.size, query) > *best_dist2 {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// compare distance of points inside leaf node
|
|
175
|
+
if let Some(point_indices) = &node.points {
|
|
176
|
+
for &pi in point_indices {
|
|
177
|
+
let p = quadtree_points[pi];
|
|
178
|
+
let d2 = dist2(p, query);
|
|
179
|
+
if d2 < *best_dist2 {
|
|
180
|
+
*best_dist2 = d2;
|
|
181
|
+
*best_idx = Some(pi);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// else, recurse into children
|
|
187
|
+
for &child_idx in &node.children {
|
|
188
|
+
self.nn_search(child_idx, query, best_idx, best_dist2, &quadtree_points);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
148
192
|
fn convert_polygon(&self, points: Option<Vec<(f64, f64)>>) -> Option<Vec<[f64; 2]>> {
|
|
149
193
|
points.map(|pts| pts.into_iter().map(|(x, y)| [x, y]).collect())
|
|
150
194
|
}
|
{polytope_python-2.0.1 → polytope_python-2.0.3}/tests/test_lambert_lam_grid_unstructured_fdb.py
RENAMED
|
@@ -6,7 +6,7 @@ import pytest
|
|
|
6
6
|
from helper_functions import find_nearest_latlon
|
|
7
7
|
|
|
8
8
|
from polytope_feature.polytope import Polytope, Request
|
|
9
|
-
from polytope_feature.shapes import Box, Select
|
|
9
|
+
from polytope_feature.shapes import Box, Point, Select, Union
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class TestQuadTreeSlicer:
|
|
@@ -111,3 +111,98 @@ class TestQuadTreeSlicer:
|
|
|
111
111
|
# plt.scatter(eccodes_lons, eccodes_lats, s=6, c="green")
|
|
112
112
|
# plt.colorbar(label="Temperature")
|
|
113
113
|
# plt.show()
|
|
114
|
+
|
|
115
|
+
@pytest.mark.fdb
|
|
116
|
+
def test_quad_tree_slicer_extract_point(self):
|
|
117
|
+
import pygribjump as gj
|
|
118
|
+
|
|
119
|
+
request = Request(
|
|
120
|
+
Select("date", [pd.Timestamp("20250221T0000")]),
|
|
121
|
+
Select("step", [0]),
|
|
122
|
+
Select("param", ["130"]),
|
|
123
|
+
Select("levtype", ["sfc"]),
|
|
124
|
+
Point(["latitude", "longitude"], [[44.25, 5.55]], method="nearest"),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
self.fdbdatacube = gj.GribJump()
|
|
128
|
+
|
|
129
|
+
self.API = Polytope(
|
|
130
|
+
datacube=self.fdbdatacube,
|
|
131
|
+
options=self.options,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
result = self.API.retrieve(request)
|
|
135
|
+
assert len(result.leaves) == 1
|
|
136
|
+
result.pprint()
|
|
137
|
+
|
|
138
|
+
lats = []
|
|
139
|
+
lons = []
|
|
140
|
+
eccodes_lats = []
|
|
141
|
+
eccodes_lons = []
|
|
142
|
+
tol = 1e-3
|
|
143
|
+
leaves = result.leaves
|
|
144
|
+
for i in range(len(leaves)):
|
|
145
|
+
cubepath = leaves[i].flatten()
|
|
146
|
+
lat = cubepath["latitude"][0]
|
|
147
|
+
lon = cubepath["longitude"][0]
|
|
148
|
+
lats.append(lat)
|
|
149
|
+
lons.append(lon)
|
|
150
|
+
nearest_points = find_nearest_latlon("tests/data/lambert_lam_one_message.grib", lat, lon)
|
|
151
|
+
eccodes_lat = nearest_points[0][0]["lat"]
|
|
152
|
+
eccodes_lon = nearest_points[0][0]["lon"]
|
|
153
|
+
eccodes_lats.append(eccodes_lat)
|
|
154
|
+
eccodes_lons.append(eccodes_lon)
|
|
155
|
+
assert eccodes_lat - tol <= lat
|
|
156
|
+
assert lat <= eccodes_lat + tol
|
|
157
|
+
assert eccodes_lon - tol <= lon
|
|
158
|
+
assert lon <= eccodes_lon + tol
|
|
159
|
+
|
|
160
|
+
@pytest.mark.fdb
|
|
161
|
+
def test_quad_tree_slicer_extract_point_union(self):
|
|
162
|
+
import pygribjump as gj
|
|
163
|
+
|
|
164
|
+
pt1 = Point(["latitude", "longitude"], [[44.25, 5.55]], method="nearest")
|
|
165
|
+
pt2 = Point(["latitude", "longitude"], [[43.75, 5.35]], method="nearest")
|
|
166
|
+
|
|
167
|
+
pt_union = Union(["latitude", "longitude"], pt1, pt2)
|
|
168
|
+
|
|
169
|
+
request = Request(
|
|
170
|
+
Select("date", [pd.Timestamp("20250221T0000")]),
|
|
171
|
+
Select("step", [0]),
|
|
172
|
+
Select("param", ["130"]),
|
|
173
|
+
Select("levtype", ["sfc"]),
|
|
174
|
+
pt_union,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
self.fdbdatacube = gj.GribJump()
|
|
178
|
+
|
|
179
|
+
self.API = Polytope(
|
|
180
|
+
datacube=self.fdbdatacube,
|
|
181
|
+
options=self.options,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
result = self.API.retrieve(request)
|
|
185
|
+
assert len(result.leaves) == 2
|
|
186
|
+
result.pprint()
|
|
187
|
+
|
|
188
|
+
lats = []
|
|
189
|
+
lons = []
|
|
190
|
+
eccodes_lats = []
|
|
191
|
+
eccodes_lons = []
|
|
192
|
+
tol = 1e-3
|
|
193
|
+
leaves = result.leaves
|
|
194
|
+
for i in range(len(leaves)):
|
|
195
|
+
cubepath = leaves[i].flatten()
|
|
196
|
+
lat = cubepath["latitude"][0]
|
|
197
|
+
lon = cubepath["longitude"][0]
|
|
198
|
+
lats.append(lat)
|
|
199
|
+
lons.append(lon)
|
|
200
|
+
nearest_points = find_nearest_latlon("tests/data/lambert_lam_one_message.grib", lat, lon)
|
|
201
|
+
eccodes_lat = nearest_points[0][0]["lat"]
|
|
202
|
+
eccodes_lon = nearest_points[0][0]["lon"]
|
|
203
|
+
eccodes_lats.append(eccodes_lat)
|
|
204
|
+
eccodes_lons.append(eccodes_lon)
|
|
205
|
+
assert eccodes_lat - tol <= lat
|
|
206
|
+
assert lat <= eccodes_lat + tol
|
|
207
|
+
assert eccodes_lon - tol <= lon
|
|
208
|
+
assert lon <= eccodes_lon + tol
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from polytope_feature.shapes import ConvexPolytope, Point, Product
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestShapeDimension:
|
|
5
|
+
def setup_method(self, method):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
def test_point_dimension(self):
|
|
9
|
+
point_1D = Point(["lat", "lon"], [[1, 1]])
|
|
10
|
+
|
|
11
|
+
for shp in point_1D.polytope():
|
|
12
|
+
assert isinstance(shp, Product)
|
|
13
|
+
for polytope in shp._polytopes:
|
|
14
|
+
assert len(polytope.axes()) == 1
|
|
15
|
+
|
|
16
|
+
point_2D = Point(["lat", "lon"], [[1, 1]])
|
|
17
|
+
point_2D.decompose_1D = False
|
|
18
|
+
|
|
19
|
+
for shp in point_2D.polytope():
|
|
20
|
+
assert isinstance(shp, ConvexPolytope)
|
|
21
|
+
assert len(shp.axes()) == 2
|
|
@@ -3,6 +3,7 @@ import pandas as pd
|
|
|
3
3
|
import xarray as xr
|
|
4
4
|
|
|
5
5
|
from polytope_feature.datacube.transformations.datacube_type_change.datacube_type_change import (
|
|
6
|
+
TypeChangeStrToFloat,
|
|
6
7
|
TypeChangeSubHourlyTimeSteps,
|
|
7
8
|
TypeChangeSubHourlyTimeStepsCompact,
|
|
8
9
|
)
|
|
@@ -33,6 +34,15 @@ class TestIntTypeChangeTransformation:
|
|
|
33
34
|
result.pprint()
|
|
34
35
|
assert result.leaves[0].flatten()["step"] == (0,)
|
|
35
36
|
|
|
37
|
+
def test_float_type_change_axis(self):
|
|
38
|
+
type_change_transform = TypeChangeStrToFloat("step", "float")
|
|
39
|
+
|
|
40
|
+
assert type_change_transform.transform_type("0.5") == 0.5
|
|
41
|
+
assert type_change_transform.transform_type("0") == 0.0
|
|
42
|
+
|
|
43
|
+
assert type_change_transform.make_str([0.1]) == ("0.1",)
|
|
44
|
+
assert type_change_transform.make_str([0.0]) == ("0",)
|
|
45
|
+
|
|
36
46
|
def test_subhourly_step_type_change_axis(self):
|
|
37
47
|
type_change_transform = TypeChangeSubHourlyTimeSteps("step", "subhourly_step")
|
|
38
48
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Developer_Guide/Axis_types.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/Overview/Polytope_at_ECMWF.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/User_Guide/Building_Features.md
RENAMED
|
File without changes
|
|
File without changes
|
{polytope_python-2.0.1 → polytope_python-2.0.3}/docs/Algorithm/User_Guide/Getting_started.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|