polytope-python 1.0.31__py3-none-any.whl
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_feature/__init__.py +1 -0
- polytope_feature/datacube/__init__.py +1 -0
- polytope_feature/datacube/backends/__init__.py +1 -0
- polytope_feature/datacube/backends/datacube.py +171 -0
- polytope_feature/datacube/backends/fdb.py +399 -0
- polytope_feature/datacube/backends/mock.py +71 -0
- polytope_feature/datacube/backends/xarray.py +142 -0
- polytope_feature/datacube/datacube_axis.py +332 -0
- polytope_feature/datacube/index_tree_pb2.py +27 -0
- polytope_feature/datacube/tensor_index_tree.py +228 -0
- polytope_feature/datacube/transformations/__init__.py +1 -0
- polytope_feature/datacube/transformations/datacube_cyclic/__init__.py +1 -0
- polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py +171 -0
- polytope_feature/datacube/transformations/datacube_mappers/__init__.py +1 -0
- polytope_feature/datacube/transformations/datacube_mappers/datacube_mappers.py +141 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/__init__.py +5 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix.py +147 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/healpix_nested.py +229 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/local_regular.py +95 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/octahedral.py +7896 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_gaussian.py +1459 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/reduced_ll.py +5128 -0
- polytope_feature/datacube/transformations/datacube_mappers/mapper_types/regular.py +75 -0
- polytope_feature/datacube/transformations/datacube_merger/__init__.py +1 -0
- polytope_feature/datacube/transformations/datacube_merger/datacube_merger.py +95 -0
- polytope_feature/datacube/transformations/datacube_reverse/__init__.py +1 -0
- polytope_feature/datacube/transformations/datacube_reverse/datacube_reverse.py +65 -0
- polytope_feature/datacube/transformations/datacube_transformations.py +96 -0
- polytope_feature/datacube/transformations/datacube_type_change/__init__.py +1 -0
- polytope_feature/datacube/transformations/datacube_type_change/datacube_type_change.py +124 -0
- polytope_feature/datacube/tree_encoding.py +132 -0
- polytope_feature/engine/__init__.py +1 -0
- polytope_feature/engine/engine.py +19 -0
- polytope_feature/engine/hullslicer.py +316 -0
- polytope_feature/options.py +77 -0
- polytope_feature/polytope.py +71 -0
- polytope_feature/shapes.py +405 -0
- polytope_feature/utility/__init__.py +0 -0
- polytope_feature/utility/combinatorics.py +48 -0
- polytope_feature/utility/exceptions.py +45 -0
- polytope_feature/utility/geometry.py +26 -0
- polytope_feature/utility/list_tools.py +41 -0
- polytope_feature/utility/profiling.py +14 -0
- polytope_feature/version.py +1 -0
- polytope_python-1.0.31.dist-info/LICENSE +201 -0
- polytope_python-1.0.31.dist-info/METADATA +21 -0
- polytope_python-1.0.31.dist-info/RECORD +49 -0
- polytope_python-1.0.31.dist-info/WHEEL +5 -0
- polytope_python-1.0.31.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import bisect
|
|
2
|
+
import math
|
|
3
|
+
|
|
4
|
+
from ..datacube_mappers import DatacubeMapper
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class HealpixGridMapper(DatacubeMapper):
|
|
8
|
+
def __init__(self, base_axis, mapped_axes, resolution, md5_hash=None, local_area=[], axis_reversed=None):
|
|
9
|
+
# TODO: if local area is not empty list, raise NotImplemented
|
|
10
|
+
self._mapped_axes = mapped_axes
|
|
11
|
+
self._base_axis = base_axis
|
|
12
|
+
self._resolution = resolution
|
|
13
|
+
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
14
|
+
self._first_axis_vals = self.first_axis_vals()
|
|
15
|
+
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
16
|
+
if md5_hash is not None:
|
|
17
|
+
self.md5_hash = md5_hash
|
|
18
|
+
else:
|
|
19
|
+
self.md5_hash = _md5_hash.get(resolution, None)
|
|
20
|
+
if self._axis_reversed[mapped_axes[1]]:
|
|
21
|
+
raise NotImplementedError("Healpix grid with second axis in decreasing order is not supported")
|
|
22
|
+
if not self._axis_reversed[mapped_axes[0]]:
|
|
23
|
+
raise NotImplementedError("Healpix grid with first axis in increasing order is not supported")
|
|
24
|
+
|
|
25
|
+
def first_axis_vals(self):
|
|
26
|
+
rad2deg = 180 / math.pi
|
|
27
|
+
vals = [0] * (4 * self._resolution - 1)
|
|
28
|
+
|
|
29
|
+
# Polar caps
|
|
30
|
+
for i in range(1, self._resolution):
|
|
31
|
+
val = 90 - (rad2deg * math.acos(1 - (i * i / (3 * self._resolution * self._resolution))))
|
|
32
|
+
vals[i - 1] = val
|
|
33
|
+
vals[4 * self._resolution - 1 - i] = -val
|
|
34
|
+
# Equatorial belts
|
|
35
|
+
for i in range(self._resolution, 2 * self._resolution):
|
|
36
|
+
val = 90 - (rad2deg * math.acos((4 * self._resolution - 2 * i) / (3 * self._resolution)))
|
|
37
|
+
vals[i - 1] = val
|
|
38
|
+
vals[4 * self._resolution - 1 - i] = -val
|
|
39
|
+
# Equator
|
|
40
|
+
vals[2 * self._resolution - 1] = 0
|
|
41
|
+
return vals
|
|
42
|
+
|
|
43
|
+
def map_first_axis(self, lower, upper):
|
|
44
|
+
axis_lines = self._first_axis_vals
|
|
45
|
+
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
46
|
+
return return_vals
|
|
47
|
+
|
|
48
|
+
def second_axis_vals(self, first_val):
|
|
49
|
+
tol = 1e-8
|
|
50
|
+
first_val = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
51
|
+
idx = self._first_axis_vals.index(first_val)
|
|
52
|
+
|
|
53
|
+
values = self.HEALPix_longitudes(idx)
|
|
54
|
+
return values
|
|
55
|
+
|
|
56
|
+
def second_axis_vals_from_idx(self, first_val_idx):
|
|
57
|
+
values = self.HEALPix_longitudes(first_val_idx)
|
|
58
|
+
return values
|
|
59
|
+
|
|
60
|
+
def HEALPix_nj(self, i):
|
|
61
|
+
assert self._resolution > 0
|
|
62
|
+
ni = 4 * self._resolution - 1
|
|
63
|
+
assert i < ni
|
|
64
|
+
|
|
65
|
+
if i < self._resolution:
|
|
66
|
+
return 4 * (i + 1)
|
|
67
|
+
elif i < 3 * self._resolution:
|
|
68
|
+
return 4 * self._resolution
|
|
69
|
+
else:
|
|
70
|
+
return self.HEALPix_nj(ni - 1 - i)
|
|
71
|
+
|
|
72
|
+
def HEALPix_longitudes(self, i):
|
|
73
|
+
Nj = self.HEALPix_nj(i)
|
|
74
|
+
step = 360.0 / Nj
|
|
75
|
+
start = (
|
|
76
|
+
step / 2.0 if i < self._resolution or 3 * self._resolution - 1 < i or (i + self._resolution) % 2 else 0.0
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
longitudes = [start + n * step for n in range(Nj)]
|
|
80
|
+
|
|
81
|
+
return longitudes
|
|
82
|
+
|
|
83
|
+
def map_second_axis(self, first_val, lower, upper):
|
|
84
|
+
axis_lines = self.second_axis_vals(first_val)
|
|
85
|
+
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
86
|
+
return return_vals
|
|
87
|
+
|
|
88
|
+
def axes_idx_to_healpix_idx(self, first_idx, second_idx):
|
|
89
|
+
idx = 0
|
|
90
|
+
for i in range(self._resolution - 1):
|
|
91
|
+
if i != first_idx:
|
|
92
|
+
idx += 4 * (i + 1)
|
|
93
|
+
else:
|
|
94
|
+
idx += second_idx
|
|
95
|
+
return idx
|
|
96
|
+
for i in range(self._resolution - 1, 3 * self._resolution):
|
|
97
|
+
if i != first_idx:
|
|
98
|
+
idx += 4 * self._resolution
|
|
99
|
+
else:
|
|
100
|
+
idx += second_idx
|
|
101
|
+
return idx
|
|
102
|
+
for i in range(3 * self._resolution, 4 * self._resolution - 1):
|
|
103
|
+
if i != first_idx:
|
|
104
|
+
idx += 4 * (4 * self._resolution - 1 - i + 1)
|
|
105
|
+
else:
|
|
106
|
+
idx += second_idx
|
|
107
|
+
return idx
|
|
108
|
+
|
|
109
|
+
def find_second_idx(self, first_val, second_val):
|
|
110
|
+
tol = 1e-10
|
|
111
|
+
second_axis_vals = self.second_axis_vals(first_val)
|
|
112
|
+
second_idx = bisect.bisect_left(second_axis_vals, second_val - tol)
|
|
113
|
+
return second_idx
|
|
114
|
+
|
|
115
|
+
def unmap_first_val_to_start_line_idx(self, first_val):
|
|
116
|
+
tol = 1e-8
|
|
117
|
+
first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0]
|
|
118
|
+
first_idx = self._first_axis_vals.index(first_val)
|
|
119
|
+
idx = 0
|
|
120
|
+
for i in range(self._resolution - 1):
|
|
121
|
+
if i != first_idx:
|
|
122
|
+
idx += 4 * (i + 1)
|
|
123
|
+
else:
|
|
124
|
+
return idx
|
|
125
|
+
for i in range(self._resolution - 1, 3 * self._resolution):
|
|
126
|
+
if i != first_idx:
|
|
127
|
+
idx += 4 * self._resolution
|
|
128
|
+
else:
|
|
129
|
+
return idx
|
|
130
|
+
for i in range(3 * self._resolution, 4 * self._resolution - 1):
|
|
131
|
+
if i != first_idx:
|
|
132
|
+
idx += 4 * (4 * self._resolution - 1 - i + 1)
|
|
133
|
+
else:
|
|
134
|
+
return idx
|
|
135
|
+
|
|
136
|
+
def unmap(self, first_val, second_val):
|
|
137
|
+
tol = 1e-8
|
|
138
|
+
first_value = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
139
|
+
first_idx = self._first_axis_vals.index(first_value)
|
|
140
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val[0] - tol <= i <= second_val[0] + tol][0]
|
|
141
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
142
|
+
healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx)
|
|
143
|
+
return healpix_index
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# md5 grid hash in form {resolution : hash}
|
|
147
|
+
_md5_hash = {}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import bisect
|
|
2
|
+
import math
|
|
3
|
+
|
|
4
|
+
from ..datacube_mappers import DatacubeMapper
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class NestedHealpixGridMapper(DatacubeMapper):
|
|
8
|
+
def __init__(self, base_axis, mapped_axes, resolution, md5_hash=None, local_area=[], axis_reversed=None):
|
|
9
|
+
# TODO: if local area is not empty list, raise NotImplemented
|
|
10
|
+
self._mapped_axes = mapped_axes
|
|
11
|
+
self._base_axis = base_axis
|
|
12
|
+
self._resolution = resolution
|
|
13
|
+
self._axis_reversed = {mapped_axes[0]: True, mapped_axes[1]: False}
|
|
14
|
+
self._first_axis_vals = self.first_axis_vals()
|
|
15
|
+
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
16
|
+
self.Nside = self._resolution
|
|
17
|
+
self.k = int(math.log2(self.Nside))
|
|
18
|
+
self.Npix = 12 * self.Nside * self.Nside
|
|
19
|
+
self.Ncap = (self.Nside * (self.Nside - 1)) << 1
|
|
20
|
+
if md5_hash is not None:
|
|
21
|
+
self.md5_hash = md5_hash
|
|
22
|
+
else:
|
|
23
|
+
self.md5_hash = _md5_hash.get(resolution, None)
|
|
24
|
+
if self._axis_reversed[mapped_axes[1]]:
|
|
25
|
+
raise NotImplementedError("Healpix grid with second axis in decreasing order is not supported")
|
|
26
|
+
if not self._axis_reversed[mapped_axes[0]]:
|
|
27
|
+
raise NotImplementedError("Healpix grid with first axis in increasing order is not supported")
|
|
28
|
+
|
|
29
|
+
def first_axis_vals(self):
|
|
30
|
+
rad2deg = 180 / math.pi
|
|
31
|
+
vals = [0] * (4 * self._resolution - 1)
|
|
32
|
+
|
|
33
|
+
# Polar caps
|
|
34
|
+
for i in range(1, self._resolution):
|
|
35
|
+
val = 90 - (rad2deg * math.acos(1 - (i * i / (3 * self._resolution * self._resolution))))
|
|
36
|
+
vals[i - 1] = val
|
|
37
|
+
vals[4 * self._resolution - 1 - i] = -val
|
|
38
|
+
# Equatorial belts
|
|
39
|
+
for i in range(self._resolution, 2 * self._resolution):
|
|
40
|
+
val = 90 - (rad2deg * math.acos((4 * self._resolution - 2 * i) / (3 * self._resolution)))
|
|
41
|
+
vals[i - 1] = val
|
|
42
|
+
vals[4 * self._resolution - 1 - i] = -val
|
|
43
|
+
# Equator
|
|
44
|
+
vals[2 * self._resolution - 1] = 0
|
|
45
|
+
return vals
|
|
46
|
+
|
|
47
|
+
def map_first_axis(self, lower, upper):
|
|
48
|
+
axis_lines = self._first_axis_vals
|
|
49
|
+
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
50
|
+
return return_vals
|
|
51
|
+
|
|
52
|
+
def second_axis_vals(self, first_val):
|
|
53
|
+
tol = 1e-8
|
|
54
|
+
first_val = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
55
|
+
idx = self._first_axis_vals.index(first_val)
|
|
56
|
+
|
|
57
|
+
values = self.HEALPix_longitudes(idx)
|
|
58
|
+
return values
|
|
59
|
+
|
|
60
|
+
def second_axis_vals_from_idx(self, first_val_idx):
|
|
61
|
+
values = self.HEALPix_longitudes(first_val_idx)
|
|
62
|
+
return values
|
|
63
|
+
|
|
64
|
+
def HEALPix_nj(self, i):
|
|
65
|
+
assert self._resolution > 0
|
|
66
|
+
ni = 4 * self._resolution - 1
|
|
67
|
+
assert i < ni
|
|
68
|
+
|
|
69
|
+
if i < self._resolution:
|
|
70
|
+
return 4 * (i + 1)
|
|
71
|
+
elif i < 3 * self._resolution:
|
|
72
|
+
return 4 * self._resolution
|
|
73
|
+
else:
|
|
74
|
+
return self.HEALPix_nj(ni - 1 - i)
|
|
75
|
+
|
|
76
|
+
def HEALPix_longitudes(self, i):
|
|
77
|
+
Nj = self.HEALPix_nj(i)
|
|
78
|
+
step = 360.0 / Nj
|
|
79
|
+
start = (
|
|
80
|
+
step / 2.0 if i < self._resolution or 3 * self._resolution - 1 < i or (i + self._resolution) % 2 else 0.0
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
longitudes = [start + n * step for n in range(Nj)]
|
|
84
|
+
|
|
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
|
+
idx = 0
|
|
94
|
+
for i in range(self._resolution - 1):
|
|
95
|
+
if i != first_idx:
|
|
96
|
+
idx += 4 * (i + 1)
|
|
97
|
+
else:
|
|
98
|
+
idx += second_idx
|
|
99
|
+
return idx
|
|
100
|
+
for i in range(self._resolution - 1, 3 * self._resolution):
|
|
101
|
+
if i != first_idx:
|
|
102
|
+
idx += 4 * self._resolution
|
|
103
|
+
else:
|
|
104
|
+
idx += second_idx
|
|
105
|
+
return idx
|
|
106
|
+
for i in range(3 * self._resolution, 4 * self._resolution - 1):
|
|
107
|
+
if i != first_idx:
|
|
108
|
+
idx += 4 * (4 * self._resolution - 1 - i + 1)
|
|
109
|
+
else:
|
|
110
|
+
idx += second_idx
|
|
111
|
+
return idx
|
|
112
|
+
|
|
113
|
+
def find_second_idx(self, first_val, second_val):
|
|
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):
|
|
141
|
+
tol = 1e-8
|
|
142
|
+
first_value = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
143
|
+
first_idx = self._first_axis_vals.index(first_value)
|
|
144
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val[0] - tol <= i <= second_val[0] + tol][0]
|
|
145
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
146
|
+
healpix_index = self.axes_idx_to_healpix_idx(first_idx, second_idx)
|
|
147
|
+
# TODO: here do conversion of ring to nested healpix representation before returning
|
|
148
|
+
healpix_index = self.ring_to_nested(healpix_index)
|
|
149
|
+
return healpix_index
|
|
150
|
+
|
|
151
|
+
def div_03(self, a, b):
|
|
152
|
+
t = 1 if a >= (b << 1) else 0
|
|
153
|
+
a -= t * (b << 1)
|
|
154
|
+
return (t << 1) + (1 if a >= b else 0)
|
|
155
|
+
|
|
156
|
+
def pll(self, f):
|
|
157
|
+
pll_values = [1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7]
|
|
158
|
+
return pll_values[f]
|
|
159
|
+
|
|
160
|
+
def to_nest(self, f, ring, Nring, phi, shift):
|
|
161
|
+
r = int(((2 + (f >> 2)) << self.k) - ring - 1)
|
|
162
|
+
p = int(2 * phi - self.pll(f) * Nring - shift - 1)
|
|
163
|
+
if p >= 2 * self.Nside:
|
|
164
|
+
p -= 8 * self.Nside
|
|
165
|
+
i = int((r + p)) >> 1
|
|
166
|
+
j = int((r - p)) >> 1
|
|
167
|
+
|
|
168
|
+
return self.fij_to_nest(f, i, j, self.k)
|
|
169
|
+
|
|
170
|
+
def fij_to_nest(self, f, i, j, k):
|
|
171
|
+
return (f << (2 * k)) + self.nest_encode_bits(i) + (self.nest_encode_bits(j) << 1)
|
|
172
|
+
|
|
173
|
+
def nest_encode_bits(self, i):
|
|
174
|
+
__masks = [
|
|
175
|
+
0x00000000FFFFFFFF,
|
|
176
|
+
0x0000FFFF0000FFFF,
|
|
177
|
+
0x00FF00FF00FF00FF,
|
|
178
|
+
0x0F0F0F0F0F0F0F0F,
|
|
179
|
+
0x3333333333333333,
|
|
180
|
+
0x5555555555555555,
|
|
181
|
+
]
|
|
182
|
+
i = int(i)
|
|
183
|
+
b = i & __masks[0]
|
|
184
|
+
b = (b ^ (b << 16)) & __masks[1]
|
|
185
|
+
b = (b ^ (b << 8)) & __masks[2]
|
|
186
|
+
b = (b ^ (b << 4)) & __masks[3]
|
|
187
|
+
b = (b ^ (b << 2)) & __masks[4]
|
|
188
|
+
b = (b ^ (b << 1)) & __masks[5]
|
|
189
|
+
return b
|
|
190
|
+
|
|
191
|
+
def ring_to_nested(self, idx):
|
|
192
|
+
if idx < self.Ncap:
|
|
193
|
+
# North polar cap
|
|
194
|
+
Nring = (1 + self.int_sqrt(2 * idx + 1)) >> 1
|
|
195
|
+
phi = 1 + idx - 2 * Nring * (Nring - 1)
|
|
196
|
+
f = self.div_03(phi - 1, Nring)
|
|
197
|
+
return self.to_nest(f, Nring, Nring, phi, 0)
|
|
198
|
+
|
|
199
|
+
if self.Npix - self.Ncap <= idx:
|
|
200
|
+
# South polar cap
|
|
201
|
+
Nring = (1 + self.int_sqrt(2 * self.Npix - 2 * idx - 1)) >> 1
|
|
202
|
+
phi = 1 + idx + 2 * Nring * (Nring - 1) + 4 * Nring - self.Npix
|
|
203
|
+
ring = 4 * self.Nside - Nring # (from South pole)
|
|
204
|
+
f = self.div_03(phi - 1, Nring) + 8
|
|
205
|
+
return self.to_nest(f, ring, Nring, phi, 0)
|
|
206
|
+
else:
|
|
207
|
+
# Equatorial belt
|
|
208
|
+
ip = idx - self.Ncap
|
|
209
|
+
tmp = ip >> (self.k + 2)
|
|
210
|
+
|
|
211
|
+
phi = ip - tmp * 4 * self.Nside + 1
|
|
212
|
+
ring = tmp + self.Nside
|
|
213
|
+
|
|
214
|
+
ifm = 1 + ((phi - 1 - ((1 + tmp) >> 1)) >> self.k)
|
|
215
|
+
ifp = 1 + ((phi - 1 - ((1 - tmp + 2 * self.Nside) >> 1)) >> self.k)
|
|
216
|
+
f = (ifp | 4) if ifp == ifm else (ifp if ifp < ifm else (ifm + 8))
|
|
217
|
+
|
|
218
|
+
return self.to_nest(f, ring, self.Nside, phi, ring & 1)
|
|
219
|
+
|
|
220
|
+
def int_sqrt(self, i):
|
|
221
|
+
return int(math.sqrt(i + 0.5))
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
# md5 grid hash in form {resolution : hash}
|
|
225
|
+
_md5_hash = {
|
|
226
|
+
1024: "cbda19e48d4d7e5e22641154878b9b22",
|
|
227
|
+
512: "47efaa0853e70948a41d5225e7653194",
|
|
228
|
+
128: "f3dfeb7a5bbbdd13a20d10fdb3797c71",
|
|
229
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import bisect
|
|
2
|
+
|
|
3
|
+
from ..datacube_mappers import DatacubeMapper
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LocalRegularGridMapper(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._first_axis_min = local_area[0]
|
|
12
|
+
self._first_axis_max = local_area[1]
|
|
13
|
+
self._second_axis_min = local_area[2]
|
|
14
|
+
self._second_axis_max = local_area[3]
|
|
15
|
+
if not isinstance(resolution, list):
|
|
16
|
+
self.first_resolution = resolution
|
|
17
|
+
self.second_resolution = resolution
|
|
18
|
+
if md5_hash is not None:
|
|
19
|
+
self.md5_hash = md5_hash
|
|
20
|
+
else:
|
|
21
|
+
self.md5_hash = _md5_hash.get(resolution, None)
|
|
22
|
+
else:
|
|
23
|
+
self.first_resolution = resolution[0]
|
|
24
|
+
self.second_resolution = resolution[1]
|
|
25
|
+
if md5_hash is not None:
|
|
26
|
+
self.md5_hash = md5_hash
|
|
27
|
+
else:
|
|
28
|
+
self.md5_hash = _md5_hash.get(tuple(resolution), None)
|
|
29
|
+
self._first_deg_increment = (local_area[1] - local_area[0]) / self.first_resolution
|
|
30
|
+
self._second_deg_increment = (local_area[3] - local_area[2]) / self.second_resolution
|
|
31
|
+
if axis_reversed is None:
|
|
32
|
+
self._axis_reversed = {mapped_axes[0]: False, mapped_axes[1]: False}
|
|
33
|
+
else:
|
|
34
|
+
assert set(axis_reversed.keys()) == set(mapped_axes)
|
|
35
|
+
self._axis_reversed = axis_reversed
|
|
36
|
+
self._first_axis_vals = self.first_axis_vals()
|
|
37
|
+
self.compressed_grid_axes = [self._mapped_axes[1]]
|
|
38
|
+
if self._axis_reversed[mapped_axes[1]]:
|
|
39
|
+
raise NotImplementedError("Local regular grid with second axis in decreasing order is not supported")
|
|
40
|
+
|
|
41
|
+
def first_axis_vals(self):
|
|
42
|
+
if self._axis_reversed[self._mapped_axes[0]]:
|
|
43
|
+
first_ax_vals = [
|
|
44
|
+
self._first_axis_max - i * self._first_deg_increment for i in range(self.first_resolution + 1)
|
|
45
|
+
]
|
|
46
|
+
else:
|
|
47
|
+
first_ax_vals = [
|
|
48
|
+
self._first_axis_min + i * self._first_deg_increment for i in range(self.first_resolution + 1)
|
|
49
|
+
]
|
|
50
|
+
return first_ax_vals
|
|
51
|
+
|
|
52
|
+
def map_first_axis(self, lower, upper):
|
|
53
|
+
axis_lines = self._first_axis_vals
|
|
54
|
+
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
55
|
+
return return_vals
|
|
56
|
+
|
|
57
|
+
def second_axis_vals(self, first_val):
|
|
58
|
+
second_ax_vals = [
|
|
59
|
+
self._second_axis_min + i * self._second_deg_increment for i in range(self.second_resolution + 1)
|
|
60
|
+
]
|
|
61
|
+
return second_ax_vals
|
|
62
|
+
|
|
63
|
+
def map_second_axis(self, first_val, lower, upper):
|
|
64
|
+
axis_lines = self.second_axis_vals(first_val)
|
|
65
|
+
return_vals = [val for val in axis_lines if lower <= val <= upper]
|
|
66
|
+
return return_vals
|
|
67
|
+
|
|
68
|
+
def axes_idx_to_regular_idx(self, first_idx, second_idx):
|
|
69
|
+
final_idx = first_idx * (self.second_resolution + 1) + second_idx
|
|
70
|
+
return final_idx
|
|
71
|
+
|
|
72
|
+
def find_second_idx(self, first_val, second_val):
|
|
73
|
+
tol = 1e-10
|
|
74
|
+
second_axis_vals = self.second_axis_vals(first_val)
|
|
75
|
+
second_idx = bisect.bisect_left(second_axis_vals, second_val - tol)
|
|
76
|
+
return second_idx
|
|
77
|
+
|
|
78
|
+
def unmap_first_val_to_start_line_idx(self, first_val):
|
|
79
|
+
tol = 1e-8
|
|
80
|
+
first_val = [i for i in self._first_axis_vals if first_val - tol <= i <= first_val + tol][0]
|
|
81
|
+
first_idx = self._first_axis_vals.index(first_val)
|
|
82
|
+
return first_idx * self.second_resolution
|
|
83
|
+
|
|
84
|
+
def unmap(self, first_val, second_val):
|
|
85
|
+
tol = 1e-8
|
|
86
|
+
first_val = [i for i in self._first_axis_vals if first_val[0] - tol <= i <= first_val[0] + tol][0]
|
|
87
|
+
first_idx = self._first_axis_vals.index(first_val)
|
|
88
|
+
second_val = [i for i in self.second_axis_vals(first_val) if second_val[0] - tol <= i <= second_val[0] + tol][0]
|
|
89
|
+
second_idx = self.second_axis_vals(first_val).index(second_val)
|
|
90
|
+
final_index = self.axes_idx_to_regular_idx(first_idx, second_idx)
|
|
91
|
+
return final_index
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# md5 grid hash in form {resolution : hash}
|
|
95
|
+
_md5_hash = {}
|