polytope-python 1.0.5__tar.gz → 1.0.7__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.5/polytope_python.egg-info → polytope-python-1.0.7}/PKG-INFO +1 -1
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/backends/datacube.py +5 -3
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/backends/fdb.py +9 -10
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/backends/mock.py +3 -1
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/backends/xarray.py +5 -3
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/tensor_index_tree.py +8 -3
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/datacube_mappers.py +1 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/mapper_types/healpix.py +5 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +5 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/mapper_types/local_regular.py +6 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/mapper_types/octahedral.py +7 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/mapper_types/reduced_ll.py +5 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/mapper_types/regular.py +5 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_merger/datacube_merger.py +0 -1
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/engine/hullslicer.py +27 -25
- polytope-python-1.0.7/polytope/options.py +78 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/polytope.py +8 -2
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/utility/exceptions.py +8 -4
- polytope-python-1.0.7/polytope/version.py +1 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7/polytope_python.egg-info}/PKG-INFO +1 -1
- polytope-python-1.0.5/polytope/options.py +0 -67
- polytope-python-1.0.5/polytope/version.py +0 -1
- {polytope-python-1.0.5 → polytope-python-1.0.7}/LICENSE +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/MANIFEST.in +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/backends/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/datacube_axis.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/index_tree_pb2.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_cyclic/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_cyclic/datacube_cyclic.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_mappers/mapper_types/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_merger/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_reverse/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_reverse/datacube_reverse.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_transformations.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_type_change/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/transformations/datacube_type_change/datacube_type_change.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/datacube/tree_encoding.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/engine/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/engine/engine.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/shapes.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/utility/__init__.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/utility/combinatorics.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/utility/geometry.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/utility/list_tools.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope/utility/profiling.py +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope_python.egg-info/SOURCES.txt +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope_python.egg-info/dependency_links.txt +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope_python.egg-info/not-zip-safe +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope_python.egg-info/requires.txt +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/polytope_python.egg-info/top_level.txt +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/pyproject.toml +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/requirements.txt +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/setup.cfg +0 -0
- {polytope-python-1.0.5 → polytope-python-1.0.7}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any, Dict
|
|
4
4
|
|
|
5
5
|
from ...utility.combinatorics import validate_axes
|
|
6
6
|
from ..datacube_axis import DatacubeAxis
|
|
@@ -31,9 +31,10 @@ class Datacube(ABC):
|
|
|
31
31
|
self.merged_axes = []
|
|
32
32
|
self.unwanted_path = {}
|
|
33
33
|
self.compressed_axes = compressed_axes_options
|
|
34
|
+
self.grid_md5_hash = None
|
|
34
35
|
|
|
35
36
|
@abstractmethod
|
|
36
|
-
def get(self, requests: TensorIndexTree) -> Any:
|
|
37
|
+
def get(self, requests: TensorIndexTree, context: Dict) -> Any:
|
|
37
38
|
"""Return data given a set of request trees"""
|
|
38
39
|
|
|
39
40
|
@property
|
|
@@ -69,6 +70,7 @@ class Datacube(ABC):
|
|
|
69
70
|
# TODO: do we use this?? This shouldn't work for a disk in lat/lon on a octahedral or other grid??
|
|
70
71
|
for compressed_grid_axis in transformation.compressed_grid_axes:
|
|
71
72
|
self.compressed_grid_axes.append(compressed_grid_axis)
|
|
73
|
+
self.grid_md5_hash = transformation.md5_hash
|
|
72
74
|
if len(final_axis_names) > 1:
|
|
73
75
|
self.coupled_axes.append(final_axis_names)
|
|
74
76
|
for axis in final_axis_names:
|
|
@@ -128,7 +130,7 @@ class Datacube(ABC):
|
|
|
128
130
|
indexes = axis.find_indexes(path, self)
|
|
129
131
|
idx_between = axis.find_indices_between(indexes, lower, upper, self, method)
|
|
130
132
|
|
|
131
|
-
logging.
|
|
133
|
+
logging.debug(f"For axis {axis.name} between {lower} and {upper}, found indices {idx_between}")
|
|
132
134
|
|
|
133
135
|
return idx_between
|
|
134
136
|
|
|
@@ -77,7 +77,10 @@ class FDBDatacube(Datacube):
|
|
|
77
77
|
for axis_name in axes_to_remove:
|
|
78
78
|
self._axes.pop(axis_name, None)
|
|
79
79
|
|
|
80
|
-
def get(self, requests: TensorIndexTree):
|
|
80
|
+
def get(self, requests: TensorIndexTree, context=None):
|
|
81
|
+
if context is None:
|
|
82
|
+
context = {}
|
|
83
|
+
requests.pprint()
|
|
81
84
|
if len(requests.children) == 0:
|
|
82
85
|
return requests
|
|
83
86
|
fdb_requests = []
|
|
@@ -103,11 +106,11 @@ class FDBDatacube(Datacube):
|
|
|
103
106
|
uncompressed_request = {}
|
|
104
107
|
for i, key in enumerate(compressed_request[0].keys()):
|
|
105
108
|
uncompressed_request[key] = combi[i]
|
|
106
|
-
complete_uncompressed_request = (uncompressed_request, compressed_request[1])
|
|
109
|
+
complete_uncompressed_request = (uncompressed_request, compressed_request[1], self.grid_md5_hash)
|
|
107
110
|
complete_list_complete_uncompressed_requests.append(complete_uncompressed_request)
|
|
108
111
|
complete_fdb_decoding_info.append(fdb_requests_decoding_info[j])
|
|
109
112
|
logging.debug("The requests we give GribJump are: %s", complete_list_complete_uncompressed_requests)
|
|
110
|
-
output_values = self.gj.extract(complete_list_complete_uncompressed_requests)
|
|
113
|
+
output_values = self.gj.extract(complete_list_complete_uncompressed_requests, context)
|
|
111
114
|
logging.debug("GribJump outputs: %s", output_values)
|
|
112
115
|
self.assign_fdb_output_to_nodes(output_values, complete_fdb_decoding_info)
|
|
113
116
|
|
|
@@ -123,7 +126,7 @@ class FDBDatacube(Datacube):
|
|
|
123
126
|
|
|
124
127
|
# First when request node is root, go to its children
|
|
125
128
|
if requests.axis.name == "root":
|
|
126
|
-
logging.
|
|
129
|
+
logging.debug("Looking for data for the tree: %s", [leaf.flatten() for leaf in requests.leaves])
|
|
127
130
|
|
|
128
131
|
for c in requests.children:
|
|
129
132
|
self.get_fdb_requests(c, fdb_requests, fdb_requests_decoding_info)
|
|
@@ -160,8 +163,8 @@ class FDBDatacube(Datacube):
|
|
|
160
163
|
new_current_start_idx = []
|
|
161
164
|
for j, idx in enumerate(sub_lat_idxs):
|
|
162
165
|
if idx not in seen_indices:
|
|
163
|
-
#
|
|
164
|
-
#
|
|
166
|
+
# NOTE: need to remove it from the values in the corresponding tree node
|
|
167
|
+
# NOTE: need to read just the range we give to gj
|
|
165
168
|
original_fdb_node_range_vals.append(actual_fdb_node[0].values[j])
|
|
166
169
|
seen_indices.add(idx)
|
|
167
170
|
new_current_start_idx.append(idx)
|
|
@@ -186,8 +189,6 @@ class FDBDatacube(Datacube):
|
|
|
186
189
|
|
|
187
190
|
second_ax = requests.children[0].children[0].axis
|
|
188
191
|
|
|
189
|
-
# TODO: actually, here we should not remap the nearest_pts, we should instead unmap the
|
|
190
|
-
# found_latlon_pts and then remap them later once we have compared found_latlon_pts and nearest_pts
|
|
191
192
|
nearest_pts = [
|
|
192
193
|
[lat_val, second_ax._remap_val_to_axis_range(lon_val)]
|
|
193
194
|
for (lat_val, lon_val) in zip(
|
|
@@ -324,8 +325,6 @@ class FDBDatacube(Datacube):
|
|
|
324
325
|
request_ranges_with_idx = list(enumerate(interm_request_ranges))
|
|
325
326
|
sorted_list = sorted(request_ranges_with_idx, key=lambda x: x[1][0])
|
|
326
327
|
original_indices, sorted_request_ranges = zip(*sorted_list)
|
|
327
|
-
logging.debug("We sorted the request ranges into: %s", sorted_request_ranges)
|
|
328
|
-
logging.debug("The sorted and unique leaf node ranges are: %s", new_fdb_node_ranges)
|
|
329
328
|
return (original_indices, sorted_request_ranges, new_fdb_node_ranges)
|
|
330
329
|
|
|
331
330
|
def datacube_natural_indexes(self, axis, subarray):
|
|
@@ -24,10 +24,12 @@ class MockDatacube(Datacube):
|
|
|
24
24
|
self.stride[k] = stride_cumulative
|
|
25
25
|
stride_cumulative *= self.dimensions[k]
|
|
26
26
|
|
|
27
|
-
def get(self, requests: TensorIndexTree):
|
|
27
|
+
def get(self, requests: TensorIndexTree, context=None):
|
|
28
28
|
# Takes in a datacube and verifies the leaves of the tree are complete
|
|
29
29
|
# (ie it found values for all datacube axis)
|
|
30
30
|
|
|
31
|
+
if context is None:
|
|
32
|
+
context = {}
|
|
31
33
|
for r in requests.leaves:
|
|
32
34
|
path = r.flatten()
|
|
33
35
|
if len(path.items()) == len(self.dimensions.items()):
|
|
@@ -50,12 +50,14 @@ class XArrayDatacube(Datacube):
|
|
|
50
50
|
val = self._axes[name].type
|
|
51
51
|
self._check_and_add_axes(options, name, val)
|
|
52
52
|
|
|
53
|
-
def get(self, requests, leaf_path=None, axis_counter=0):
|
|
53
|
+
def get(self, requests, context=None, leaf_path=None, axis_counter=0):
|
|
54
|
+
if context is None:
|
|
55
|
+
context = {}
|
|
54
56
|
if leaf_path is None:
|
|
55
57
|
leaf_path = {}
|
|
56
58
|
if requests.axis.name == "root":
|
|
57
59
|
for c in requests.children:
|
|
58
|
-
self.get(c, leaf_path, axis_counter + 1)
|
|
60
|
+
self.get(c, context, leaf_path, axis_counter + 1)
|
|
59
61
|
else:
|
|
60
62
|
key_value_path = {requests.axis.name: requests.values}
|
|
61
63
|
ax = requests.axis
|
|
@@ -66,7 +68,7 @@ class XArrayDatacube(Datacube):
|
|
|
66
68
|
if len(requests.children) != 0:
|
|
67
69
|
# We are not a leaf and we loop over
|
|
68
70
|
for c in requests.children:
|
|
69
|
-
self.get(c, leaf_path, axis_counter + 1)
|
|
71
|
+
self.get(c, context, leaf_path, axis_counter + 1)
|
|
70
72
|
else:
|
|
71
73
|
if self.axis_counter != axis_counter:
|
|
72
74
|
requests.remove_branch()
|
|
@@ -81,8 +81,12 @@ class TensorIndexTree(object):
|
|
|
81
81
|
for i in range(len(other.values)):
|
|
82
82
|
other_val = other.values[i]
|
|
83
83
|
self_val = self.values[i]
|
|
84
|
-
if
|
|
85
|
-
|
|
84
|
+
if self.axis.can_round:
|
|
85
|
+
if abs(other_val - self_val) > 2 * max(other.axis.tol, self.axis.tol):
|
|
86
|
+
return False
|
|
87
|
+
else:
|
|
88
|
+
if other_val != self_val:
|
|
89
|
+
return False
|
|
86
90
|
return True
|
|
87
91
|
|
|
88
92
|
def __lt__(self, other):
|
|
@@ -101,6 +105,7 @@ class TensorIndexTree(object):
|
|
|
101
105
|
def add_value(self, value):
|
|
102
106
|
new_values = list(self.values)
|
|
103
107
|
new_values.append(value)
|
|
108
|
+
new_values.sort()
|
|
104
109
|
self.values = tuple(new_values)
|
|
105
110
|
|
|
106
111
|
def create_child(self, axis, value, next_nodes):
|
|
@@ -217,7 +222,7 @@ class TensorIndexTree(object):
|
|
|
217
222
|
def get_ancestors(self):
|
|
218
223
|
ancestors = []
|
|
219
224
|
current_node = self
|
|
220
|
-
while current_node.axis !=
|
|
225
|
+
while current_node.axis.name != "root":
|
|
221
226
|
ancestors.append(current_node)
|
|
222
227
|
current_node = current_node.parent
|
|
223
228
|
return ancestors[::-1]
|
|
@@ -20,6 +20,7 @@ class DatacubeMapper(DatacubeAxisTransformation):
|
|
|
20
20
|
self._final_mapped_axes = self._final_transformation._mapped_axes
|
|
21
21
|
self._axis_reversed = self._final_transformation._axis_reversed
|
|
22
22
|
self.compressed_grid_axes = self._final_transformation.compressed_grid_axes
|
|
23
|
+
self.md5_hash = self._final_transformation.md5_hash
|
|
23
24
|
|
|
24
25
|
def generate_final_transformation(self):
|
|
25
26
|
map_type = _type_to_datacube_mapper_lookup[self.grid_type]
|
|
@@ -13,6 +13,7 @@ class HealpixGridMapper(DatacubeMapper):
|
|
|
13
13
|
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
14
14
|
self._first_axis_vals = self.first_axis_vals()
|
|
15
15
|
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
16
|
+
self.md5_hash = md5_hash.get(resolution, None)
|
|
16
17
|
|
|
17
18
|
def first_axis_vals(self):
|
|
18
19
|
rad2deg = 180 / math.pi
|
|
@@ -133,3 +134,7 @@ class HealpixGridMapper(DatacubeMapper):
|
|
|
133
134
|
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
134
135
|
healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx)
|
|
135
136
|
return healpix_index
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# md5 grid hash in form {resolution : hash}
|
|
140
|
+
md5_hash = {}
|
|
@@ -17,6 +17,7 @@ class NestedHealpixGridMapper(DatacubeMapper):
|
|
|
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.md5_hash = md5_hash.get(resolution, None)
|
|
20
21
|
|
|
21
22
|
def first_axis_vals(self):
|
|
22
23
|
rad2deg = 180 / math.pi
|
|
@@ -211,3 +212,7 @@ class NestedHealpixGridMapper(DatacubeMapper):
|
|
|
211
212
|
|
|
212
213
|
def int_sqrt(self, i):
|
|
213
214
|
return int(math.sqrt(i + 0.5))
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# md5 grid hash in form {resolution : hash}
|
|
218
|
+
md5_hash = {}
|
|
@@ -15,9 +15,11 @@ class LocalRegularGridMapper(DatacubeMapper):
|
|
|
15
15
|
if not isinstance(resolution, list):
|
|
16
16
|
self.first_resolution = resolution
|
|
17
17
|
self.second_resolution = resolution
|
|
18
|
+
self.md5_hash = md5_hash.get(resolution, None)
|
|
18
19
|
else:
|
|
19
20
|
self.first_resolution = resolution[0]
|
|
20
21
|
self.second_resolution = resolution[1]
|
|
22
|
+
self.md5_hash = md5_hash.get(tuple(resolution), None)
|
|
21
23
|
self._first_deg_increment = (local_area[1] - local_area[0]) / self.first_resolution
|
|
22
24
|
self._second_deg_increment = (local_area[3] - local_area[2]) / self.second_resolution
|
|
23
25
|
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
@@ -68,3 +70,7 @@ class LocalRegularGridMapper(DatacubeMapper):
|
|
|
68
70
|
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
69
71
|
final_index = self.axes_idx_to_regular_idx(first_idx, second_idx)
|
|
70
72
|
return final_index
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# md5 grid hash in form {resolution : hash}
|
|
76
|
+
md5_hash = {}
|
|
@@ -15,6 +15,7 @@ class OctahedralGridMapper(DatacubeMapper):
|
|
|
15
15
|
self._second_axis_spacing = {}
|
|
16
16
|
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
17
17
|
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
18
|
+
self.md5_hash = md5_hash.get(resolution, None)
|
|
18
19
|
|
|
19
20
|
def gauss_first_guess(self):
|
|
20
21
|
i = 0
|
|
@@ -2750,3 +2751,9 @@ class OctahedralGridMapper(DatacubeMapper):
|
|
|
2750
2751
|
(first_idx, second_idx) = self.find_second_axis_idx(first_val, second_val)
|
|
2751
2752
|
octahedral_index = self.axes_idx_to_octahedral_idx(first_idx, second_idx)
|
|
2752
2753
|
return octahedral_index
|
|
2754
|
+
|
|
2755
|
+
|
|
2756
|
+
# md5 grid hash in form {resolution : hash}
|
|
2757
|
+
md5_hash = {
|
|
2758
|
+
1280: "158db321ae8e773681eeb40e0a3d350f",
|
|
2759
|
+
}
|
|
@@ -12,6 +12,7 @@ class ReducedLatLonMapper(DatacubeMapper):
|
|
|
12
12
|
self._axis_reversed = {mapped_axes[0]: False, mapped_axes[1]: False}
|
|
13
13
|
self._first_axis_vals = self.first_axis_vals()
|
|
14
14
|
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
15
|
+
self.md5_hash = md5_hash.get(resolution, None)
|
|
15
16
|
|
|
16
17
|
def first_axis_vals(self):
|
|
17
18
|
resolution = 180 / (self._resolution - 1)
|
|
@@ -1504,3 +1505,7 @@ class ReducedLatLonMapper(DatacubeMapper):
|
|
|
1504
1505
|
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
1505
1506
|
reduced_ll_index = self.axes_idx_to_reduced_ll_idx(first_idx, second_idx)
|
|
1506
1507
|
return reduced_ll_index
|
|
1508
|
+
|
|
1509
|
+
|
|
1510
|
+
# md5 grid hash in form {resolution : hash}
|
|
1511
|
+
md5_hash = {}
|
|
@@ -13,6 +13,7 @@ class RegularGridMapper(DatacubeMapper):
|
|
|
13
13
|
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
14
14
|
self._first_axis_vals = self.first_axis_vals()
|
|
15
15
|
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
16
|
+
self.md5_hash = md5_hash.get(resolution, None)
|
|
16
17
|
|
|
17
18
|
def first_axis_vals(self):
|
|
18
19
|
first_ax_vals = [90 - i * self.deg_increment for i in range(2 * self._resolution)]
|
|
@@ -56,3 +57,7 @@ class RegularGridMapper(DatacubeMapper):
|
|
|
56
57
|
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
57
58
|
final_index = self.axes_idx_to_regular_idx(first_idx, second_idx)
|
|
58
59
|
return final_index
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# md5 grid hash in form {resolution : hash}
|
|
63
|
+
md5_hash = {}
|
|
@@ -93,6 +93,5 @@ class DatacubeAxisMerger(DatacubeAxisTransformation):
|
|
|
93
93
|
if node.axis.name == self._first_axis:
|
|
94
94
|
(new_first_vals, new_second_vals) = self.unmerge(node.values)
|
|
95
95
|
node.values = new_first_vals
|
|
96
|
-
# TODO: actually need to give the second axis of the transformation to get the interm axis
|
|
97
96
|
interm_node = node.add_node_layer_after(self._second_axis, new_second_vals)
|
|
98
97
|
return (interm_node, unwanted_path)
|
|
@@ -109,11 +109,8 @@ class HullSlicer(Engine):
|
|
|
109
109
|
return remapped_val
|
|
110
110
|
|
|
111
111
|
def _build_sliceable_child(self, polytope, ax, node, datacube, values, next_nodes, slice_axis_idx):
|
|
112
|
-
if len(values) == 0:
|
|
113
|
-
node.remove_branch()
|
|
114
|
-
|
|
115
112
|
for i, value in enumerate(values):
|
|
116
|
-
if i == 0:
|
|
113
|
+
if i == 0 or ax.name not in self.compressed_axes:
|
|
117
114
|
fvalue = ax.to_float(value)
|
|
118
115
|
new_polytope = slice(polytope, ax.name, fvalue, slice_axis_idx)
|
|
119
116
|
remapped_val = self.remap_values(ax, value)
|
|
@@ -124,38 +121,41 @@ class HullSlicer(Engine):
|
|
|
124
121
|
child["unsliced_polytopes"].add(new_polytope)
|
|
125
122
|
next_nodes.append(child)
|
|
126
123
|
else:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
new_polytope = slice(polytope, ax.name, fvalue, slice_axis_idx)
|
|
130
|
-
remapped_val = self.remap_values(ax, value)
|
|
131
|
-
(child, next_nodes) = node.create_child(ax, remapped_val, next_nodes)
|
|
132
|
-
child["unsliced_polytopes"] = copy(node["unsliced_polytopes"])
|
|
133
|
-
child["unsliced_polytopes"].remove(polytope)
|
|
134
|
-
if new_polytope is not None:
|
|
135
|
-
child["unsliced_polytopes"].add(new_polytope)
|
|
136
|
-
next_nodes.append(child)
|
|
137
|
-
else:
|
|
138
|
-
remapped_val = self.remap_values(ax, value)
|
|
139
|
-
child.add_value(remapped_val)
|
|
124
|
+
remapped_val = self.remap_values(ax, value)
|
|
125
|
+
child.add_value(remapped_val)
|
|
140
126
|
|
|
141
127
|
def _build_branch(self, ax, node, datacube, next_nodes):
|
|
142
128
|
if ax.name not in self.compressed_axes:
|
|
129
|
+
parent_node = node.parent
|
|
130
|
+
right_unsliced_polytopes = []
|
|
143
131
|
for polytope in node["unsliced_polytopes"]:
|
|
144
132
|
if ax.name in polytope._axes:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
133
|
+
right_unsliced_polytopes.append(polytope)
|
|
134
|
+
for i, polytope in enumerate(right_unsliced_polytopes):
|
|
135
|
+
node._parent = parent_node
|
|
136
|
+
lower, upper, slice_axis_idx = polytope.extents(ax.name)
|
|
137
|
+
# here, first check if the axis is an unsliceable axis and directly build node if it is
|
|
138
|
+
# NOTE: we should have already created the ax_is_unsliceable cache before
|
|
139
|
+
if self.ax_is_unsliceable[ax.name]:
|
|
140
|
+
self._build_unsliceable_child(polytope, ax, node, datacube, [lower], next_nodes, slice_axis_idx)
|
|
141
|
+
else:
|
|
142
|
+
values = self.find_values_between(polytope, ax, node, datacube, lower, upper)
|
|
143
|
+
# NOTE: need to only remove the branches if the values are empty,
|
|
144
|
+
# but only if there are no other possible children left in the tree that
|
|
145
|
+
# we can append and if somehow this happens before and we need to remove, then what do we do??
|
|
146
|
+
if i == len(right_unsliced_polytopes) - 1:
|
|
147
|
+
# we have iterated all polytopes and we can now remove the node if we need to
|
|
148
|
+
if len(values) == 0 and len(node.children) == 0:
|
|
149
|
+
node.remove_branch()
|
|
150
|
+
self._build_sliceable_child(polytope, ax, node, datacube, values, next_nodes, slice_axis_idx)
|
|
153
151
|
else:
|
|
154
152
|
all_values = []
|
|
155
153
|
all_lowers = []
|
|
156
154
|
first_polytope = False
|
|
157
155
|
first_slice_axis_idx = False
|
|
156
|
+
parent_node = node.parent
|
|
158
157
|
for polytope in node["unsliced_polytopes"]:
|
|
158
|
+
node._parent = parent_node
|
|
159
159
|
if ax.name in polytope._axes:
|
|
160
160
|
# keep track of the first polytope defined on the given axis
|
|
161
161
|
if not first_polytope:
|
|
@@ -173,6 +173,8 @@ class HullSlicer(Engine):
|
|
|
173
173
|
first_polytope, ax, node, datacube, all_lowers, next_nodes, first_slice_axis_idx
|
|
174
174
|
)
|
|
175
175
|
else:
|
|
176
|
+
if len(all_values) == 0:
|
|
177
|
+
node.remove_branch()
|
|
176
178
|
self._build_sliceable_child(
|
|
177
179
|
first_polytope, ax, node, datacube, all_values, next_nodes, first_slice_axis_idx
|
|
178
180
|
)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from abc import ABC
|
|
3
|
+
from typing import Dict, List, Literal, Optional, Union
|
|
4
|
+
|
|
5
|
+
from conflator import ConfigModel, Conflator
|
|
6
|
+
from pydantic import ConfigDict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TransformationConfig(ConfigModel):
|
|
10
|
+
model_config = ConfigDict(extra="forbid")
|
|
11
|
+
name: str = ""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CyclicConfig(TransformationConfig):
|
|
15
|
+
name: Literal["cyclic"]
|
|
16
|
+
range: List[float] = [0]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MapperConfig(TransformationConfig):
|
|
20
|
+
name: Literal["mapper"]
|
|
21
|
+
type: str = ""
|
|
22
|
+
resolution: Union[int, List[int]] = 0
|
|
23
|
+
axes: List[str] = [""]
|
|
24
|
+
local: Optional[List[float]] = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ReverseConfig(TransformationConfig):
|
|
28
|
+
name: Literal["reverse"]
|
|
29
|
+
is_reverse: bool = False
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TypeChangeConfig(TransformationConfig):
|
|
33
|
+
name: Literal["type_change"]
|
|
34
|
+
type: str = "int"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class MergeConfig(TransformationConfig):
|
|
38
|
+
name: Literal["merge"]
|
|
39
|
+
other_axis: str = ""
|
|
40
|
+
linkers: List[str] = [""]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
action_subclasses_union = Union[CyclicConfig, MapperConfig, ReverseConfig, TypeChangeConfig, MergeConfig]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AxisConfig(ConfigModel):
|
|
47
|
+
axis_name: str = ""
|
|
48
|
+
transformations: list[action_subclasses_union]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
path_subclasses_union = Union[str, int, float]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class GribJumpAxesConfig(ConfigModel):
|
|
55
|
+
axis_name: str = ""
|
|
56
|
+
values: List[str] = [""]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Config(ConfigModel):
|
|
60
|
+
axis_config: List[AxisConfig] = []
|
|
61
|
+
compressed_axes_config: List[str] = [""]
|
|
62
|
+
pre_path: Optional[Dict[str, path_subclasses_union]] = {}
|
|
63
|
+
alternative_axes: List[GribJumpAxesConfig] = []
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class PolytopeOptions(ABC):
|
|
67
|
+
@staticmethod
|
|
68
|
+
def get_polytope_options(options):
|
|
69
|
+
parser = argparse.ArgumentParser(allow_abbrev=False)
|
|
70
|
+
conflator = Conflator(app_name="polytope", model=Config, cli=False, argparser=parser, **options)
|
|
71
|
+
config_options = conflator.load()
|
|
72
|
+
|
|
73
|
+
axis_config = config_options.axis_config
|
|
74
|
+
compressed_axes_config = config_options.compressed_axes_config
|
|
75
|
+
pre_path = config_options.pre_path
|
|
76
|
+
alternative_axes = config_options.alternative_axes
|
|
77
|
+
|
|
78
|
+
return (axis_config, compressed_axes_config, pre_path, alternative_axes)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from typing import List
|
|
2
3
|
|
|
3
4
|
from .options import PolytopeOptions
|
|
@@ -55,9 +56,14 @@ class Polytope:
|
|
|
55
56
|
"""Low-level API which takes a polytope geometry object and uses it to slice the datacube"""
|
|
56
57
|
return self.engine.extract(self.datacube, polytopes)
|
|
57
58
|
|
|
58
|
-
def retrieve(self, request: Request, method="standard"):
|
|
59
|
+
def retrieve(self, request: Request, method="standard", context=None):
|
|
59
60
|
"""Higher-level API which takes a request and uses it to slice the datacube"""
|
|
61
|
+
if context is None:
|
|
62
|
+
context = {}
|
|
63
|
+
logging.info("Starting request for %s ", context)
|
|
60
64
|
self.datacube.check_branching_axes(request)
|
|
61
65
|
request_tree = self.engine.extract(self.datacube, request.polytopes())
|
|
62
|
-
|
|
66
|
+
logging.info("Created request tree for %s ", context)
|
|
67
|
+
self.datacube.get(request_tree, context)
|
|
68
|
+
logging.info("Retrieved data for %s ", context)
|
|
63
69
|
return request_tree
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
class
|
|
1
|
+
class PolytopeError(Exception):
|
|
2
|
+
pass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AxisOverdefinedError(PolytopeError, KeyError):
|
|
2
6
|
def __init__(self, axis):
|
|
3
7
|
self.axis = axis
|
|
4
8
|
self.message = (
|
|
@@ -7,19 +11,19 @@ class AxisOverdefinedError(KeyError):
|
|
|
7
11
|
)
|
|
8
12
|
|
|
9
13
|
|
|
10
|
-
class AxisUnderdefinedError(KeyError):
|
|
14
|
+
class AxisUnderdefinedError(PolytopeError, KeyError):
|
|
11
15
|
def __init__(self, axis):
|
|
12
16
|
self.axis = axis
|
|
13
17
|
self.message = f"Axis {axis} is underdefined. It does not appear in any input polytope."
|
|
14
18
|
|
|
15
19
|
|
|
16
|
-
class AxisNotFoundError(KeyError):
|
|
20
|
+
class AxisNotFoundError(PolytopeError, KeyError):
|
|
17
21
|
def __init__(self, axis):
|
|
18
22
|
self.axis = axis
|
|
19
23
|
self.message = f"Axis {axis} does not exist in the datacube."
|
|
20
24
|
|
|
21
25
|
|
|
22
|
-
class UnsliceableShapeError(KeyError):
|
|
26
|
+
class UnsliceableShapeError(PolytopeError, KeyError):
|
|
23
27
|
def __init__(self, axis):
|
|
24
28
|
self.axis = axis
|
|
25
29
|
self.message = f"Higher-dimensional shape does not support unsliceable axis {axis.name}."
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.7"
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
from abc import ABC
|
|
3
|
-
from typing import Dict, List, Literal, Optional, Union
|
|
4
|
-
|
|
5
|
-
from conflator import ConfigModel, Conflator
|
|
6
|
-
from pydantic import ConfigDict
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class PolytopeOptions(ABC):
|
|
10
|
-
@staticmethod
|
|
11
|
-
def get_polytope_options(options):
|
|
12
|
-
class TransformationConfig(ConfigModel):
|
|
13
|
-
model_config = ConfigDict(extra="forbid")
|
|
14
|
-
name: str = ""
|
|
15
|
-
|
|
16
|
-
class CyclicConfig(TransformationConfig):
|
|
17
|
-
name: Literal["cyclic"]
|
|
18
|
-
range: List[float] = [0]
|
|
19
|
-
|
|
20
|
-
class MapperConfig(TransformationConfig):
|
|
21
|
-
name: Literal["mapper"]
|
|
22
|
-
type: str = ""
|
|
23
|
-
resolution: Union[int, List[int]] = 0
|
|
24
|
-
axes: List[str] = [""]
|
|
25
|
-
local: Optional[List[float]] = None
|
|
26
|
-
|
|
27
|
-
class ReverseConfig(TransformationConfig):
|
|
28
|
-
name: Literal["reverse"]
|
|
29
|
-
is_reverse: bool = False
|
|
30
|
-
|
|
31
|
-
class TypeChangeConfig(TransformationConfig):
|
|
32
|
-
name: Literal["type_change"]
|
|
33
|
-
type: str = "int"
|
|
34
|
-
|
|
35
|
-
class MergeConfig(TransformationConfig):
|
|
36
|
-
name: Literal["merge"]
|
|
37
|
-
other_axis: str = ""
|
|
38
|
-
linkers: List[str] = [""]
|
|
39
|
-
|
|
40
|
-
action_subclasses_union = Union[CyclicConfig, MapperConfig, ReverseConfig, TypeChangeConfig, MergeConfig]
|
|
41
|
-
|
|
42
|
-
class AxisConfig(ConfigModel):
|
|
43
|
-
axis_name: str = ""
|
|
44
|
-
transformations: list[action_subclasses_union]
|
|
45
|
-
|
|
46
|
-
path_subclasses_union = Union[str, int, float]
|
|
47
|
-
|
|
48
|
-
class GribJumpAxesConfig(ConfigModel):
|
|
49
|
-
axis_name: str = ""
|
|
50
|
-
values: List[str] = [""]
|
|
51
|
-
|
|
52
|
-
class Config(ConfigModel):
|
|
53
|
-
axis_config: List[AxisConfig] = []
|
|
54
|
-
compressed_axes_config: List[str] = [""]
|
|
55
|
-
pre_path: Optional[Dict[str, path_subclasses_union]] = {}
|
|
56
|
-
alternative_axes: List[GribJumpAxesConfig] = []
|
|
57
|
-
|
|
58
|
-
parser = argparse.ArgumentParser(allow_abbrev=False)
|
|
59
|
-
conflator = Conflator(app_name="polytope", model=Config, cli=False, argparser=parser, **options)
|
|
60
|
-
config_options = conflator.load()
|
|
61
|
-
|
|
62
|
-
axis_config = config_options.axis_config
|
|
63
|
-
compressed_axes_config = config_options.compressed_axes_config
|
|
64
|
-
pre_path = config_options.pre_path
|
|
65
|
-
alternative_axes = config_options.alternative_axes
|
|
66
|
-
|
|
67
|
-
return (axis_config, compressed_axes_config, pre_path, alternative_axes)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.5"
|
|
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.5 → polytope-python-1.0.7}/polytope/datacube/transformations/__init__.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
|
{polytope-python-1.0.5 → polytope-python-1.0.7}/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
|