polytope-python 1.0.40__tar.gz → 1.0.41__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.40/polytope_python.egg-info → polytope_python-1.0.41}/PKG-INFO +1 -1
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/fdb.py +2 -2
- polytope_python-1.0.41/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +218 -0
- polytope_python-1.0.41/polytope_feature/version.py +1 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41/polytope_python.egg-info}/PKG-INFO +1 -1
- polytope_python-1.0.40/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +0 -210
- polytope_python-1.0.40/polytope_feature/version.py +0 -1
- {polytope_python-1.0.40 → polytope_python-1.0.41}/LICENSE +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/MANIFEST.in +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/datacube.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/mock.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/xarray.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/datacube_axis.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/index_tree_pb2.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/tensor_index_tree.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_cyclic/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/datacube_mappers.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/local_regular.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/octahedral.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_gaussian.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_ll.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_mappers/mapper_types/regular.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_merger/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_merger/datacube_merger.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_reverse/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_reverse/datacube_reverse.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_transformations.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_type_change/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/transformations/datacube_type_change/datacube_type_change.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/tree_encoding.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/engine/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/engine/engine.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/engine/hullslicer.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/options.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/polytope.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/shapes.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/utility/__init__.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/utility/combinatorics.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/utility/exceptions.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/utility/geometry.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/utility/list_tools.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/utility/profiling.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_python.egg-info/SOURCES.txt +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_python.egg-info/dependency_links.txt +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_python.egg-info/not-zip-safe +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_python.egg-info/requires.txt +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_python.egg-info/top_level.txt +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/pyproject.toml +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/requirements.txt +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/setup.cfg +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/setup.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_axis_mappers.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_bad_request_error.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_combinatorics.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_cyclic_axis_over_negative_vals.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_cyclic_axis_slicer_not_0.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_cyclic_axis_slicing.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_cyclic_nearest.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_cyclic_simple.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_cyclic_snapping.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_datacube_axes_init.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_datacube_mock.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_datacube_xarray.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_date_time_unmerged.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_ecmwf_oper_data_fdb.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_engine_slicer.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_fdb_datacube.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_fdb_unmap_tree.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_float_type.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_healpix_mapper.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_healpix_nested_grid.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_hull_slicer.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_hullslicer_engine.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_incomplete_tree_fdb.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_local_grid_cyclic.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_local_regular_grid.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_local_swiss_grid.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_mappers.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_merge_cyclic_octahedral.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_merge_octahedral_one_axis.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_merge_transformation.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_multiple_param_fdb.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_octahedral_grid.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_override_md5_hash_options.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_point_nearest.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_point_shape.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_point_union.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_profiling_requesttree.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_reduced_ll_grid.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_regular_grid.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_regular_reduced_grid.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_request_tree.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_request_trees_after_slicing.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_reverse_transformation.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_shapes.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slice_date_range_fdb.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slice_date_range_fdb_v2.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slice_fdb_box.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slicer_engine.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slicer_era5.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slicer_xarray.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slicing_unsliceable_axis.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slicing_xarray_3D.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_slicing_xarray_4D.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_snapping.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_snapping_real_data.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_tree_protobuf.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_tree_protobuf_encoding.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_tree_protobuf_encoding_fdb.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_type_change_transformation.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_union_gj.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_union_point_box.py +0 -0
- {polytope_python-1.0.40 → polytope_python-1.0.41}/tests/test_wave_spectra_data.py +0 -0
|
@@ -205,11 +205,11 @@ class FDBDatacube(Datacube):
|
|
|
205
205
|
original_fdb_node_range_vals = []
|
|
206
206
|
new_current_start_idx = []
|
|
207
207
|
for j, idx in enumerate(sub_lat_idxs):
|
|
208
|
-
if idx not in seen_indices:
|
|
208
|
+
if idx.tolist() not in seen_indices:
|
|
209
209
|
# NOTE: need to remove it from the values in the corresponding tree node
|
|
210
210
|
# NOTE: need to read just the range we give to gj
|
|
211
211
|
original_fdb_node_range_vals.append(actual_fdb_node[0].values[j])
|
|
212
|
-
seen_indices.add(idx)
|
|
212
|
+
seen_indices.add(idx.tolist())
|
|
213
213
|
new_current_start_idx.append(idx)
|
|
214
214
|
if original_fdb_node_range_vals != []:
|
|
215
215
|
actual_fdb_node[0].values = tuple(original_fdb_node_range_vals)
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from ..datacube_mappers import DatacubeMapper
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class NestedHealpixGridMapper(DatacubeMapper):
|
|
9
|
+
def __init__(self, base_axis, mapped_axes, resolution, md5_hash=None, local_area=[], axis_reversed=None):
|
|
10
|
+
# TODO: if local area is not empty list, raise NotImplemented
|
|
11
|
+
self._mapped_axes = mapped_axes
|
|
12
|
+
self._base_axis = base_axis
|
|
13
|
+
self._resolution = resolution
|
|
14
|
+
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
15
|
+
self._first_axis_vals = self.first_axis_vals()
|
|
16
|
+
self._first_axis_vals_np_rounded = -np.round(np.array(self._first_axis_vals), decimals=8)
|
|
17
|
+
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
18
|
+
self.Nside = self._resolution
|
|
19
|
+
self.k = int(math.log2(self.Nside))
|
|
20
|
+
self.Npix = 12 * self.Nside * self.Nside
|
|
21
|
+
self.Ncap = (self.Nside * (self.Nside - 1)) << 1
|
|
22
|
+
if md5_hash is not None:
|
|
23
|
+
self.md5_hash = md5_hash
|
|
24
|
+
else:
|
|
25
|
+
self.md5_hash = _md5_hash.get(resolution, None)
|
|
26
|
+
if self._axis_reversed[mapped_axes[1]]:
|
|
27
|
+
raise NotImplementedError("Healpix grid with second axis in decreasing order is not supported")
|
|
28
|
+
if not self._axis_reversed[mapped_axes[0]]:
|
|
29
|
+
raise NotImplementedError("Healpix grid with first axis in increasing order is not supported")
|
|
30
|
+
|
|
31
|
+
def first_axis_vals(self):
|
|
32
|
+
rad2deg = 180 / math.pi
|
|
33
|
+
vals = [0] * (4 * self._resolution - 1)
|
|
34
|
+
|
|
35
|
+
# Polar caps
|
|
36
|
+
for i in range(1, self._resolution):
|
|
37
|
+
val = 90 - (rad2deg * math.acos(1 - (i * i / (3 * self._resolution * self._resolution))))
|
|
38
|
+
vals[i - 1] = val
|
|
39
|
+
vals[4 * self._resolution - 1 - i] = -val
|
|
40
|
+
# Equatorial belts
|
|
41
|
+
for i in range(self._resolution, 2 * self._resolution):
|
|
42
|
+
val = 90 - (rad2deg * math.acos((4 * self._resolution - 2 * i) / (3 * self._resolution)))
|
|
43
|
+
vals[i - 1] = val
|
|
44
|
+
vals[4 * self._resolution - 1 - i] = -val
|
|
45
|
+
# Equator
|
|
46
|
+
vals[2 * self._resolution - 1] = 0
|
|
47
|
+
return vals
|
|
48
|
+
|
|
49
|
+
def map_first_axis(self, lower, upper):
|
|
50
|
+
axis_lines = self._first_axis_vals
|
|
51
|
+
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
52
|
+
return return_vals
|
|
53
|
+
|
|
54
|
+
def second_axis_vals(self, first_val):
|
|
55
|
+
tol = 1e-8
|
|
56
|
+
first_val = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
57
|
+
idx = self._first_axis_vals.index(first_val)
|
|
58
|
+
|
|
59
|
+
values = self.HEALPix_longitudes(idx)
|
|
60
|
+
return values
|
|
61
|
+
|
|
62
|
+
def second_axis_vals_from_idx(self, first_val_idx):
|
|
63
|
+
values = self.HEALPix_longitudes(first_val_idx)
|
|
64
|
+
return values
|
|
65
|
+
|
|
66
|
+
def HEALPix_nj(self, i):
|
|
67
|
+
assert self._resolution > 0
|
|
68
|
+
ni = 4 * self._resolution - 1
|
|
69
|
+
assert i < ni
|
|
70
|
+
|
|
71
|
+
if i < self._resolution:
|
|
72
|
+
return 4 * (i + 1)
|
|
73
|
+
elif i < 3 * self._resolution:
|
|
74
|
+
return 4 * self._resolution
|
|
75
|
+
else:
|
|
76
|
+
return self.HEALPix_nj(ni - 1 - i)
|
|
77
|
+
|
|
78
|
+
def HEALPix_longitudes(self, i):
|
|
79
|
+
Nj = self.HEALPix_nj(i)
|
|
80
|
+
step = 360.0 / Nj
|
|
81
|
+
start = np.where(
|
|
82
|
+
(i < self._resolution) | (3 * self._resolution - 1 < i) | ((i + self._resolution) % 2 == 1), step / 2.0, 0.0
|
|
83
|
+
)
|
|
84
|
+
longitudes = start + np.arange(Nj) * step
|
|
85
|
+
return longitudes
|
|
86
|
+
|
|
87
|
+
def map_second_axis(self, first_val, lower, upper):
|
|
88
|
+
axis_lines = self.second_axis_vals(first_val)
|
|
89
|
+
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
90
|
+
return return_vals
|
|
91
|
+
|
|
92
|
+
def axes_idx_to_healpix_idx(self, first_idx, second_idx):
|
|
93
|
+
res = self._resolution
|
|
94
|
+
sum1 = 2 * (res - 1) * res
|
|
95
|
+
sum2 = 2 * (((res - 1) * res) - ((4 * res - 1 - first_idx) * (4 * res - first_idx)))
|
|
96
|
+
|
|
97
|
+
if first_idx < res - 1:
|
|
98
|
+
return (2 * first_idx * (first_idx + 1)) + second_idx
|
|
99
|
+
elif first_idx < 3 * res:
|
|
100
|
+
return sum1 + (first_idx - (res - 1)) * (4 * res) + second_idx
|
|
101
|
+
else:
|
|
102
|
+
return sum1 + (2 * res + 1) * (4 * res) + sum2 + second_idx
|
|
103
|
+
|
|
104
|
+
def unmap(self, first_val, second_vals):
|
|
105
|
+
# Convert to NumPy array for fast computation
|
|
106
|
+
idx = np.searchsorted(self._first_axis_vals_np_rounded, -np.round(first_val[0], decimals=8))
|
|
107
|
+
if idx >= len(self._first_axis_vals_np_rounded):
|
|
108
|
+
return None
|
|
109
|
+
second_axis_vals = np.round(np.array(self.second_axis_vals_from_idx(idx)), decimals=8)
|
|
110
|
+
second_vals = np.round(np.array(second_vals), decimals=8)
|
|
111
|
+
second_idxs = np.searchsorted(second_axis_vals, second_vals)
|
|
112
|
+
valid_mask = second_idxs < len(second_axis_vals)
|
|
113
|
+
if not np.all(valid_mask):
|
|
114
|
+
return None
|
|
115
|
+
healpix_idxs = [self.axes_idx_to_healpix_idx(idx, sec_idx) for sec_idx in second_idxs]
|
|
116
|
+
return self.ring_to_nested(np.asarray(healpix_idxs))
|
|
117
|
+
|
|
118
|
+
def div_03(self, a, b):
|
|
119
|
+
"""Vectorized version of div_03"""
|
|
120
|
+
t = np.where(a >= (b << 1), 1, 0)
|
|
121
|
+
a -= t * (b << 1)
|
|
122
|
+
return (t << 1) + np.where(a >= b, 1, 0)
|
|
123
|
+
|
|
124
|
+
def pll(self, f):
|
|
125
|
+
"""Vectorized lookup for PLL values"""
|
|
126
|
+
pll_values = np.array([1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7])
|
|
127
|
+
return pll_values[f]
|
|
128
|
+
|
|
129
|
+
def to_nest(self, f, ring, Nring, phi, shift):
|
|
130
|
+
"""Vectorized to_nest conversion"""
|
|
131
|
+
r = ((2 + (f >> 2)) << self.k) - ring - 1
|
|
132
|
+
p = 2 * phi - self.pll(f) * Nring - shift - 1
|
|
133
|
+
p = np.where(p >= 2 * self.Nside, p - 8 * self.Nside, p)
|
|
134
|
+
|
|
135
|
+
i = (r + p) >> 1
|
|
136
|
+
j = (r - p) >> 1
|
|
137
|
+
return self.fij_to_nest(f, i, j, self.k)
|
|
138
|
+
|
|
139
|
+
def fij_to_nest(self, f, i, j, k):
|
|
140
|
+
"""Vectorized nest encoding"""
|
|
141
|
+
return (
|
|
142
|
+
# (f.astype(np.uint64) << np.uint64(2 * k))
|
|
143
|
+
(f.astype(object) << (2 * k))
|
|
144
|
+
+ self.nest_encode_bits(i)
|
|
145
|
+
+ (self.nest_encode_bits(j).astype(np.uint64) << np.uint64(1))
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def nest_encode_bits(self, i):
|
|
149
|
+
"""Vectorized bit manipulation for HEALPix indexing"""
|
|
150
|
+
__masks = np.array(
|
|
151
|
+
[
|
|
152
|
+
0x00000000FFFFFFFF,
|
|
153
|
+
0x0000FFFF0000FFFF,
|
|
154
|
+
0x00FF00FF00FF00FF,
|
|
155
|
+
0x0F0F0F0F0F0F0F0F,
|
|
156
|
+
0x3333333333333333,
|
|
157
|
+
0x5555555555555555,
|
|
158
|
+
],
|
|
159
|
+
dtype=np.uint64,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
b = i.astype(np.uint64) & __masks[0]
|
|
163
|
+
b = (b ^ (b << np.uint64(16))) & __masks[1]
|
|
164
|
+
b = (b ^ (b << np.uint64(8))) & __masks[2]
|
|
165
|
+
b = (b ^ (b << np.uint64(4))) & __masks[3]
|
|
166
|
+
b = (b ^ (b << np.uint64(2))) & __masks[4]
|
|
167
|
+
b = (b ^ (b << np.uint64(1))) & __masks[5]
|
|
168
|
+
return b
|
|
169
|
+
|
|
170
|
+
def int_sqrt(self, x):
|
|
171
|
+
"""Efficient integer square root for arrays"""
|
|
172
|
+
return np.sqrt(x + 0.5).astype(int)
|
|
173
|
+
|
|
174
|
+
def ring_to_nested(self, idx):
|
|
175
|
+
"""Vectorized ring_to_nested conversion"""
|
|
176
|
+
# idx = np.asarray(idx) # Ensure input is an array
|
|
177
|
+
|
|
178
|
+
north_mask = idx < self.Ncap
|
|
179
|
+
south_mask = self.Npix - self.Ncap <= idx
|
|
180
|
+
|
|
181
|
+
# North polar cap
|
|
182
|
+
Nring_north = (1 + self.int_sqrt(2 * idx + 1)) >> 1
|
|
183
|
+
phi_north = 1 + idx - 2 * Nring_north * (Nring_north - 1)
|
|
184
|
+
f_north = self.div_03(phi_north - 1, Nring_north)
|
|
185
|
+
nested_north = self.to_nest(f_north, Nring_north, Nring_north, phi_north, 0)
|
|
186
|
+
|
|
187
|
+
# South polar cap
|
|
188
|
+
Nring_south = (1 + self.int_sqrt(2 * self.Npix - 2 * idx - 1)) >> 1
|
|
189
|
+
phi_south = 1 + idx + 2 * Nring_south * (Nring_south - 1) + 4 * Nring_south - self.Npix
|
|
190
|
+
ring_south = 4 * self.Nside - Nring_south
|
|
191
|
+
f_south = self.div_03(phi_south - 1, Nring_south) + 8
|
|
192
|
+
nested_south = self.to_nest(f_south, ring_south, Nring_south, phi_south, 0)
|
|
193
|
+
|
|
194
|
+
# Equatorial belt
|
|
195
|
+
ip = idx - self.Ncap
|
|
196
|
+
tmp = ip >> (self.k + 2)
|
|
197
|
+
|
|
198
|
+
phi_equatorial = ip - tmp * 4 * self.Nside + 1
|
|
199
|
+
ring_equatorial = tmp + self.Nside
|
|
200
|
+
|
|
201
|
+
ifm = 1 + ((phi_equatorial - 1 - ((1 + tmp) >> 1)) >> self.k)
|
|
202
|
+
ifp = 1 + ((phi_equatorial - 1 - ((1 - tmp + 2 * self.Nside) >> 1)) >> self.k)
|
|
203
|
+
f_equatorial = np.where(ifp == ifm, ifp | 4, np.where(ifp < ifm, ifp, ifm + 8))
|
|
204
|
+
|
|
205
|
+
nested_equatorial = self.to_nest(f_equatorial, ring_equatorial, self.Nside, phi_equatorial, ring_equatorial & 1)
|
|
206
|
+
nested_result = np.empty_like(idx) # Preallocate array for performance
|
|
207
|
+
nested_result[north_mask] = nested_north[north_mask]
|
|
208
|
+
nested_result[south_mask] = nested_south[south_mask]
|
|
209
|
+
nested_result[~(north_mask | south_mask)] = nested_equatorial[~(north_mask | south_mask)]
|
|
210
|
+
return nested_result
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# md5 grid hash in form {resolution : hash}
|
|
214
|
+
_md5_hash = {
|
|
215
|
+
1024: "cbda19e48d4d7e5e22641154878b9b22",
|
|
216
|
+
512: "47efaa0853e70948a41d5225e7653194",
|
|
217
|
+
128: "f3dfeb7a5bbbdd13a20d10fdb3797c71",
|
|
218
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.41"
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import math
|
|
2
|
-
|
|
3
|
-
from ..datacube_mappers import DatacubeMapper
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class NestedHealpixGridMapper(DatacubeMapper):
|
|
7
|
-
def __init__(self, base_axis, mapped_axes, resolution, md5_hash=None, local_area=[], axis_reversed=None):
|
|
8
|
-
# TODO: if local area is not empty list, raise NotImplemented
|
|
9
|
-
self._mapped_axes = mapped_axes
|
|
10
|
-
self._base_axis = base_axis
|
|
11
|
-
self._resolution = resolution
|
|
12
|
-
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
13
|
-
self._first_axis_vals = self.first_axis_vals()
|
|
14
|
-
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
15
|
-
self.Nside = self._resolution
|
|
16
|
-
self.k = int(math.log2(self.Nside))
|
|
17
|
-
self.Npix = 12 * self.Nside * self.Nside
|
|
18
|
-
self.Ncap = (self.Nside * (self.Nside - 1)) << 1
|
|
19
|
-
if md5_hash is not None:
|
|
20
|
-
self.md5_hash = md5_hash
|
|
21
|
-
else:
|
|
22
|
-
self.md5_hash = _md5_hash.get(resolution, None)
|
|
23
|
-
if self._axis_reversed[mapped_axes[1]]:
|
|
24
|
-
raise NotImplementedError("Healpix grid with second axis in decreasing order is not supported")
|
|
25
|
-
if not self._axis_reversed[mapped_axes[0]]:
|
|
26
|
-
raise NotImplementedError("Healpix grid with first axis in increasing order is not supported")
|
|
27
|
-
|
|
28
|
-
def first_axis_vals(self):
|
|
29
|
-
rad2deg = 180 / math.pi
|
|
30
|
-
vals = [0] * (4 * self._resolution - 1)
|
|
31
|
-
|
|
32
|
-
# Polar caps
|
|
33
|
-
for i in range(1, self._resolution):
|
|
34
|
-
val = 90 - (rad2deg * math.acos(1 - (i * i / (3 * self._resolution * self._resolution))))
|
|
35
|
-
vals[i - 1] = val
|
|
36
|
-
vals[4 * self._resolution - 1 - i] = -val
|
|
37
|
-
# Equatorial belts
|
|
38
|
-
for i in range(self._resolution, 2 * self._resolution):
|
|
39
|
-
val = 90 - (rad2deg * math.acos((4 * self._resolution - 2 * i) / (3 * self._resolution)))
|
|
40
|
-
vals[i - 1] = val
|
|
41
|
-
vals[4 * self._resolution - 1 - i] = -val
|
|
42
|
-
# Equator
|
|
43
|
-
vals[2 * self._resolution - 1] = 0
|
|
44
|
-
return vals
|
|
45
|
-
|
|
46
|
-
def map_first_axis(self, lower, upper):
|
|
47
|
-
axis_lines = self._first_axis_vals
|
|
48
|
-
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
49
|
-
return return_vals
|
|
50
|
-
|
|
51
|
-
def second_axis_vals(self, first_val):
|
|
52
|
-
tol = 1e-8
|
|
53
|
-
first_val = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
54
|
-
idx = self._first_axis_vals.index(first_val)
|
|
55
|
-
|
|
56
|
-
values = self.HEALPix_longitudes(idx)
|
|
57
|
-
return values
|
|
58
|
-
|
|
59
|
-
def second_axis_vals_from_idx(self, first_val_idx):
|
|
60
|
-
values = self.HEALPix_longitudes(first_val_idx)
|
|
61
|
-
return values
|
|
62
|
-
|
|
63
|
-
def HEALPix_nj(self, i):
|
|
64
|
-
assert self._resolution > 0
|
|
65
|
-
ni = 4 * self._resolution - 1
|
|
66
|
-
assert i < ni
|
|
67
|
-
|
|
68
|
-
if i < self._resolution:
|
|
69
|
-
return 4 * (i + 1)
|
|
70
|
-
elif i < 3 * self._resolution:
|
|
71
|
-
return 4 * self._resolution
|
|
72
|
-
else:
|
|
73
|
-
return self.HEALPix_nj(ni - 1 - i)
|
|
74
|
-
|
|
75
|
-
def HEALPix_longitudes(self, i):
|
|
76
|
-
Nj = self.HEALPix_nj(i)
|
|
77
|
-
step = 360.0 / Nj
|
|
78
|
-
start = (
|
|
79
|
-
step / 2.0 if i < self._resolution or 3 * self._resolution - 1 < i or (i + self._resolution) % 2 else 0.0
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
longitudes = [start + n * step for n in range(Nj)]
|
|
83
|
-
return longitudes
|
|
84
|
-
|
|
85
|
-
def map_second_axis(self, first_val, lower, upper):
|
|
86
|
-
axis_lines = self.second_axis_vals(first_val)
|
|
87
|
-
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
88
|
-
return return_vals
|
|
89
|
-
|
|
90
|
-
def axes_idx_to_healpix_idx(self, first_idx, second_idx):
|
|
91
|
-
idx = 0
|
|
92
|
-
for i in range(self._resolution - 1):
|
|
93
|
-
if i != first_idx:
|
|
94
|
-
idx += 4 * (i + 1)
|
|
95
|
-
else:
|
|
96
|
-
idx += second_idx
|
|
97
|
-
return idx
|
|
98
|
-
for i in range(self._resolution - 1, 3 * self._resolution):
|
|
99
|
-
if i != first_idx:
|
|
100
|
-
idx += 4 * self._resolution
|
|
101
|
-
else:
|
|
102
|
-
idx += second_idx
|
|
103
|
-
return idx
|
|
104
|
-
for i in range(3 * self._resolution, 4 * self._resolution - 1):
|
|
105
|
-
if i != first_idx:
|
|
106
|
-
idx += 4 * (4 * self._resolution - 1 - i)
|
|
107
|
-
else:
|
|
108
|
-
idx += second_idx
|
|
109
|
-
return idx
|
|
110
|
-
|
|
111
|
-
def unmap(self, first_val, second_vals):
|
|
112
|
-
tol = 1e-8
|
|
113
|
-
first_idx = next(
|
|
114
|
-
(i for i, val in enumerate(self._first_axis_vals) if first_val[0] - tol <= val <= first_val[0] + tol), None
|
|
115
|
-
)
|
|
116
|
-
if first_idx is None:
|
|
117
|
-
return None
|
|
118
|
-
second_axis_vals = self.second_axis_vals_from_idx(first_idx)
|
|
119
|
-
|
|
120
|
-
return_idxs = []
|
|
121
|
-
for second_val in second_vals:
|
|
122
|
-
second_idx = next(
|
|
123
|
-
(i for i, val in enumerate(second_axis_vals) if second_val - tol <= val <= second_val + tol), None
|
|
124
|
-
)
|
|
125
|
-
if second_idx is None:
|
|
126
|
-
return None
|
|
127
|
-
healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx)
|
|
128
|
-
nested_healpix_index = self.ring_to_nested(healpix_index)
|
|
129
|
-
return_idxs.append(nested_healpix_index)
|
|
130
|
-
return return_idxs
|
|
131
|
-
|
|
132
|
-
def div_03(self, a, b):
|
|
133
|
-
t = 1 if a >= (b << 1) else 0
|
|
134
|
-
a -= t * (b << 1)
|
|
135
|
-
return (t << 1) + (1 if a >= b else 0)
|
|
136
|
-
|
|
137
|
-
def pll(self, f):
|
|
138
|
-
pll_values = [1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7]
|
|
139
|
-
return pll_values[f]
|
|
140
|
-
|
|
141
|
-
def to_nest(self, f, ring, Nring, phi, shift):
|
|
142
|
-
r = int(((2 + (f >> 2)) << self.k) - ring - 1)
|
|
143
|
-
p = int(2 * phi - self.pll(f) * Nring - shift - 1)
|
|
144
|
-
if p >= 2 * self.Nside:
|
|
145
|
-
p -= 8 * self.Nside
|
|
146
|
-
i = int((r + p)) >> 1
|
|
147
|
-
j = int((r - p)) >> 1
|
|
148
|
-
|
|
149
|
-
return self.fij_to_nest(f, i, j, self.k)
|
|
150
|
-
|
|
151
|
-
def fij_to_nest(self, f, i, j, k):
|
|
152
|
-
return (f << (2 * k)) + self.nest_encode_bits(i) + (self.nest_encode_bits(j) << 1)
|
|
153
|
-
|
|
154
|
-
def nest_encode_bits(self, i):
|
|
155
|
-
__masks = [
|
|
156
|
-
0x00000000FFFFFFFF,
|
|
157
|
-
0x0000FFFF0000FFFF,
|
|
158
|
-
0x00FF00FF00FF00FF,
|
|
159
|
-
0x0F0F0F0F0F0F0F0F,
|
|
160
|
-
0x3333333333333333,
|
|
161
|
-
0x5555555555555555,
|
|
162
|
-
]
|
|
163
|
-
i = int(i)
|
|
164
|
-
b = i & __masks[0]
|
|
165
|
-
b = (b ^ (b << 16)) & __masks[1]
|
|
166
|
-
b = (b ^ (b << 8)) & __masks[2]
|
|
167
|
-
b = (b ^ (b << 4)) & __masks[3]
|
|
168
|
-
b = (b ^ (b << 2)) & __masks[4]
|
|
169
|
-
b = (b ^ (b << 1)) & __masks[5]
|
|
170
|
-
return b
|
|
171
|
-
|
|
172
|
-
def ring_to_nested(self, idx):
|
|
173
|
-
if idx < self.Ncap:
|
|
174
|
-
# North polar cap
|
|
175
|
-
Nring = (1 + self.int_sqrt(2 * idx + 1)) >> 1
|
|
176
|
-
phi = 1 + idx - 2 * Nring * (Nring - 1)
|
|
177
|
-
f = self.div_03(phi - 1, Nring)
|
|
178
|
-
return self.to_nest(f, Nring, Nring, phi, 0)
|
|
179
|
-
|
|
180
|
-
if self.Npix - self.Ncap <= idx:
|
|
181
|
-
# South polar cap
|
|
182
|
-
Nring = (1 + self.int_sqrt(2 * self.Npix - 2 * idx - 1)) >> 1
|
|
183
|
-
phi = 1 + idx + 2 * Nring * (Nring - 1) + 4 * Nring - self.Npix
|
|
184
|
-
ring = 4 * self.Nside - Nring # (from South pole)
|
|
185
|
-
f = self.div_03(phi - 1, Nring) + 8
|
|
186
|
-
return self.to_nest(f, ring, Nring, phi, 0)
|
|
187
|
-
else:
|
|
188
|
-
# Equatorial belt
|
|
189
|
-
ip = idx - self.Ncap
|
|
190
|
-
tmp = ip >> (self.k + 2)
|
|
191
|
-
|
|
192
|
-
phi = ip - tmp * 4 * self.Nside + 1
|
|
193
|
-
ring = tmp + self.Nside
|
|
194
|
-
|
|
195
|
-
ifm = 1 + ((phi - 1 - ((1 + tmp) >> 1)) >> self.k)
|
|
196
|
-
ifp = 1 + ((phi - 1 - ((1 - tmp + 2 * self.Nside) >> 1)) >> self.k)
|
|
197
|
-
f = (ifp | 4) if ifp == ifm else (ifp if ifp < ifm else (ifm + 8))
|
|
198
|
-
|
|
199
|
-
return self.to_nest(f, ring, self.Nside, phi, ring & 1)
|
|
200
|
-
|
|
201
|
-
def int_sqrt(self, i):
|
|
202
|
-
return int(math.sqrt(i + 0.5))
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
# md5 grid hash in form {resolution : hash}
|
|
206
|
-
_md5_hash = {
|
|
207
|
-
1024: "cbda19e48d4d7e5e22641154878b9b22",
|
|
208
|
-
512: "47efaa0853e70948a41d5225e7653194",
|
|
209
|
-
128: "f3dfeb7a5bbbdd13a20d10fdb3797c71",
|
|
210
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.40"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/__init__.py
RENAMED
|
File without changes
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/datacube.py
RENAMED
|
File without changes
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/mock.py
RENAMED
|
File without changes
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/backends/xarray.py
RENAMED
|
File without changes
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/datacube_axis.py
RENAMED
|
File without changes
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/index_tree_pb2.py
RENAMED
|
File without changes
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/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
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/polytope_feature/datacube/tree_encoding.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
|
{polytope_python-1.0.40 → polytope_python-1.0.41}/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.40 → polytope_python-1.0.41}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|