polytope-python 2.1.9__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.9/polytope_python.egg-info → polytope_python-2.1.12}/PKG-INFO +1 -1
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Full_fields.md +2 -2
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/_version.py +1 -1
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/options.py +9 -5
- {polytope_python-2.1.9 → polytope_python-2.1.12/polytope_python.egg-info}/PKG-INFO +1 -1
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_python.egg-info/SOURCES.txt +1 -0
- {polytope_python-2.1.9 → 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.9 → polytope_python-2.1.12}/.github/ci-config.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.github/ci-hpc-config.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.github/workflows/cd.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.github/workflows/ci.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.github/workflows/downstream-ci.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.github/workflows/label-public-pr.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.github/workflows/test-pypi.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.gitignore +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.pre-commit-config.yaml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/.readthedocs.yaml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/ACKNOWLEDGEMENTS.rst +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/CONTRIBUTING.rst +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/LICENSE +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/Makefile +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/README.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/codecov.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/API.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Axis_types.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Datacube.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Overview.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/Slicer.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/images/Polytope_APIs_3.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/images/polytope_components_5.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/images/slicing_process.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Developer_Guide/shapes.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Overview/Overview.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Overview/Polytope_at_ECMWF.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Overview/images_overview/ecmwf_datacube.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/Overview/images_overview/ecmwf_polytope.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Building_Features.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Example.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Getting_started.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Overview.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/images_users/shipping_route.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Client/Overview.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Server/Design.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Server/Overview.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Data_Portfolio.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Design_doc.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_boundingbox_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_circle_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_country_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_polygon_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_position_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_timeseries_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_trajectory_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/OpenData/od_vertical_profile_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/boundingbox_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/circle_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/climate_dt_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/country_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/examples.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/extremes_dt_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/on-demand_dt_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/opendata_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/operational_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/polygon_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/position_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/timeseries_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/trajectory_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/vertical_profile_example.ipynb +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/boundingbox.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/circle.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/feature.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/polygon.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/position.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/timeseries.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/trajectory.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Features/vertical_profile.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Installation.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Overview.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Quick_Start.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/extra.css +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/flight_path.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/greece.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/logo.gif +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/polytope_feature.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/polytope_logo_new_animated_AdobeExpress_3.gif +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/timeseries.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/timeseries_example.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/images/timeseries_qs.png +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/index.md +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/docs/requirements.txt +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/3D_shipping_route.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/3D_shipping_route_wave_model.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/4D_flight_path.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/country_slicing.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/cyclic_route_around_earth.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shp +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shx +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/Shipping-Lanes-v1.shp +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/Shipping-Lanes-v1.shx +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/World_Countries__Generalized_.shp +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/World_Countries__Generalized_.shx +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/earth_image.jpg +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/map_earth_4k.jpg +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/mars_req_9km_wind.req +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/mars_req_levels.req +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/mars_req_timeseries.req +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/output4.grib +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/output4.req +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/output8.grib +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/output8.req +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/temp_model_levels.grib +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/timeseries_t2m.grib +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/data/winds.grib +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/healpix_grid_box_example.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/octahedral_grid_box_example.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/octahedral_grid_country_example.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/plotting_country_data.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/read_me_example.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/requirements_examples.txt +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/slicing_all_ecmwf_countries.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/timeseries_example.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/examples/wind_farms.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/mkdocs.yml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/fdb_performance.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/fdb_performance_3D.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/fdb_scalability_plot.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/fdb_slice_many_numbers_timeseries.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/performance_many_num_steps.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/plotting_scalability.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/scalability_test.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance/scalability_test_2.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance_unstructured/octahedral_vs_unstructured_slicing.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/performance_unstructured/plot_structured_vs_unstructured_slicing.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/backends/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/backends/catalogue_helper.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/backends/datacube.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/backends/fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/backends/mock.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/backends/xarray.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/datacube_axis.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/index_tree.proto +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/index_tree_pb2.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/quadtree/quad_tree.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/quadtree/quadtree_additional_operations.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/switching_grid_helper.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/tensor_index_tree.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_cyclic/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/datacube_mappers.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/icon.py +0 -0
- {polytope_python-2.1.9 → 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.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/irregular_mapper_types/unstructured.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/local_regular.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/octahedral.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_gaussian.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_ll.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/regular.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_merger/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_merger/datacube_merger.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_reverse/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_reverse/datacube_reverse.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_transformations.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_type_change/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/transformations/datacube_type_change/datacube_type_change.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/datacube/tree_encoding.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/engine.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/hullslicer.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/optimised_point_in_polygon_slicer.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/optimised_quadtree_slicer.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/point_in_polygon_slicer.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/quadtree_slicer.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/engine/slicing_tools.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/polytope.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/shapes.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/utility/__init__.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/utility/combinatorics.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/utility/engine_tools.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/utility/exceptions.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/utility/geometry.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/utility/list_tools.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_feature/utility/profiling.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_python.egg-info/dependency_links.txt +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_python.egg-info/requires.txt +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/polytope_python.egg-info/top_level.txt +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/pyproject.toml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/Cargo.toml +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/healpix_nested.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/lambert_conformal.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/lib.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/list_tools.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/octahedral.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/point_in_polygon.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/quadtree_mod.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/rust/src/slicing_tools.rs +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/setup.cfg +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/setup.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/conftest.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/fdb_data/schema +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/helper_functions.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/profiled_quadtree.profile +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/quadtree_slicer_profiler.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_axis_mappers.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_bad_request_error.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_combinatorics.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_cyclic_axis_over_negative_vals.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_cyclic_axis_slicer_not_0.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_cyclic_axis_slicing.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_cyclic_nearest.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_cyclic_simple.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_cyclic_snapping.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_datacube_axes_init.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_datacube_mock.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_datacube_xarray.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_date_time_unmerged.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_ecmwf_oper_data_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_engine_slicer.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_fdb_datacube.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_fdb_unmap_tree.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_float_type.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_healpix_mapper.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_healpix_nested_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_hull_slicer.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_hullslicer_engine.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_icon_grid_unstructured.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_icon_grid_unstructured_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_incomplete_tree_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_lambert_lam_grid_unstructured_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_lambert_lam_grid_unstructured_fdb_optimised_quadtree.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_local_grid_cyclic.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_local_regular_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_local_swiss_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_mappers.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_merge_cyclic_octahedral.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_merge_octahedral_one_axis.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_merge_transformation.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_multiple_param_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_octahedral_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_orca_irregular_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_orca_irregular_grid_optimised_point_in_polygon.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_orca_irregular_grid_point_in_polygon.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_override_md5_hash_options.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_point_nearest.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_point_shape.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_point_union.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_polytope_extract.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_polytope_extract_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_profiling_requesttree.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_quad_tree.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_quadtree_edge_cases.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_quadtree_indices.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_quadtree_optimisation.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_reduced_ll_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_regular_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_regular_reduced_grid.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_request_tree.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_request_trees_after_slicing.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_reverse_transformation.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_shapes.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_shapes_volume.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slice_date_range_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slice_date_range_fdb_v2.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slice_fdb_box.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slicer_engine.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slicer_era5.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slicer_xarray.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slicing_unsliceable_axis.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slicing_xarray_3D.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_slicing_xarray_4D.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_snapping.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_snapping_real_data.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_tree_protobuf.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_tree_protobuf_encoding.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_tree_protobuf_encoding_fdb.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_type_change_transformation.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_union_gj.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_union_point_box.py +0 -0
- {polytope_python-2.1.9 → polytope_python-2.1.12}/tests/test_wave_spectra_data.py +0 -0
- {polytope_python-2.1.9 → 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,12 +1,11 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import logging
|
|
2
3
|
from abc import ABC
|
|
3
4
|
from typing import Dict, List, Literal, Optional, Tuple, Union
|
|
4
5
|
|
|
5
6
|
from conflator import ConfigModel, Conflator
|
|
6
7
|
from pydantic import ConfigDict
|
|
7
8
|
|
|
8
|
-
from polytope_feature.datacube.switching_grid_helper import lookup_grid_config
|
|
9
|
-
|
|
10
9
|
|
|
11
10
|
class TransformationConfig(ConfigModel):
|
|
12
11
|
model_config = ConfigDict(extra="forbid")
|
|
@@ -111,9 +110,12 @@ class PolytopeOptions(ABC):
|
|
|
111
110
|
replaced = replace_grid_config_in_options(config_options, pre_path)
|
|
112
111
|
if replaced:
|
|
113
112
|
axis_config = config_options.axis_config
|
|
114
|
-
except Exception:
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
except Exception as e:
|
|
114
|
+
logging.warning(
|
|
115
|
+
"Dynamic grid replacement failed for georef '%s': %s. Using static grid config.",
|
|
116
|
+
pre_path.get("georef", "unknown"),
|
|
117
|
+
e,
|
|
118
|
+
)
|
|
117
119
|
return (
|
|
118
120
|
axis_config,
|
|
119
121
|
compressed_axes_config,
|
|
@@ -151,6 +153,8 @@ def gridspec_to_grid_config(gridspec, md5hash):
|
|
|
151
153
|
|
|
152
154
|
|
|
153
155
|
def replace_grid_config_in_options(options, req):
|
|
156
|
+
from polytope_feature.datacube.switching_grid_helper import lookup_grid_config
|
|
157
|
+
|
|
154
158
|
gridspec, md5hash = lookup_grid_config(req)
|
|
155
159
|
grid_config = gridspec_to_grid_config(gridspec, md5hash)
|
|
156
160
|
if grid_config is not None:
|
|
@@ -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.9 → polytope_python-2.1.12}/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.1.9 → 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.9 → polytope_python-2.1.12}/docs/Algorithm/User_Guide/Building_Features.md
RENAMED
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.9 → 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.9 → polytope_python-2.1.12}/docs/Service/Examples/boundingbox_example.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/climate_dt_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/country_example.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/extremes_dt_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/on-demand_dt_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/opendata_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/operational_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/polygon_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/position_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → polytope_python-2.1.12}/docs/Service/Examples/timeseries_example.ipynb
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → 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.9 → polytope_python-2.1.12}/examples/data/EMODnet_HA_WindFarms_pg_20220324.shp
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → 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.9 → polytope_python-2.1.12}/examples/data/World_Countries__Generalized_.shp
RENAMED
|
File without changes
|
{polytope_python-2.1.9 → 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
|