polytope-python 2.1.10__tar.gz → 2.1.12__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.1.10/polytope_python.egg-info → polytope_python-2.1.12}/PKG-INFO +1 -1
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Full_fields.md +2 -2
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/_version.py +1 -1
- {polytope_python-2.1.10 → polytope_python-2.1.12/polytope_python.egg-info}/PKG-INFO +1 -1
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_python.egg-info/SOURCES.txt +1 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/distance.rs +5 -7
- polytope_python-2.1.12/tests/test_nn_quadtree_search.py +276 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.github/ci-config.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.github/ci-hpc-config.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.github/workflows/cd.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.github/workflows/ci.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.github/workflows/downstream-ci.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.github/workflows/label-public-pr.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.github/workflows/test-pypi.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.gitignore +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.pre-commit-config.yaml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/.readthedocs.yaml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/ACKNOWLEDGEMENTS.rst +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/CONTRIBUTING.rst +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/LICENSE +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/Makefile +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/README.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/codecov.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/API.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Axis_types.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Datacube.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Overview.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Slicer.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/images/Polytope_APIs_3.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/images/polytope_components_5.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/images/slicing_process.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/shapes.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Overview/Overview.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Overview/Polytope_at_ECMWF.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Overview/images_overview/ecmwf_datacube.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Overview/images_overview/ecmwf_polytope.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Building_Features.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Example.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Getting_started.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Overview.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/images_users/shipping_route.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Client/Overview.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Server/Design.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Server/Overview.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Data_Portfolio.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Design_doc.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_boundingbox_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_circle_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_country_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_polygon_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_position_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_timeseries_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_trajectory_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_vertical_profile_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/boundingbox_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/circle_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/climate_dt_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/country_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/examples.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/extremes_dt_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/on-demand_dt_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/opendata_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/operational_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/polygon_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/position_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/timeseries_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/trajectory_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/vertical_profile_example.ipynb +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/boundingbox.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/circle.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/feature.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/polygon.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/position.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/timeseries.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/trajectory.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Features/vertical_profile.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Installation.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Overview.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Quick_Start.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/extra.css +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/flight_path.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/greece.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/logo.gif +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/polytope_feature.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/polytope_logo_new_animated_AdobeExpress_3.gif +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/timeseries.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/timeseries_example.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/images/timeseries_qs.png +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/index.md +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/docs/requirements.txt +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/3D_shipping_route.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/3D_shipping_route_wave_model.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/4D_flight_path.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/country_slicing.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/cyclic_route_around_earth.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shp +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shx +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/Shipping-Lanes-v1.shp +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/Shipping-Lanes-v1.shx +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/World_Countries__Generalized_.shp +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/World_Countries__Generalized_.shx +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/earth_image.jpg +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/map_earth_4k.jpg +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/mars_req_9km_wind.req +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/mars_req_levels.req +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/mars_req_timeseries.req +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/output4.grib +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/output4.req +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/output8.grib +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/output8.req +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/temp_model_levels.grib +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/timeseries_t2m.grib +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/winds.grib +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/healpix_grid_box_example.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/octahedral_grid_box_example.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/octahedral_grid_country_example.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/plotting_country_data.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/read_me_example.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/requirements_examples.txt +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/slicing_all_ecmwf_countries.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/timeseries_example.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/examples/wind_farms.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/mkdocs.yml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/fdb_performance.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/fdb_performance_3D.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/fdb_scalability_plot.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/fdb_slice_many_numbers_timeseries.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/performance_many_num_steps.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/plotting_scalability.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/scalability_test.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance/scalability_test_2.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance_unstructured/octahedral_vs_unstructured_slicing.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/performance_unstructured/plot_structured_vs_unstructured_slicing.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/backends/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/backends/catalogue_helper.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/backends/datacube.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/backends/fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/backends/mock.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/backends/xarray.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/datacube_axis.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/index_tree.proto +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/index_tree_pb2.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/quadtree/quad_tree.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/quadtree/quadtree_additional_operations.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/switching_grid_helper.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/tensor_index_tree.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_cyclic/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/datacube_mappers.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/icon.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/lambert_conformal.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/unstructured.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/local_regular.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/octahedral.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_gaussian.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_ll.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/regular.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_merger/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_merger/datacube_merger.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_reverse/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_reverse/datacube_reverse.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_transformations.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_type_change/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_type_change/datacube_type_change.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/datacube/tree_encoding.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/engine.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/hullslicer.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/optimised_point_in_polygon_slicer.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/optimised_quadtree_slicer.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/point_in_polygon_slicer.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/quadtree_slicer.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/engine/slicing_tools.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/options.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/polytope.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/shapes.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/utility/__init__.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/utility/combinatorics.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/utility/engine_tools.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/utility/exceptions.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/utility/geometry.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/utility/list_tools.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_feature/utility/profiling.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_python.egg-info/dependency_links.txt +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_python.egg-info/requires.txt +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/polytope_python.egg-info/top_level.txt +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/pyproject.toml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/Cargo.toml +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/healpix_nested.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/lambert_conformal.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/lib.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/list_tools.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/octahedral.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/point_in_polygon.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/quadtree_mod.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/rust/src/slicing_tools.rs +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/setup.cfg +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/setup.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/conftest.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/fdb_data/schema +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/helper_functions.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/profiled_quadtree.profile +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/quadtree_slicer_profiler.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_axis_mappers.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_bad_request_error.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_combinatorics.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_cyclic_axis_over_negative_vals.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_cyclic_axis_slicer_not_0.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_cyclic_axis_slicing.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_cyclic_nearest.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_cyclic_simple.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_cyclic_snapping.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_datacube_axes_init.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_datacube_mock.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_datacube_xarray.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_date_time_unmerged.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_ecmwf_oper_data_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_engine_slicer.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_fdb_datacube.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_fdb_unmap_tree.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_float_type.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_healpix_mapper.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_healpix_nested_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_hull_slicer.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_hullslicer_engine.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_icon_grid_unstructured.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_icon_grid_unstructured_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_incomplete_tree_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_lambert_lam_grid_unstructured_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_lambert_lam_grid_unstructured_fdb_optimised_quadtree.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_local_grid_cyclic.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_local_regular_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_local_swiss_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_mappers.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_merge_cyclic_octahedral.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_merge_octahedral_one_axis.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_merge_transformation.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_multiple_param_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_octahedral_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_orca_irregular_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_orca_irregular_grid_optimised_point_in_polygon.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_orca_irregular_grid_point_in_polygon.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_override_md5_hash_options.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_point_nearest.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_point_shape.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_point_union.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_polytope_extract.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_polytope_extract_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_profiling_requesttree.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_quad_tree.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_quadtree_edge_cases.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_quadtree_indices.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_quadtree_optimisation.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_reduced_ll_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_regular_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_regular_reduced_grid.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_request_tree.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_request_trees_after_slicing.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_reverse_transformation.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_shapes.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_shapes_volume.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slice_date_range_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slice_date_range_fdb_v2.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slice_fdb_box.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slicer_engine.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slicer_era5.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slicer_xarray.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slicing_unsliceable_axis.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slicing_xarray_3D.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_slicing_xarray_4D.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_snapping.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_snapping_real_data.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_tree_protobuf.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_tree_protobuf_encoding.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_tree_protobuf_encoding_fdb.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_type_change_transformation.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_union_gj.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_union_point_box.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tests/test_wave_spectra_data.py +0 -0
- {polytope_python-2.1.10 → polytope_python-2.1.12}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polytope-python
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.12
|
|
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>
|
|
@@ -11,8 +11,8 @@ Full field requests return GRIB data. They use the same keys as [MARS](https://c
|
|
|
11
11
|
For full field extraction the Polytope service supports retrieval from the following datasets:
|
|
12
12
|
|
|
13
13
|
* ECMWF Operational Data from the last two days [Further Details](https://apps.ecmwf.int/mars-catalogue/)
|
|
14
|
-
* DestinE Climate Digital Twin [Further Details](https://
|
|
15
|
-
* DestinE Extremes Digital Twin [Further Details](https://
|
|
14
|
+
* DestinE Climate Digital Twin [Further Details](https://destine.ecmwf.int/climate-change-adaptation-digital-twin-climate-dt/)
|
|
15
|
+
* DestinE Extremes Digital Twin [Further Details](https://destine.ecmwf.int/weather-induced-extremes-digital-twin/)
|
|
16
16
|
* DestinE On-Demand Extremes Digital Twin
|
|
17
17
|
* ECMWF Opendata for AI datasets [Further Details](https://confluence.ecmwf.int/display/DAC/ECMWF+open+data%3A+real-time+forecasts+from+IFS+and+AIFS#ECMWFopendata:realtimeforecastsfromIFSandAIFS-IndexFilesIndexfiles)
|
|
18
18
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# Do not change! Do not track in version control!
|
|
2
|
-
__version__ = "2.1.
|
|
2
|
+
__version__ = "2.1.12"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polytope-python
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.12
|
|
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>
|
|
@@ -242,6 +242,7 @@ tests/test_merge_cyclic_octahedral.py
|
|
|
242
242
|
tests/test_merge_octahedral_one_axis.py
|
|
243
243
|
tests/test_merge_transformation.py
|
|
244
244
|
tests/test_multiple_param_fdb.py
|
|
245
|
+
tests/test_nn_quadtree_search.py
|
|
245
246
|
tests/test_octahedral_grid.py
|
|
246
247
|
tests/test_orca_irregular_grid.py
|
|
247
248
|
tests/test_orca_irregular_grid_optimised_point_in_polygon.py
|
|
@@ -5,13 +5,11 @@ pub fn dist2(a: (f64, f64), b: (f64, f64)) -> f64 {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
pub fn box_dist2(center: (f64, f64), size: (f64, f64), point: (f64, f64)) -> f64 {
|
|
8
|
-
|
|
9
|
-
let
|
|
10
|
-
|
|
11
|
-
let
|
|
12
|
-
let
|
|
13
|
-
let min_y = center.1 - half_h;
|
|
14
|
-
let max_y = center.1 + half_h;
|
|
8
|
+
// `size` is already the half-extent of each axis
|
|
9
|
+
let min_x = center.0 - size.0;
|
|
10
|
+
let max_x = center.0 + size.0;
|
|
11
|
+
let min_y = center.1 - size.1;
|
|
12
|
+
let max_y = center.1 + size.1;
|
|
15
13
|
|
|
16
14
|
let dx = if point.0 < min_x {
|
|
17
15
|
min_x - point.0
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for QuadTree.nearest_neighbor() functionality.
|
|
3
|
+
|
|
4
|
+
Tests verify that:
|
|
5
|
+
1. The nearest neighbor search correctly identifies the closest point
|
|
6
|
+
2. Edge cases are handled (empty tree, single point, exact matches)
|
|
7
|
+
3. Various query positions work correctly
|
|
8
|
+
4. The algorithm works with large point sets
|
|
9
|
+
5. Negative coordinates and scattered points work as expected
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from polytope_feature.polytope_rs import QuadTree
|
|
16
|
+
except ImportError:
|
|
17
|
+
QuadTree = None
|
|
18
|
+
|
|
19
|
+
pytestmark = pytest.mark.skipif(QuadTree is None, reason="QuadTree not installed")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def squared_distance(p1, p2):
|
|
23
|
+
"""Calculate squared Euclidean distance between two points."""
|
|
24
|
+
dx = p1[0] - p2[0]
|
|
25
|
+
dy = p1[1] - p2[1]
|
|
26
|
+
return dx * dx + dy * dy
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def find_expected_nearest(query, points):
|
|
30
|
+
"""
|
|
31
|
+
Brute force search to find expected nearest neighbor.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
query: (x, y) query point
|
|
35
|
+
points: list of (x, y) points
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
tuple: (index, distance_squared) or (None, None) if no points
|
|
39
|
+
"""
|
|
40
|
+
if not points:
|
|
41
|
+
return None, None
|
|
42
|
+
|
|
43
|
+
min_distance = float("inf")
|
|
44
|
+
min_index = None
|
|
45
|
+
|
|
46
|
+
for idx, point in enumerate(points):
|
|
47
|
+
dist = squared_distance(query, point)
|
|
48
|
+
if dist < min_distance:
|
|
49
|
+
min_distance = dist
|
|
50
|
+
min_index = idx
|
|
51
|
+
|
|
52
|
+
return min_index, min_distance
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TestNearestNeighbor:
|
|
56
|
+
"""Test suite for nearest neighbor search."""
|
|
57
|
+
|
|
58
|
+
def test_simple_grid(self):
|
|
59
|
+
"""Test with simple grid of 5 points."""
|
|
60
|
+
print("\n=== Test: Simple Grid ===")
|
|
61
|
+
points = [
|
|
62
|
+
(10.0, 0.0), # index 1
|
|
63
|
+
(0.0, 0.0), # index 0
|
|
64
|
+
(0.0, 10.0), # index 2
|
|
65
|
+
(10.0, 10.0), # index 3
|
|
66
|
+
(5.0, 5.0), # index 4
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
quadtree = QuadTree()
|
|
70
|
+
quadtree.build_point_tree(points)
|
|
71
|
+
|
|
72
|
+
# Test 1: Query at (1, 1) - should find point (0, 0)
|
|
73
|
+
query = (1.0, 1.0)
|
|
74
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
75
|
+
expected = 1
|
|
76
|
+
assert result == expected, f"Query {query}: expected {expected}, got {result}"
|
|
77
|
+
print(f"✓ Query {query} → index {result} (point {points[result]})")
|
|
78
|
+
|
|
79
|
+
# Test 2: Query at (11, 11) - should find point (10, 10)
|
|
80
|
+
query = (11.0, 11.0)
|
|
81
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
82
|
+
expected = 3
|
|
83
|
+
assert result == expected, f"Query {query}: expected {expected}, got {result}"
|
|
84
|
+
print(f"✓ Query {query} → index {result} (point {points[result]})")
|
|
85
|
+
|
|
86
|
+
# Test 3: Query at (5.1, 5.1) - should find point (5, 5)
|
|
87
|
+
query = (5.1, 5.1)
|
|
88
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
89
|
+
expected = 4
|
|
90
|
+
assert result == expected, f"Query {query}: expected {expected}, got {result}"
|
|
91
|
+
print(f"✓ Query {query} → index {result} (point {points[result]})")
|
|
92
|
+
|
|
93
|
+
def test_exact_point_match(self):
|
|
94
|
+
"""Test querying exactly on a point in the tree."""
|
|
95
|
+
print("\n=== Test: Exact Point Match ===")
|
|
96
|
+
points = [
|
|
97
|
+
(0.0, 0.0),
|
|
98
|
+
(10.0, 10.0),
|
|
99
|
+
(20.0, 20.0),
|
|
100
|
+
(15.0, 5.0),
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
quadtree = QuadTree()
|
|
104
|
+
quadtree.build_point_tree(points)
|
|
105
|
+
|
|
106
|
+
# Query exactly at point (10, 10) - should find itself
|
|
107
|
+
query = (10.0, 10.0)
|
|
108
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
109
|
+
expected = 1
|
|
110
|
+
assert result == expected, f"Query {query}: expected {expected}, got {result}"
|
|
111
|
+
print(f"✓ Query exactly at {query} → index {result} (itself)")
|
|
112
|
+
|
|
113
|
+
def test_random_points_correctness(self):
|
|
114
|
+
"""Test correctness with random-ish points."""
|
|
115
|
+
print("\n=== Test: Random Points Correctness ===")
|
|
116
|
+
points = [
|
|
117
|
+
(1.0, 2.0),
|
|
118
|
+
(5.0, 3.0),
|
|
119
|
+
(9.0, 8.0),
|
|
120
|
+
(2.0, 9.0),
|
|
121
|
+
(7.0, 1.0),
|
|
122
|
+
(4.0, 6.0),
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
quadtree = QuadTree()
|
|
126
|
+
quadtree.build_point_tree(points)
|
|
127
|
+
|
|
128
|
+
test_queries = [
|
|
129
|
+
(3.5, 2.5),
|
|
130
|
+
(6.0, 4.0),
|
|
131
|
+
(0.5, 0.5),
|
|
132
|
+
(8.5, 8.5),
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
for query in test_queries:
|
|
136
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
137
|
+
expected_idx, expected_dist = find_expected_nearest(query, points)
|
|
138
|
+
|
|
139
|
+
assert result == expected_idx, f"Query {query}: expected {expected_idx}, got {result}"
|
|
140
|
+
|
|
141
|
+
# Verify distances match
|
|
142
|
+
result_dist = squared_distance(query, points[result])
|
|
143
|
+
assert abs(result_dist - expected_dist) < 1e-10, f"Distance mismatch for query {query}"
|
|
144
|
+
|
|
145
|
+
print(f"✓ Query {query} → index {result} (point {points[result]}, dist²={result_dist:.2f})")
|
|
146
|
+
|
|
147
|
+
def test_single_point(self):
|
|
148
|
+
"""Test edge case: only one point in tree."""
|
|
149
|
+
print("\n=== Test: Single Point ===")
|
|
150
|
+
points = [(5.0, 5.0)]
|
|
151
|
+
|
|
152
|
+
quadtree = QuadTree()
|
|
153
|
+
quadtree.build_point_tree(points)
|
|
154
|
+
|
|
155
|
+
query = (0.0, 0.0)
|
|
156
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
157
|
+
expected = 0
|
|
158
|
+
assert result == expected, f"Query {query}: expected {expected}, got {result}"
|
|
159
|
+
print(f"✓ Query {query} with single point → index {result}")
|
|
160
|
+
|
|
161
|
+
def test_empty_tree(self):
|
|
162
|
+
"""Test edge case: empty tree."""
|
|
163
|
+
print("\n=== Test: Empty Tree ===")
|
|
164
|
+
points = []
|
|
165
|
+
|
|
166
|
+
quadtree = QuadTree()
|
|
167
|
+
# Don't call build_point_tree on empty list
|
|
168
|
+
|
|
169
|
+
query = (5.0, 5.0)
|
|
170
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
171
|
+
assert result is None, f"Query on empty tree should return None, got {result}"
|
|
172
|
+
|
|
173
|
+
def test_distant_query(self):
|
|
174
|
+
"""Test with query point far from all tree points."""
|
|
175
|
+
print("\n=== Test: Distant Query ===")
|
|
176
|
+
points = [
|
|
177
|
+
(0.0, 0.0),
|
|
178
|
+
(1.0, 1.0),
|
|
179
|
+
(2.0, 2.0),
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
quadtree = QuadTree()
|
|
183
|
+
quadtree.build_point_tree(points)
|
|
184
|
+
|
|
185
|
+
# Query far away - should still find correct nearest
|
|
186
|
+
query = (100.0, 100.0)
|
|
187
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
188
|
+
expected = 2 # (2, 2) is closest
|
|
189
|
+
assert result == expected, f"Query {query}: expected {expected}, got {result}"
|
|
190
|
+
print(f"✓ Query {query} (distant) → index {result} (point {points[result]})")
|
|
191
|
+
|
|
192
|
+
def test_negative_coordinates(self):
|
|
193
|
+
"""Test with negative coordinates."""
|
|
194
|
+
print("\n=== Test: Negative Coordinates ===")
|
|
195
|
+
points = [
|
|
196
|
+
(-10.0, -10.0),
|
|
197
|
+
(-5.0, 0.0),
|
|
198
|
+
(0.0, 5.0),
|
|
199
|
+
(5.0, -5.0),
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
quadtree = QuadTree()
|
|
203
|
+
quadtree.build_point_tree(points)
|
|
204
|
+
|
|
205
|
+
query = (-6.0, -9.0)
|
|
206
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
207
|
+
expected_idx, _ = find_expected_nearest(query, points)
|
|
208
|
+
|
|
209
|
+
assert result == expected_idx, f"Query {query}: expected {expected_idx}, got {result}"
|
|
210
|
+
print(f"✓ Query {query} with negatives → index {result} (point {points[result]})")
|
|
211
|
+
|
|
212
|
+
def test_large_tree(self):
|
|
213
|
+
"""Test with many points to exercise quadtree splitting."""
|
|
214
|
+
print("\n=== Test: Large Tree (400 points) ===")
|
|
215
|
+
# Create 20x20 grid
|
|
216
|
+
points = []
|
|
217
|
+
for i in range(20):
|
|
218
|
+
for j in range(20):
|
|
219
|
+
points.append((i * 5.0, j * 5.0))
|
|
220
|
+
|
|
221
|
+
print(f"Building tree with {len(points)} points...")
|
|
222
|
+
quadtree = QuadTree()
|
|
223
|
+
quadtree.build_point_tree(points)
|
|
224
|
+
|
|
225
|
+
test_queries = [
|
|
226
|
+
(12.5, 12.5),
|
|
227
|
+
(75.0, 75.0),
|
|
228
|
+
(2.0, 98.0),
|
|
229
|
+
(97.0, 2.0),
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
for query in test_queries:
|
|
233
|
+
result = quadtree.nearest_neighbor(query, points)
|
|
234
|
+
expected_idx, expected_dist = find_expected_nearest(query, points)
|
|
235
|
+
|
|
236
|
+
assert result == expected_idx, f"Query {query}: expected {expected_idx}, got {result}"
|
|
237
|
+
|
|
238
|
+
result_dist = squared_distance(query, points[result])
|
|
239
|
+
print(f"✓ Query {query} → index {result} (dist²={result_dist:.2f})")
|
|
240
|
+
|
|
241
|
+
def run_all(self):
|
|
242
|
+
"""Run all tests."""
|
|
243
|
+
print("=" * 60)
|
|
244
|
+
print("QUADTREE NEAREST NEIGHBOR TESTS")
|
|
245
|
+
print("=" * 60)
|
|
246
|
+
|
|
247
|
+
tests = [
|
|
248
|
+
self.test_simple_grid,
|
|
249
|
+
self.test_exact_point_match,
|
|
250
|
+
self.test_random_points_correctness,
|
|
251
|
+
self.test_single_point,
|
|
252
|
+
self.test_empty_tree,
|
|
253
|
+
self.test_distant_query,
|
|
254
|
+
self.test_negative_coordinates,
|
|
255
|
+
self.test_large_tree,
|
|
256
|
+
]
|
|
257
|
+
|
|
258
|
+
passed = 0
|
|
259
|
+
failed = 0
|
|
260
|
+
|
|
261
|
+
for test in tests:
|
|
262
|
+
try:
|
|
263
|
+
test()
|
|
264
|
+
passed += 1
|
|
265
|
+
except AssertionError as e:
|
|
266
|
+
print(f"✗ FAILED: {e}")
|
|
267
|
+
failed += 1
|
|
268
|
+
except Exception as e:
|
|
269
|
+
print(f"✗ ERROR: {e}")
|
|
270
|
+
failed += 1
|
|
271
|
+
|
|
272
|
+
print("\n" + "=" * 60)
|
|
273
|
+
print(f"RESULTS: {passed} passed, {failed} failed")
|
|
274
|
+
print("=" * 60)
|
|
275
|
+
|
|
276
|
+
return failed == 0
|
|
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
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Axis_types.md
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Datacube.md
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Overview.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/Overview/Polytope_at_ECMWF.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Building_Features.md
RENAMED
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/boundingbox_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/circle_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/climate_dt_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/country_example.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/extremes_dt_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/on-demand_dt_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/opendata_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/operational_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/polygon_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/position_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/timeseries_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/docs/Service/Examples/trajectory_example.ipynb
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shp
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/World_Countries__Generalized_.shp
RENAMED
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/examples/data/World_Countries__Generalized_.shx
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.10 → polytope_python-2.1.12}/examples/octahedral_grid_country_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|