polytope-python 1.0.34__tar.gz → 1.0.36__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-1.0.34/polytope_python.egg-info → polytope_python-1.0.36}/PKG-INFO +1 -1
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/fdb.py +13 -8
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/datacube_mappers.py +3 -5
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix.py +8 -5
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +36 -46
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/local_regular.py +8 -5
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/octahedral.py +10 -7
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_gaussian.py +8 -16
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_ll.py +8 -5
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/regular.py +8 -5
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/tree_encoding.py +2 -1
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/engine/hullslicer.py +16 -5
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/polytope.py +7 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/shapes.py +47 -8
- polytope_python-1.0.36/polytope_feature/version.py +1 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36/polytope_python.egg-info}/PKG-INFO +1 -1
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_python.egg-info/SOURCES.txt +1 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_fdb_unmap_tree.py +9 -9
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_healpix_mapper.py +1 -1
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_mappers.py +3 -3
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_point_shape.py +9 -3
- polytope_python-1.0.36/tests/test_point_union.py +148 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_regular_grid.py +1 -1
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_regular_reduced_grid.py +3 -0
- polytope_python-1.0.34/polytope_feature/version.py +0 -1
- {polytope_python-1.0.34 → polytope_python-1.0.36}/LICENSE +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/MANIFEST.in +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/datacube.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/mock.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/xarray.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/datacube_axis.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/index_tree_pb2.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/tensor_index_tree.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_cyclic/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_merger/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_merger/datacube_merger.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_reverse/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_reverse/datacube_reverse.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_transformations.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_type_change/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/transformations/datacube_type_change/datacube_type_change.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/engine/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/engine/engine.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/options.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/utility/__init__.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/utility/combinatorics.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/utility/exceptions.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/utility/geometry.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/utility/list_tools.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/utility/profiling.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_python.egg-info/dependency_links.txt +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_python.egg-info/not-zip-safe +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_python.egg-info/requires.txt +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_python.egg-info/top_level.txt +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/pyproject.toml +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/requirements.txt +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/setup.cfg +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/setup.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_axis_mappers.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_bad_request_error.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_combinatorics.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_cyclic_axis_over_negative_vals.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_cyclic_axis_slicer_not_0.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_cyclic_axis_slicing.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_cyclic_nearest.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_cyclic_simple.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_cyclic_snapping.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_datacube_axes_init.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_datacube_mock.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_datacube_xarray.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_date_time_unmerged.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_ecmwf_oper_data_fdb.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_engine_slicer.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_fdb_datacube.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_float_type.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_healpix_nested_grid.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_hull_slicer.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_hullslicer_engine.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_incomplete_tree_fdb.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_local_grid_cyclic.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_local_regular_grid.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_local_swiss_grid.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_merge_cyclic_octahedral.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_merge_octahedral_one_axis.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_merge_transformation.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_multiple_param_fdb.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_octahedral_grid.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_override_md5_hash_options.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_point_nearest.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_profiling_requesttree.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_reduced_ll_grid.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_request_tree.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_request_trees_after_slicing.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_reverse_transformation.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_shapes.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slice_date_range_fdb.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slice_date_range_fdb_v2.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slice_fdb_box.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slicer_engine.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slicer_era5.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slicer_xarray.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slicing_unsliceable_axis.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slicing_xarray_3D.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_slicing_xarray_4D.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_snapping.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_snapping_real_data.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_tree_protobuf.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_tree_protobuf_encoding.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_tree_protobuf_encoding_fdb.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_type_change_transformation.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_union_gj.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_union_point_box.py +0 -0
- {polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_wave_spectra_data.py +0 -0
|
@@ -227,17 +227,22 @@ class FDBDatacube(Datacube):
|
|
|
227
227
|
first_ax_name = requests.children[0].axis.name
|
|
228
228
|
second_ax_name = requests.children[0].children[0].axis.name
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
axes_in_nearest_search = [
|
|
231
|
+
first_ax_name not in self.nearest_search.keys(),
|
|
232
|
+
second_ax_name not in self.nearest_search.keys(),
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
if all(not item for item in axes_in_nearest_search):
|
|
231
236
|
raise Exception("nearest point search axes are wrong")
|
|
232
237
|
|
|
233
238
|
second_ax = requests.children[0].children[0].axis
|
|
239
|
+
nearest_pts = self.nearest_search.get(first_ax_name, None)
|
|
240
|
+
if nearest_pts is None:
|
|
241
|
+
nearest_pts = self.nearest_search[second_ax_name]
|
|
234
242
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
self.nearest_search[first_ax_name][0], self.nearest_search[second_ax_name][0]
|
|
239
|
-
)
|
|
240
|
-
]
|
|
243
|
+
transformed_nearest_pts = []
|
|
244
|
+
for point in nearest_pts:
|
|
245
|
+
transformed_nearest_pts.append([point[0], second_ax._remap_val_to_axis_range(point[1])])
|
|
241
246
|
|
|
242
247
|
found_latlon_pts = []
|
|
243
248
|
for lat_child in requests.children:
|
|
@@ -246,7 +251,7 @@ class FDBDatacube(Datacube):
|
|
|
246
251
|
|
|
247
252
|
# now find the nearest lat lon to the points requested
|
|
248
253
|
nearest_latlons = []
|
|
249
|
-
for pt in
|
|
254
|
+
for pt in transformed_nearest_pts:
|
|
250
255
|
nearest_latlon = nearest_pt(found_latlon_pts, pt)
|
|
251
256
|
nearest_latlons.append(nearest_latlon)
|
|
252
257
|
|
|
@@ -99,16 +99,14 @@ class DatacubeMapper(DatacubeAxisTransformation):
|
|
|
99
99
|
return self.second_axis_vals(first_val)
|
|
100
100
|
|
|
101
101
|
def unmap_path_key(self, key_value_path, leaf_path, unwanted_path, axis):
|
|
102
|
-
|
|
102
|
+
values = key_value_path[axis.name]
|
|
103
103
|
if axis.name == self._mapped_axes()[0]:
|
|
104
104
|
unwanted_val = key_value_path[self._mapped_axes()[0]]
|
|
105
105
|
unwanted_path[axis.name] = unwanted_val
|
|
106
106
|
if axis.name == self._mapped_axes()[1]:
|
|
107
107
|
first_val = unwanted_path[self._mapped_axes()[0]]
|
|
108
|
-
unmapped_idx = []
|
|
109
|
-
|
|
110
|
-
unmapped_idx.append(self.unmap(first_val, (val,)))
|
|
111
|
-
# unmapped_idx = self.unmap(first_val, value)
|
|
108
|
+
# unmapped_idx = [self.unmap(first_val, (val,)) for val in value]
|
|
109
|
+
unmapped_idx = self.unmap(first_val, values)
|
|
112
110
|
leaf_path.pop(self._mapped_axes()[0], None)
|
|
113
111
|
key_value_path.pop(axis.name)
|
|
114
112
|
key_value_path[self.old_axis] = unmapped_idx
|
|
@@ -133,14 +133,17 @@ class HealpixGridMapper(DatacubeMapper):
|
|
|
133
133
|
else:
|
|
134
134
|
return idx
|
|
135
135
|
|
|
136
|
-
def unmap(self, first_val,
|
|
136
|
+
def unmap(self, first_val, second_vals):
|
|
137
137
|
tol = 1e-8
|
|
138
138
|
first_value = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
139
139
|
first_idx = self._first_axis_vals.index(first_value)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
return_idxs = []
|
|
141
|
+
for second_val in second_vals:
|
|
142
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0]
|
|
143
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
144
|
+
healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx)
|
|
145
|
+
return_idxs.append(healpix_index)
|
|
146
|
+
return return_idxs
|
|
144
147
|
|
|
145
148
|
|
|
146
149
|
# md5 grid hash in form {resolution : hash}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import bisect
|
|
2
1
|
import math
|
|
3
2
|
|
|
4
3
|
from ..datacube_mappers import DatacubeMapper
|
|
@@ -14,9 +13,11 @@ class NestedHealpixGridMapper(DatacubeMapper):
|
|
|
14
13
|
self._first_axis_vals = self.first_axis_vals()
|
|
15
14
|
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
16
15
|
self.Nside = self._resolution
|
|
16
|
+
self._cached_longitudes = {}
|
|
17
17
|
self.k = int(math.log2(self.Nside))
|
|
18
18
|
self.Npix = 12 * self.Nside * self.Nside
|
|
19
19
|
self.Ncap = (self.Nside * (self.Nside - 1)) << 1
|
|
20
|
+
self._healpix_longitudes = {}
|
|
20
21
|
if md5_hash is not None:
|
|
21
22
|
self.md5_hash = md5_hash
|
|
22
23
|
else:
|
|
@@ -58,7 +59,9 @@ class NestedHealpixGridMapper(DatacubeMapper):
|
|
|
58
59
|
return values
|
|
59
60
|
|
|
60
61
|
def second_axis_vals_from_idx(self, first_val_idx):
|
|
61
|
-
|
|
62
|
+
if first_val_idx not in self._healpix_longitudes:
|
|
63
|
+
self._healpix_longitudes[first_val_idx] = self.HEALPix_longitudes(first_val_idx)
|
|
64
|
+
values = self._healpix_longitudes[first_val_idx]
|
|
62
65
|
return values
|
|
63
66
|
|
|
64
67
|
def HEALPix_nj(self, i):
|
|
@@ -74,14 +77,19 @@ class NestedHealpixGridMapper(DatacubeMapper):
|
|
|
74
77
|
return self.HEALPix_nj(ni - 1 - i)
|
|
75
78
|
|
|
76
79
|
def HEALPix_longitudes(self, i):
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
if i in self._cached_longitudes:
|
|
81
|
+
return self._cached_longitudes[i]
|
|
82
|
+
else:
|
|
83
|
+
Nj = self.HEALPix_nj(i)
|
|
84
|
+
step = 360.0 / Nj
|
|
85
|
+
start = (
|
|
86
|
+
step / 2.0
|
|
87
|
+
if i < self._resolution or 3 * self._resolution - 1 < i or (i + self._resolution) % 2
|
|
88
|
+
else 0.0
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
longitudes = [start + n * step for n in range(Nj)]
|
|
92
|
+
self._cached_longitudes[i] = longitudes
|
|
85
93
|
return longitudes
|
|
86
94
|
|
|
87
95
|
def map_second_axis(self, first_val, lower, upper):
|
|
@@ -110,43 +118,25 @@ class NestedHealpixGridMapper(DatacubeMapper):
|
|
|
110
118
|
idx += second_idx
|
|
111
119
|
return idx
|
|
112
120
|
|
|
113
|
-
def
|
|
114
|
-
tol = 1e-10
|
|
115
|
-
second_axis_vals = self.second_axis_vals(first_val)
|
|
116
|
-
second_idx = bisect.bisect_left(second_axis_vals, second_val - tol)
|
|
117
|
-
return second_idx
|
|
118
|
-
|
|
119
|
-
def unmap_first_val_to_start_line_idx(self, first_val):
|
|
120
|
-
tol = 1e-8
|
|
121
|
-
first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0]
|
|
122
|
-
first_idx = self._first_axis_vals.index(first_val)
|
|
123
|
-
idx = 0
|
|
124
|
-
for i in range(self._resolution - 1):
|
|
125
|
-
if i != first_idx:
|
|
126
|
-
idx += 4 * (i + 1)
|
|
127
|
-
else:
|
|
128
|
-
return idx
|
|
129
|
-
for i in range(self._resolution - 1, 3 * self._resolution):
|
|
130
|
-
if i != first_idx:
|
|
131
|
-
idx += 4 * self._resolution
|
|
132
|
-
else:
|
|
133
|
-
return idx
|
|
134
|
-
for i in range(3 * self._resolution, 4 * self._resolution - 1):
|
|
135
|
-
if i != first_idx:
|
|
136
|
-
idx += 4 * (4 * self._resolution - 1 - i + 1)
|
|
137
|
-
else:
|
|
138
|
-
return idx
|
|
139
|
-
|
|
140
|
-
def unmap(self, first_val, second_val):
|
|
121
|
+
def unmap(self, first_val, second_vals):
|
|
141
122
|
tol = 1e-8
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
123
|
+
first_idx = next(
|
|
124
|
+
(i for i, val in enumerate(self._first_axis_vals) if first_val[0] - tol <= val <= first_val[0] + tol), None
|
|
125
|
+
)
|
|
126
|
+
if first_idx is None:
|
|
127
|
+
return None
|
|
128
|
+
second_axis_vals = self.second_axis_vals_from_idx(first_idx)
|
|
129
|
+
|
|
130
|
+
return_idxs = []
|
|
131
|
+
for second_val in second_vals:
|
|
132
|
+
second_idx = next(
|
|
133
|
+
(i for i, val in enumerate(second_axis_vals) if second_val - tol <= val <= second_val + tol), None
|
|
134
|
+
)
|
|
135
|
+
if second_idx is None:
|
|
136
|
+
return None
|
|
137
|
+
healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx)
|
|
138
|
+
return_idxs.append(healpix_index)
|
|
139
|
+
return return_idxs
|
|
150
140
|
|
|
151
141
|
def div_03(self, a, b):
|
|
152
142
|
t = 1 if a >= (b << 1) else 0
|
|
@@ -81,14 +81,17 @@ class LocalRegularGridMapper(DatacubeMapper):
|
|
|
81
81
|
first_idx = self._first_axis_vals.index(first_val)
|
|
82
82
|
return first_idx * self.second_resolution
|
|
83
83
|
|
|
84
|
-
def unmap(self, first_val,
|
|
84
|
+
def unmap(self, first_val, second_vals):
|
|
85
85
|
tol = 1e-8
|
|
86
86
|
first_val = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
87
87
|
first_idx = self._first_axis_vals.index(first_val)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
return_idxs = []
|
|
89
|
+
for second_val in second_vals:
|
|
90
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0]
|
|
91
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
92
|
+
final_index = self.axes_idx_to_regular_idx(first_idx, second_idx)
|
|
93
|
+
return_idxs.append(final_index)
|
|
94
|
+
return return_idxs
|
|
92
95
|
|
|
93
96
|
|
|
94
97
|
# md5 grid hash in form {resolution : hash}
|
|
@@ -7877,16 +7877,19 @@ class OctahedralGridMapper(DatacubeMapper):
|
|
|
7877
7877
|
def find_second_axis_idx(self, first_val, second_val):
|
|
7878
7878
|
(second_axis_spacing, first_idx) = self.second_axis_spacing(first_val)
|
|
7879
7879
|
tol = 1e-8
|
|
7880
|
-
if second_val
|
|
7881
|
-
second_idx = int(second_val
|
|
7880
|
+
if second_val / second_axis_spacing > int(second_val / second_axis_spacing) + 1 - tol:
|
|
7881
|
+
second_idx = int(second_val / second_axis_spacing) + 1
|
|
7882
7882
|
else:
|
|
7883
|
-
second_idx = int(second_val
|
|
7883
|
+
second_idx = int(second_val / second_axis_spacing)
|
|
7884
7884
|
return (first_idx, second_idx)
|
|
7885
7885
|
|
|
7886
|
-
def unmap(self, first_val,
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7886
|
+
def unmap(self, first_val, second_vals):
|
|
7887
|
+
return_idxs = []
|
|
7888
|
+
for second_val in second_vals:
|
|
7889
|
+
(first_idx, second_idx) = self.find_second_axis_idx(first_val, second_val)
|
|
7890
|
+
octahedral_index = self.axes_idx_to_octahedral_idx(first_idx, second_idx)
|
|
7891
|
+
return_idxs.append(octahedral_index)
|
|
7892
|
+
return return_idxs
|
|
7890
7893
|
|
|
7891
7894
|
|
|
7892
7895
|
# md5 grid hash in form {resolution : hash}
|
|
@@ -1432,25 +1432,17 @@ class ReducedGaussianGridMapper(DatacubeMapper):
|
|
|
1432
1432
|
idx += second_idx
|
|
1433
1433
|
return idx
|
|
1434
1434
|
|
|
1435
|
-
|
|
1436
|
-
# tol = 1e-10
|
|
1437
|
-
# second_axis_vals = self.second_axis_vals(first_val)
|
|
1438
|
-
# second_idx = bisect.bisect_left(second_axis_vals, second_val[0] - tol)
|
|
1439
|
-
# return second_idx
|
|
1440
|
-
|
|
1441
|
-
# def unmap(self, first_val, second_val):
|
|
1442
|
-
# (first_idx, second_idx) = self.find_second_idx(first_val, second_val)
|
|
1443
|
-
# octahedral_index = self.axes_idx_to_reduced_gaussian_idx(first_idx, second_idx)
|
|
1444
|
-
# return octahedral_index
|
|
1445
|
-
|
|
1446
|
-
def unmap(self, first_val, second_val):
|
|
1435
|
+
def unmap(self, first_val, second_vals):
|
|
1447
1436
|
tol = 1e-8
|
|
1448
1437
|
first_value = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
1449
1438
|
first_idx = self._first_axis_vals.index(first_value)
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1439
|
+
return_idxs = []
|
|
1440
|
+
for second_val in second_vals:
|
|
1441
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0]
|
|
1442
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
1443
|
+
reduced_gaussian_index = self.axes_idx_to_reduced_gaussian_idx(first_idx, second_idx)
|
|
1444
|
+
return_idxs.append(reduced_gaussian_index)
|
|
1445
|
+
return return_idxs
|
|
1454
1446
|
|
|
1455
1447
|
|
|
1456
1448
|
# md5 grid hash in form {resolution : hash}
|
|
@@ -5114,14 +5114,17 @@ class ReducedLatLonMapper(DatacubeMapper):
|
|
|
5114
5114
|
second_idx = bisect.bisect_left(second_axis_vals, second_val - tol)
|
|
5115
5115
|
return second_idx
|
|
5116
5116
|
|
|
5117
|
-
def unmap(self, first_val,
|
|
5117
|
+
def unmap(self, first_val, second_vals):
|
|
5118
5118
|
tol = 1e-8
|
|
5119
5119
|
first_value = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
5120
5120
|
first_idx = self._first_axis_vals.index(first_value)
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5121
|
+
return_idxs = []
|
|
5122
|
+
for second_val in second_vals:
|
|
5123
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0]
|
|
5124
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
5125
|
+
reduced_ll_index = self.axes_idx_to_reduced_ll_idx(first_idx, second_idx)
|
|
5126
|
+
return_idxs.append(reduced_ll_index)
|
|
5127
|
+
return return_idxs
|
|
5125
5128
|
|
|
5126
5129
|
|
|
5127
5130
|
# md5 grid hash in form {resolution : hash}
|
|
@@ -61,14 +61,17 @@ class RegularGridMapper(DatacubeMapper):
|
|
|
61
61
|
first_idx = self._first_axis_vals.index(first_val)
|
|
62
62
|
return first_idx * 4 * self._resolution
|
|
63
63
|
|
|
64
|
-
def unmap(self, first_val,
|
|
64
|
+
def unmap(self, first_val, second_vals):
|
|
65
65
|
tol = 1e-8
|
|
66
66
|
first_val = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
67
67
|
first_idx = self._first_axis_vals.index(first_val)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
return_idxs = []
|
|
69
|
+
for second_val in second_vals:
|
|
70
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val - tol <= i <= second_val + tol][0]
|
|
71
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
72
|
+
final_index = self.axes_idx_to_regular_idx(first_idx, second_idx)
|
|
73
|
+
return_idxs.append(final_index)
|
|
74
|
+
return return_idxs
|
|
72
75
|
|
|
73
76
|
|
|
74
77
|
# md5 grid hash in form {resolution : hash}
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/tree_encoding.py
RENAMED
|
@@ -38,7 +38,8 @@ def encode_child(tree: TensorIndexTree, child: TensorIndexTree, node, result_siz
|
|
|
38
38
|
|
|
39
39
|
if child.hidden:
|
|
40
40
|
# add indexes to parent and add also indexes size...
|
|
41
|
-
|
|
41
|
+
for tree_indexes in tree.indexes:
|
|
42
|
+
node.indexes.extend(tree_indexes)
|
|
42
43
|
break_tag = False
|
|
43
44
|
return break_tag
|
|
44
45
|
|
|
@@ -8,7 +8,7 @@ import scipy.spatial
|
|
|
8
8
|
from ..datacube.backends.datacube import Datacube
|
|
9
9
|
from ..datacube.datacube_axis import UnsliceableDatacubeAxis
|
|
10
10
|
from ..datacube.tensor_index_tree import TensorIndexTree
|
|
11
|
-
from ..shapes import ConvexPolytope
|
|
11
|
+
from ..shapes import ConvexPolytope, Product
|
|
12
12
|
from ..utility.combinatorics import group, tensor_product
|
|
13
13
|
from ..utility.exceptions import UnsliceableShapeError
|
|
14
14
|
from ..utility.geometry import lerp
|
|
@@ -76,8 +76,6 @@ class HullSlicer(Engine):
|
|
|
76
76
|
upper = ax.from_float(upper + tol)
|
|
77
77
|
flattened = node.flatten()
|
|
78
78
|
method = polytope.method
|
|
79
|
-
if method == "nearest":
|
|
80
|
-
datacube.nearest_search[ax.name] = polytope.points
|
|
81
79
|
|
|
82
80
|
# NOTE: caching
|
|
83
81
|
# Create a coupled_axes list inside of datacube and add to it during axis formation, then here
|
|
@@ -214,7 +212,11 @@ class HullSlicer(Engine):
|
|
|
214
212
|
|
|
215
213
|
# Convert the polytope points to float type to support triangulation and interpolation
|
|
216
214
|
for p in polytopes:
|
|
217
|
-
|
|
215
|
+
if isinstance(p, Product):
|
|
216
|
+
for poly in p.polytope():
|
|
217
|
+
self._unique_continuous_points(poly, datacube)
|
|
218
|
+
else:
|
|
219
|
+
self._unique_continuous_points(p, datacube)
|
|
218
220
|
|
|
219
221
|
groups, input_axes = group(polytopes)
|
|
220
222
|
datacube.validate(input_axes)
|
|
@@ -233,7 +235,16 @@ class HullSlicer(Engine):
|
|
|
233
235
|
new_c.extend(combi)
|
|
234
236
|
else:
|
|
235
237
|
new_c.append(combi)
|
|
236
|
-
|
|
238
|
+
# NOTE TODO: here some of the polys in new_c can be a Product shape instead of a ConvexPolytope
|
|
239
|
+
# -> need to go through the polytopes in new_c and replace the Products with their sub-ConvexPolytopes
|
|
240
|
+
final_polys = []
|
|
241
|
+
for poly in new_c:
|
|
242
|
+
if isinstance(poly, Product):
|
|
243
|
+
final_polys.extend(poly.polytope())
|
|
244
|
+
else:
|
|
245
|
+
final_polys.append(poly)
|
|
246
|
+
# r["unsliced_polytopes"] = set(new_c)
|
|
247
|
+
r["unsliced_polytopes"] = set(final_polys)
|
|
237
248
|
current_nodes = [r]
|
|
238
249
|
for ax in datacube.axes.values():
|
|
239
250
|
next_nodes = []
|
|
@@ -64,6 +64,13 @@ class Polytope:
|
|
|
64
64
|
"""Higher-level API which takes a request and uses it to slice the datacube"""
|
|
65
65
|
logging.info("Starting request for %s ", self.context)
|
|
66
66
|
self.datacube.check_branching_axes(request)
|
|
67
|
+
for polytope in request.polytopes():
|
|
68
|
+
method = polytope.method
|
|
69
|
+
if method == "nearest":
|
|
70
|
+
if self.datacube.nearest_search.get(polytope.axes()[0], None) is None:
|
|
71
|
+
self.datacube.nearest_search[polytope.axes()[0]] = polytope.values
|
|
72
|
+
else:
|
|
73
|
+
self.datacube.nearest_search[polytope.axes()[0]].append(polytope.values[0])
|
|
67
74
|
request_tree = self.engine.extract(self.datacube, request.polytopes())
|
|
68
75
|
logging.info("Created request tree for %s ", self.context)
|
|
69
76
|
self.datacube.get(request_tree, self.context)
|
|
@@ -61,6 +61,42 @@ class ConvexPolytope(Shape):
|
|
|
61
61
|
return [self]
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
class Product(Shape):
|
|
65
|
+
"""Shape that takes two polytopes and 'multiplies' them together to obtain higher-dimensional shape"""
|
|
66
|
+
|
|
67
|
+
def __init__(self, *polytopes, method, value):
|
|
68
|
+
# TODO
|
|
69
|
+
all_axes = []
|
|
70
|
+
for poly in polytopes:
|
|
71
|
+
all_axes.extend(poly.axes())
|
|
72
|
+
self._axes = list(set(all_axes))
|
|
73
|
+
# Check there weren't any duplicates in the polytopes' axes
|
|
74
|
+
assert len(self._axes) == len(all_axes)
|
|
75
|
+
|
|
76
|
+
self._polytopes = []
|
|
77
|
+
for poly in polytopes:
|
|
78
|
+
self._polytopes.extend(poly.polytope())
|
|
79
|
+
|
|
80
|
+
self.is_in_union = False
|
|
81
|
+
self.method = method
|
|
82
|
+
self.values = value
|
|
83
|
+
|
|
84
|
+
self.is_orthogonal = False
|
|
85
|
+
|
|
86
|
+
polys_orthogonal = [poly.is_orthogonal for poly in polytopes]
|
|
87
|
+
if all(polys_orthogonal):
|
|
88
|
+
self.is_orthogonal = True
|
|
89
|
+
|
|
90
|
+
def add_to_union(self):
|
|
91
|
+
self.is_in_union = True
|
|
92
|
+
|
|
93
|
+
def axes(self):
|
|
94
|
+
return self._axes
|
|
95
|
+
|
|
96
|
+
def polytope(self):
|
|
97
|
+
return self._polytopes
|
|
98
|
+
|
|
99
|
+
|
|
64
100
|
# This is the only shape which can slice on axes without a discretizer or interpolator
|
|
65
101
|
class Select(Shape):
|
|
66
102
|
"""Matches several discrete values"""
|
|
@@ -89,19 +125,22 @@ class Point(Shape):
|
|
|
89
125
|
self._axes = axes
|
|
90
126
|
self.values = values
|
|
91
127
|
self.method = method
|
|
92
|
-
|
|
93
|
-
if method == "nearest":
|
|
94
|
-
assert len(self.values) == 1
|
|
95
|
-
for i in range(len(axes)):
|
|
96
|
-
polytope_points = [v[i] for v in self.values]
|
|
97
|
-
self.polytopes.extend(
|
|
98
|
-
[ConvexPolytope([axes[i]], [[point]], self.method, is_orthogonal=True) for point in polytope_points]
|
|
99
|
-
)
|
|
128
|
+
assert len(values) == 1
|
|
100
129
|
|
|
101
130
|
def axes(self):
|
|
102
131
|
return self._axes
|
|
103
132
|
|
|
104
133
|
def polytope(self):
|
|
134
|
+
# TODO: change this to use the Product instead and return a Product here of the two 1D selects
|
|
135
|
+
|
|
136
|
+
polytopes = []
|
|
137
|
+
for point in self.values:
|
|
138
|
+
poly_to_mult = []
|
|
139
|
+
for i in range(len(self._axes)):
|
|
140
|
+
poly_to_mult.append(ConvexPolytope([self._axes[i]], [[point[i]]], self.method, is_orthogonal=True))
|
|
141
|
+
polytopes.append(Product(*poly_to_mult, method=self.method, value=[point]))
|
|
142
|
+
self.polytopes = polytopes
|
|
143
|
+
|
|
105
144
|
return self.polytopes
|
|
106
145
|
|
|
107
146
|
def __repr__(self):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.36"
|
|
@@ -88,6 +88,7 @@ tests/test_octahedral_grid.py
|
|
|
88
88
|
tests/test_override_md5_hash_options.py
|
|
89
89
|
tests/test_point_nearest.py
|
|
90
90
|
tests/test_point_shape.py
|
|
91
|
+
tests/test_point_union.py
|
|
91
92
|
tests/test_profiling_requesttree.py
|
|
92
93
|
tests/test_reduced_ll_grid.py
|
|
93
94
|
tests/test_regular_grid.py
|
|
@@ -73,13 +73,13 @@ class TestSlicingFDBDatacube:
|
|
|
73
73
|
assert leaf.hidden
|
|
74
74
|
assert leaf._parent.hidden
|
|
75
75
|
assert leaf._parent._parent.indexes == [
|
|
76
|
-
3294704,
|
|
77
|
-
3294705,
|
|
78
|
-
3294706,
|
|
79
|
-
3289572,
|
|
80
|
-
3289573,
|
|
81
|
-
3289574,
|
|
82
|
-
3284444,
|
|
83
|
-
3284445,
|
|
84
|
-
3284446,
|
|
76
|
+
[3294704],
|
|
77
|
+
[3294705],
|
|
78
|
+
[3294706],
|
|
79
|
+
[3289572],
|
|
80
|
+
[3289573],
|
|
81
|
+
[3289574],
|
|
82
|
+
[3284444],
|
|
83
|
+
[3284445],
|
|
84
|
+
[3284446],
|
|
85
85
|
]
|
|
@@ -70,7 +70,7 @@ class TestHealpixGrid:
|
|
|
70
70
|
eccodes_result = nearest_points[0][0]["value"]
|
|
71
71
|
|
|
72
72
|
mapper = HealpixGridMapper("base", ["base1", "base2"], 32)
|
|
73
|
-
assert nearest_points[0][0]["index"] == mapper.unmap((lat,), (lon,))
|
|
73
|
+
assert nearest_points[0][0]["index"] == mapper.unmap((lat,), (lon,))[0]
|
|
74
74
|
assert eccodes_lat - tol <= lat
|
|
75
75
|
assert lat <= eccodes_lat + tol
|
|
76
76
|
assert eccodes_lon - tol <= lon
|
|
@@ -102,6 +102,6 @@ class TestMapper:
|
|
|
102
102
|
base_axis = "base"
|
|
103
103
|
resolution = 1280
|
|
104
104
|
octahedral_mapper = OctahedralGridMapper(base_axis, mapped_axes, resolution)
|
|
105
|
-
assert octahedral_mapper.unmap((89.94618771566562,), (0,)) == 0
|
|
106
|
-
assert octahedral_mapper.unmap((0.035149384215604956,), (0,)) == 3299840 - 5136
|
|
107
|
-
assert octahedral_mapper.unmap((-0.035149384215604956,), (0,)) == 3299840
|
|
105
|
+
assert octahedral_mapper.unmap((89.94618771566562,), (0,))[0] == 0
|
|
106
|
+
assert octahedral_mapper.unmap((0.035149384215604956,), (0,))[0] == 3299840 - 5136
|
|
107
|
+
assert octahedral_mapper.unmap((-0.035149384215604956,), (0,))[0] == 3299840
|
|
@@ -4,7 +4,7 @@ import xarray as xr
|
|
|
4
4
|
|
|
5
5
|
from polytope_feature.engine.hullslicer import HullSlicer
|
|
6
6
|
from polytope_feature.polytope import Polytope, Request
|
|
7
|
-
from polytope_feature.shapes import Point, Select
|
|
7
|
+
from polytope_feature.shapes import Point, Select, Union
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class TestSlicing3DXarrayDatacube:
|
|
@@ -30,20 +30,26 @@ class TestSlicing3DXarrayDatacube:
|
|
|
30
30
|
assert result.leaves[0].axis.name == "level"
|
|
31
31
|
|
|
32
32
|
def test_multiple_points(self):
|
|
33
|
-
request = Request(Point(["step", "level"], [[3, 10], [3, 12]]), Select("date", ["2000-01-01"]))
|
|
33
|
+
# request = Request(Point(["step", "level"], [[3, 10], [3, 12]]), Select("date", ["2000-01-01"]))
|
|
34
|
+
request = Request(
|
|
35
|
+
Union(["step", "level"], Point(["step", "level"], [[3, 10]]), Point(["step", "level"], [[3, 12]])),
|
|
36
|
+
Select("date", ["2000-01-01"]),
|
|
37
|
+
)
|
|
34
38
|
result = self.API.retrieve(request)
|
|
35
39
|
result.pprint()
|
|
36
|
-
assert len(result.leaves) ==
|
|
40
|
+
assert len(result.leaves) == 2
|
|
37
41
|
assert result.leaves[0].axis.name == "level"
|
|
38
42
|
|
|
39
43
|
def test_point_surrounding_step(self):
|
|
40
44
|
request = Request(Point(["step", "level"], [[2, 10]], method="surrounding"), Select("date", ["2000-01-01"]))
|
|
41
45
|
result = self.API.retrieve(request)
|
|
46
|
+
result.pprint()
|
|
42
47
|
assert len(result.leaves) == 1
|
|
43
48
|
assert np.shape(result.leaves[0].result[1]) == (1, 2, 3)
|
|
44
49
|
|
|
45
50
|
def test_point_surrounding_exact_step(self):
|
|
46
51
|
request = Request(Point(["step", "level"], [[3, 10]], method="surrounding"), Select("date", ["2000-01-01"]))
|
|
47
52
|
result = self.API.retrieve(request)
|
|
53
|
+
result.pprint()
|
|
48
54
|
assert len(result.leaves) == 1
|
|
49
55
|
assert np.shape(result.leaves[0].result[1]) == (1, 3, 3)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from polytope_feature.engine.hullslicer import HullSlicer
|
|
5
|
+
from polytope_feature.polytope import Polytope, Request
|
|
6
|
+
from polytope_feature.shapes import Point, Select, Span, Union
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestSlicingFDBDatacube:
|
|
10
|
+
def setup_method(self, method):
|
|
11
|
+
# Create a dataarray with 3 labelled axes using different index types
|
|
12
|
+
self.options = {
|
|
13
|
+
"axis_config": [
|
|
14
|
+
{"axis_name": "number", "transformations": [{"name": "type_change", "type": "int"}]},
|
|
15
|
+
{"axis_name": "step", "transformations": [{"name": "type_change", "type": "int"}]},
|
|
16
|
+
{
|
|
17
|
+
"axis_name": "date",
|
|
18
|
+
"transformations": [{"name": "merge", "other_axis": "time", "linkers": ["T", "00"]}],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"axis_name": "values",
|
|
22
|
+
"transformations": [
|
|
23
|
+
{"name": "mapper", "type": "octahedral", "resolution": 1280, "axes": ["latitude", "longitude"]}
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
{"axis_name": "latitude", "transformations": [{"name": "reverse", "is_reverse": True}]},
|
|
27
|
+
{"axis_name": "longitude", "transformations": [{"name": "cyclic", "range": [0, 360]}]},
|
|
28
|
+
],
|
|
29
|
+
"pre_path": {"class": "od", "expver": "0001", "levtype": "sfc", "stream": "oper"},
|
|
30
|
+
"compressed_axes_config": [
|
|
31
|
+
"longitude",
|
|
32
|
+
"latitude",
|
|
33
|
+
"levtype",
|
|
34
|
+
"step",
|
|
35
|
+
"date",
|
|
36
|
+
"domain",
|
|
37
|
+
"expver",
|
|
38
|
+
"param",
|
|
39
|
+
"class",
|
|
40
|
+
"stream",
|
|
41
|
+
"type",
|
|
42
|
+
],
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Testing different shapes
|
|
46
|
+
@pytest.mark.fdb
|
|
47
|
+
def test_fdb_datacube(self):
|
|
48
|
+
import pygribjump as gj
|
|
49
|
+
|
|
50
|
+
request = Request(
|
|
51
|
+
Select("step", [0]),
|
|
52
|
+
Select("levtype", ["sfc"]),
|
|
53
|
+
Span("date", pd.Timestamp("20230625T120000"), pd.Timestamp("20230626T120000")),
|
|
54
|
+
Select("domain", ["g"]),
|
|
55
|
+
Select("expver", ["0001"]),
|
|
56
|
+
Select("param", ["167"]),
|
|
57
|
+
Select("class", ["od"]),
|
|
58
|
+
Select("stream", ["oper"]),
|
|
59
|
+
Select("type", ["an"]),
|
|
60
|
+
Union(
|
|
61
|
+
["latitude", "longitude"],
|
|
62
|
+
Point(["latitude", "longitude"], [[20, 20]], method="nearest"),
|
|
63
|
+
Point(["latitude", "longitude"], [[0, 0]], method="nearest"),
|
|
64
|
+
Point(["latitude", "longitude"], [[0, 20]], method="nearest"),
|
|
65
|
+
Point(["latitude", "longitude"], [[25, 30]], method="nearest"),
|
|
66
|
+
Point(["latitude", "longitude"], [[-30, 90]], method="nearest"),
|
|
67
|
+
Point(["latitude", "longitude"], [[-60, -30]], method="nearest"),
|
|
68
|
+
Point(["latitude", "longitude"], [[-15, -45]], method="nearest"),
|
|
69
|
+
Point(["latitude", "longitude"], [[20, 0]], method="nearest"),
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
self.fdbdatacube = gj.GribJump()
|
|
74
|
+
self.slicer = HullSlicer()
|
|
75
|
+
self.API = Polytope(
|
|
76
|
+
datacube=self.fdbdatacube,
|
|
77
|
+
engine=self.slicer,
|
|
78
|
+
options=self.options,
|
|
79
|
+
)
|
|
80
|
+
result = self.API.retrieve(request)
|
|
81
|
+
result.pprint()
|
|
82
|
+
assert len(result.leaves) == 8
|
|
83
|
+
|
|
84
|
+
@pytest.mark.fdb
|
|
85
|
+
def test_fdb_datacube_surrounding(self):
|
|
86
|
+
import pygribjump as gj
|
|
87
|
+
|
|
88
|
+
request = Request(
|
|
89
|
+
Select("step", [0]),
|
|
90
|
+
Select("levtype", ["sfc"]),
|
|
91
|
+
Span("date", pd.Timestamp("20230625T120000"), pd.Timestamp("20230626T120000")),
|
|
92
|
+
Select("domain", ["g"]),
|
|
93
|
+
Select("expver", ["0001"]),
|
|
94
|
+
Select("param", ["167"]),
|
|
95
|
+
Select("class", ["od"]),
|
|
96
|
+
Select("stream", ["oper"]),
|
|
97
|
+
Select("type", ["an"]),
|
|
98
|
+
Union(
|
|
99
|
+
["latitude", "longitude"],
|
|
100
|
+
Point(["latitude", "longitude"], [[25, 30]], method="surrounding"),
|
|
101
|
+
Point(["latitude", "longitude"], [[-15, -45]], method="surrounding"),
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
self.fdbdatacube = gj.GribJump()
|
|
106
|
+
self.slicer = HullSlicer()
|
|
107
|
+
self.API = Polytope(
|
|
108
|
+
datacube=self.fdbdatacube,
|
|
109
|
+
engine=self.slicer,
|
|
110
|
+
options=self.options,
|
|
111
|
+
)
|
|
112
|
+
result = self.API.retrieve(request)
|
|
113
|
+
result.pprint()
|
|
114
|
+
assert len(result.leaves) == 4
|
|
115
|
+
tot_leaves = 0
|
|
116
|
+
for leaf in result.leaves:
|
|
117
|
+
tot_leaves += len(leaf.result)
|
|
118
|
+
assert tot_leaves == 9
|
|
119
|
+
|
|
120
|
+
# @pytest.mark.fdb
|
|
121
|
+
# def test_fdb_datacube_mix_methods(self):
|
|
122
|
+
# import pygribjump as gj
|
|
123
|
+
|
|
124
|
+
# request = Request(
|
|
125
|
+
# Select("step", [0]),
|
|
126
|
+
# Select("levtype", ["sfc"]),
|
|
127
|
+
# Span("date", pd.Timestamp("20230625T120000"), pd.Timestamp("20230626T120000")),
|
|
128
|
+
# Select("domain", ["g"]),
|
|
129
|
+
# Select("expver", ["0001"]),
|
|
130
|
+
# Select("param", ["167"]),
|
|
131
|
+
# Select("class", ["od"]),
|
|
132
|
+
# Select("stream", ["oper"]),
|
|
133
|
+
# Select("type", ["an"]),
|
|
134
|
+
# Union(["latitude", "longitude"],
|
|
135
|
+
# Point(["latitude", "longitude"], [[25, 30]], method="nearest"),
|
|
136
|
+
# Point(["latitude", "longitude"], [[-15, -45]], method="surrounding"))
|
|
137
|
+
# )
|
|
138
|
+
|
|
139
|
+
# self.fdbdatacube = gj.GribJump()
|
|
140
|
+
# self.slicer = HullSlicer()
|
|
141
|
+
# self.API = Polytope(
|
|
142
|
+
# datacube=self.fdbdatacube,
|
|
143
|
+
# engine=self.slicer,
|
|
144
|
+
# options=self.options,
|
|
145
|
+
# )
|
|
146
|
+
# result = self.API.retrieve(request)
|
|
147
|
+
# result.pprint()
|
|
148
|
+
# assert len(result.leaves) == 6
|
|
@@ -116,7 +116,7 @@ class TestRegularGrid:
|
|
|
116
116
|
eccodes_lats.append(eccodes_lat)
|
|
117
117
|
|
|
118
118
|
mapper = RegularGridMapper("base", ["base1", "base2"], 30)
|
|
119
|
-
assert nearest_points[121][0]["index"] == mapper.unmap((lat,), (lon,))
|
|
119
|
+
assert nearest_points[121][0]["index"] == mapper.unmap((lat,), (lon,))[0]
|
|
120
120
|
|
|
121
121
|
assert eccodes_lat - tol <= lat
|
|
122
122
|
assert lat <= eccodes_lat + tol
|
|
@@ -10,6 +10,8 @@ from polytope_feature.shapes import Box, Select
|
|
|
10
10
|
class TestSlicingFDBDatacube:
|
|
11
11
|
def setup_method(self, method):
|
|
12
12
|
# Create a dataarray with 3 labelled axes using different index types
|
|
13
|
+
# TODO: This uses the wrong fdb/schema/data so the hash for the grid is wrong
|
|
14
|
+
# BUT the validation against eccodes is OK because the GRIB file is the same grid as Polytope returns
|
|
13
15
|
self.options = {
|
|
14
16
|
"axis_config": [
|
|
15
17
|
{"axis_name": "step", "transformations": [{"name": "type_change", "type": "int"}]},
|
|
@@ -25,6 +27,7 @@ class TestSlicingFDBDatacube:
|
|
|
25
27
|
"type": "reduced_gaussian",
|
|
26
28
|
"resolution": 320,
|
|
27
29
|
"axes": ["latitude", "longitude"],
|
|
30
|
+
"md5_hash": "158db321ae8e773681eeb40e0a3d350f",
|
|
28
31
|
}
|
|
29
32
|
],
|
|
30
33
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.34"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/__init__.py
RENAMED
|
File without changes
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/datacube.py
RENAMED
|
File without changes
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/mock.py
RENAMED
|
File without changes
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/backends/xarray.py
RENAMED
|
File without changes
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/datacube_axis.py
RENAMED
|
File without changes
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/index_tree_pb2.py
RENAMED
|
File without changes
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_feature/datacube/tensor_index_tree.py
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
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/polytope_python.egg-info/dependency_links.txt
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
|
{polytope_python-1.0.34 → polytope_python-1.0.36}/tests/test_cyclic_axis_over_negative_vals.py
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
|
|
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
|