healpix-geo 0.0.9__cp310-cp310-win32.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.
Potentially problematic release.
This version of healpix-geo might be problematic. Click here for more details.
- healpix_geo/__init__.py +3 -0
- healpix_geo/geometry.py +3 -0
- healpix_geo/healpix_geo.cp310-win32.pyd +0 -0
- healpix_geo/nested.py +571 -0
- healpix_geo/ring.py +286 -0
- healpix_geo/slices.py +4 -0
- healpix_geo/tests/test_conversion.py +59 -0
- healpix_geo/tests/test_coverage.py +293 -0
- healpix_geo/tests/test_distances.py +81 -0
- healpix_geo/tests/test_index.py +290 -0
- healpix_geo/tests/test_inference.py +393 -0
- healpix_geo/tests/test_neighbours.py +40 -0
- healpix_geo/tests/test_slices.py +116 -0
- healpix_geo/tests/test_zoom.py +76 -0
- healpix_geo/utils.py +25 -0
- healpix_geo/zuniq.py +216 -0
- healpix_geo-0.0.9.dist-info/METADATA +35 -0
- healpix_geo-0.0.9.dist-info/RECORD +20 -0
- healpix_geo-0.0.9.dist-info/WHEEL +4 -0
- healpix_geo-0.0.9.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
import healpix_geo
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.parametrize(
|
|
8
|
+
["depth", "indexing_scheme", "from_", "to_", "expected"],
|
|
9
|
+
(
|
|
10
|
+
(
|
|
11
|
+
1,
|
|
12
|
+
"nested",
|
|
13
|
+
np.array([0, 16, 25, 32, 46]),
|
|
14
|
+
np.array([2, 15, 27, 40, 41], dtype="int64"),
|
|
15
|
+
np.array(
|
|
16
|
+
[0.51262797, 1.60992678, 0.51347673, 0.82227572, 0.57850402],
|
|
17
|
+
dtype="float64",
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
(
|
|
21
|
+
1,
|
|
22
|
+
"ring",
|
|
23
|
+
np.array([0, 16, 25, 32, 46]),
|
|
24
|
+
np.array([2, 15, 27, 40, 41], dtype="int64"),
|
|
25
|
+
np.array(
|
|
26
|
+
[0.82227572, 0.73824548, 1.57079633, 0.51262797, 0.48146047],
|
|
27
|
+
dtype="float64",
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
(
|
|
31
|
+
1,
|
|
32
|
+
"nested",
|
|
33
|
+
np.array([0, 16, 25, 32, 46]),
|
|
34
|
+
np.array([[2], [15], [27], [40], [41]], dtype="int64"),
|
|
35
|
+
np.array(
|
|
36
|
+
[[0.51262797], [1.60992678], [0.51347673], [0.82227572], [0.57850402]],
|
|
37
|
+
dtype="float64",
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
(
|
|
41
|
+
2,
|
|
42
|
+
"ring",
|
|
43
|
+
np.array([0, 16, 25, 32, 46]),
|
|
44
|
+
np.array([[2, 4], [15, 7], [27, 26], [40, -1], [-1, 41]], dtype="int64"),
|
|
45
|
+
np.array(
|
|
46
|
+
[
|
|
47
|
+
[0.4089604, 0.23486912],
|
|
48
|
+
[0.30291976, 0.283655],
|
|
49
|
+
[0.57850402, 0.29185825],
|
|
50
|
+
[1.87523829, np.nan],
|
|
51
|
+
[np.nan, 1.60781736],
|
|
52
|
+
],
|
|
53
|
+
dtype="float64",
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
def test_distance(depth, indexing_scheme, from_, to_, expected):
|
|
59
|
+
if indexing_scheme == "nested":
|
|
60
|
+
angular_distances = healpix_geo.nested.angular_distances
|
|
61
|
+
elif indexing_scheme == "ring":
|
|
62
|
+
angular_distances = healpix_geo.ring.angular_distances
|
|
63
|
+
|
|
64
|
+
actual = angular_distances(from_, to_, depth)
|
|
65
|
+
|
|
66
|
+
np.testing.assert_allclose(actual, expected)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pytest.mark.parametrize("indexing_scheme", ["ring", "nested"])
|
|
70
|
+
def test_distance_error(indexing_scheme):
|
|
71
|
+
if indexing_scheme == "nested":
|
|
72
|
+
angular_distances = healpix_geo.nested.angular_distances
|
|
73
|
+
elif indexing_scheme == "ring":
|
|
74
|
+
angular_distances = healpix_geo.ring.angular_distances
|
|
75
|
+
|
|
76
|
+
from_ = np.array([4, 7])
|
|
77
|
+
to_ = np.array([[2, 3], [4, 6], [5, 4]])
|
|
78
|
+
depth = 1
|
|
79
|
+
|
|
80
|
+
with pytest.raises(ValueError, match="The shape of `from_` must be compatible"):
|
|
81
|
+
angular_distances(from_, to_, depth)
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
5
|
+
import shapely
|
|
6
|
+
|
|
7
|
+
import healpix_geo
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestRangeMOCIndex:
|
|
11
|
+
@pytest.mark.parametrize("level", [0, 3, 6])
|
|
12
|
+
def test_full_domain(self, level):
|
|
13
|
+
index = healpix_geo.nested.RangeMOCIndex.full_domain(level)
|
|
14
|
+
|
|
15
|
+
expected = np.arange(12 * 4**level, dtype="uint64")
|
|
16
|
+
|
|
17
|
+
assert index.nbytes == 16
|
|
18
|
+
assert index.size == expected.size
|
|
19
|
+
assert index.depth == level
|
|
20
|
+
|
|
21
|
+
@pytest.mark.parametrize(
|
|
22
|
+
["level", "cell_ids"],
|
|
23
|
+
(
|
|
24
|
+
(0, np.array([1, 2, 5], dtype="uint64")),
|
|
25
|
+
(3, np.array([12, 16, 17, 19, 22, 23, 71, 72, 73, 79], dtype="uint64")),
|
|
26
|
+
(6, np.arange(3 * 4**6, 5 * 4**6, dtype="uint64")),
|
|
27
|
+
),
|
|
28
|
+
)
|
|
29
|
+
def test_from_cell_ids(self, level, cell_ids):
|
|
30
|
+
index = healpix_geo.nested.RangeMOCIndex.from_cell_ids(level, cell_ids)
|
|
31
|
+
|
|
32
|
+
assert index.size == cell_ids.size
|
|
33
|
+
assert index.depth == level
|
|
34
|
+
|
|
35
|
+
@pytest.mark.parametrize(
|
|
36
|
+
["level", "cell_ids1", "cell_ids2", "expected"],
|
|
37
|
+
(
|
|
38
|
+
(
|
|
39
|
+
4,
|
|
40
|
+
np.arange(0, 6 * 4**4, dtype="uint64"),
|
|
41
|
+
np.arange(6 * 4**4, 12 * 4**4, dtype="uint64"),
|
|
42
|
+
np.arange(12 * 4**4, dtype="uint64"),
|
|
43
|
+
),
|
|
44
|
+
(
|
|
45
|
+
1,
|
|
46
|
+
np.array([1, 2, 3, 4, 21, 22], dtype="uint64"),
|
|
47
|
+
np.array([23, 25, 26, 32, 33, 34, 35], dtype="uint64"),
|
|
48
|
+
np.array(
|
|
49
|
+
[1, 2, 3, 4, 21, 22, 23, 25, 26, 32, 33, 34, 35], dtype="uint64"
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
def test_union(self, level, cell_ids1, cell_ids2, expected):
|
|
55
|
+
index1 = healpix_geo.nested.RangeMOCIndex.from_cell_ids(level, cell_ids1)
|
|
56
|
+
index2 = healpix_geo.nested.RangeMOCIndex.from_cell_ids(level, cell_ids2)
|
|
57
|
+
|
|
58
|
+
actual = index1.union(index2)
|
|
59
|
+
|
|
60
|
+
assert isinstance(actual, healpix_geo.nested.RangeMOCIndex)
|
|
61
|
+
np.testing.assert_equal(actual.cell_ids(), expected)
|
|
62
|
+
|
|
63
|
+
@pytest.mark.parametrize(
|
|
64
|
+
["level", "cell_ids1", "cell_ids2", "expected"],
|
|
65
|
+
(
|
|
66
|
+
(
|
|
67
|
+
4,
|
|
68
|
+
np.arange(2 * 4**4, 4 * 4**4, dtype="uint64"),
|
|
69
|
+
np.arange(3 * 4**4, 5 * 4**4, dtype="uint64"),
|
|
70
|
+
np.arange(3 * 4**4, 4 * 4**4, dtype="uint64"),
|
|
71
|
+
),
|
|
72
|
+
(
|
|
73
|
+
1,
|
|
74
|
+
np.array([1, 2, 3, 4, 21, 22, 23, 24, 25], dtype="uint64"),
|
|
75
|
+
np.array([21, 22, 23, 25, 26, 32, 33, 34, 35], dtype="uint64"),
|
|
76
|
+
np.array([21, 22, 23, 25], dtype="uint64"),
|
|
77
|
+
),
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
def test_intersection(self, level, cell_ids1, cell_ids2, expected):
|
|
81
|
+
index1 = healpix_geo.nested.RangeMOCIndex.from_cell_ids(level, cell_ids1)
|
|
82
|
+
index2 = healpix_geo.nested.RangeMOCIndex.from_cell_ids(level, cell_ids2)
|
|
83
|
+
|
|
84
|
+
actual = index1.intersection(index2)
|
|
85
|
+
|
|
86
|
+
assert isinstance(actual, healpix_geo.nested.RangeMOCIndex)
|
|
87
|
+
np.testing.assert_equal(actual.cell_ids(), expected)
|
|
88
|
+
|
|
89
|
+
@pytest.mark.parametrize(
|
|
90
|
+
["level", "cell_ids"],
|
|
91
|
+
(
|
|
92
|
+
pytest.param(0, np.arange(12, dtype="uint64"), id="base cells"),
|
|
93
|
+
pytest.param(
|
|
94
|
+
1,
|
|
95
|
+
np.array([0, 1, 2, 4, 5, 11, 12, 13, 25, 26, 27], dtype="uint64"),
|
|
96
|
+
id="list of level 1 cells",
|
|
97
|
+
),
|
|
98
|
+
pytest.param(
|
|
99
|
+
4,
|
|
100
|
+
np.arange(1 * 4**4, 2 * 4**4, dtype="uint64"),
|
|
101
|
+
id="single level 4 base cell",
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
@pytest.mark.parametrize(
|
|
106
|
+
"indexer",
|
|
107
|
+
[
|
|
108
|
+
slice(None),
|
|
109
|
+
slice(None, 4),
|
|
110
|
+
slice(2, None),
|
|
111
|
+
slice(3, 7),
|
|
112
|
+
np.arange(5, dtype="uint64"),
|
|
113
|
+
np.array([1, 2, 4, 6, 8], dtype="uint64"),
|
|
114
|
+
],
|
|
115
|
+
)
|
|
116
|
+
def test_isel(self, level, cell_ids, indexer):
|
|
117
|
+
expected = cell_ids[indexer]
|
|
118
|
+
|
|
119
|
+
index = healpix_geo.nested.RangeMOCIndex.from_cell_ids(level, cell_ids)
|
|
120
|
+
|
|
121
|
+
actual = index.isel(indexer)
|
|
122
|
+
|
|
123
|
+
np.testing.assert_equal(actual.cell_ids(), expected)
|
|
124
|
+
|
|
125
|
+
@pytest.mark.parametrize(
|
|
126
|
+
["level", "cell_ids", "indexer"],
|
|
127
|
+
(
|
|
128
|
+
pytest.param(
|
|
129
|
+
0,
|
|
130
|
+
np.arange(12, dtype="uint64"),
|
|
131
|
+
slice(None),
|
|
132
|
+
id="base cells-slice-full",
|
|
133
|
+
),
|
|
134
|
+
pytest.param(
|
|
135
|
+
0,
|
|
136
|
+
np.arange(12, dtype="uint64"),
|
|
137
|
+
slice(None, 6),
|
|
138
|
+
id="base cells-slice-left_open",
|
|
139
|
+
),
|
|
140
|
+
pytest.param(
|
|
141
|
+
0,
|
|
142
|
+
np.arange(12, dtype="uint64"),
|
|
143
|
+
slice(2, None),
|
|
144
|
+
id="base cells-slice-right_open",
|
|
145
|
+
),
|
|
146
|
+
pytest.param(
|
|
147
|
+
0,
|
|
148
|
+
np.arange(12, dtype="uint64"),
|
|
149
|
+
slice(2, 7),
|
|
150
|
+
id="base cells-slice-domain",
|
|
151
|
+
),
|
|
152
|
+
pytest.param(
|
|
153
|
+
0,
|
|
154
|
+
np.arange(12, dtype="uint64"),
|
|
155
|
+
np.arange(12, dtype="uint64"),
|
|
156
|
+
id="base cells-array-full",
|
|
157
|
+
),
|
|
158
|
+
pytest.param(
|
|
159
|
+
0,
|
|
160
|
+
np.arange(12, dtype="uint64"),
|
|
161
|
+
np.arange(2, 7, dtype="uint64"),
|
|
162
|
+
id="base cells-array-domain",
|
|
163
|
+
),
|
|
164
|
+
pytest.param(
|
|
165
|
+
0,
|
|
166
|
+
np.arange(12, dtype="uint64"),
|
|
167
|
+
np.array([1, 2, 3, 7, 8, 9, 10], dtype="uint64"),
|
|
168
|
+
id="base cells-array-disconnected",
|
|
169
|
+
),
|
|
170
|
+
pytest.param(
|
|
171
|
+
3,
|
|
172
|
+
np.arange(12 * 4**3, dtype="uint64"),
|
|
173
|
+
slice(None, 15),
|
|
174
|
+
id="level 3 cells-slice-left_open",
|
|
175
|
+
),
|
|
176
|
+
pytest.param(
|
|
177
|
+
1,
|
|
178
|
+
np.array([0, 1, 2, 4, 5, 11, 12, 13, 25, 26, 27], dtype="uint64"),
|
|
179
|
+
np.array([2, 5, 11, 12, 25, 27], dtype="uint64"),
|
|
180
|
+
id="list of level 1 cells-array-disconnected",
|
|
181
|
+
),
|
|
182
|
+
pytest.param(
|
|
183
|
+
4,
|
|
184
|
+
np.arange(1 * 4**4, 2 * 4**4, dtype="uint64"),
|
|
185
|
+
slice(260, 280),
|
|
186
|
+
id="single level 4 base cell-slice-domain",
|
|
187
|
+
),
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
def test_sel(self, level, cell_ids, indexer):
|
|
191
|
+
if isinstance(indexer, slice):
|
|
192
|
+
n = slice(
|
|
193
|
+
indexer.start if indexer.start is not None else 0,
|
|
194
|
+
(
|
|
195
|
+
indexer.stop + 1
|
|
196
|
+
if indexer.stop is not None
|
|
197
|
+
else int(np.max(cell_ids)) + 1
|
|
198
|
+
),
|
|
199
|
+
indexer.step if indexer.step is not None else 1,
|
|
200
|
+
)
|
|
201
|
+
range_ = np.arange(n.start, n.stop, n.step, dtype="uint64")
|
|
202
|
+
condition = np.isin(cell_ids, range_)
|
|
203
|
+
else:
|
|
204
|
+
condition = np.isin(cell_ids, indexer)
|
|
205
|
+
expected_cell_ids = cell_ids[condition]
|
|
206
|
+
|
|
207
|
+
index = healpix_geo.nested.RangeMOCIndex.from_cell_ids(level, cell_ids)
|
|
208
|
+
|
|
209
|
+
actual_indexer, actual_moc = index.sel(indexer)
|
|
210
|
+
|
|
211
|
+
np.testing.assert_equal(cell_ids[actual_indexer], expected_cell_ids)
|
|
212
|
+
np.testing.assert_equal(actual_moc.cell_ids(), expected_cell_ids)
|
|
213
|
+
|
|
214
|
+
@pytest.mark.parametrize(
|
|
215
|
+
["depth", "cell_ids"],
|
|
216
|
+
(
|
|
217
|
+
(2, np.arange(1 * 4**2, 3 * 4**2, dtype="uint64")),
|
|
218
|
+
(5, np.arange(12 * 4**5, dtype="uint64")),
|
|
219
|
+
),
|
|
220
|
+
)
|
|
221
|
+
def test_pickle_roundtrip(self, depth, cell_ids):
|
|
222
|
+
index = healpix_geo.nested.RangeMOCIndex.from_cell_ids(depth, cell_ids)
|
|
223
|
+
|
|
224
|
+
pickled = pickle.dumps(index)
|
|
225
|
+
assert isinstance(pickled, bytes)
|
|
226
|
+
unpickled = pickle.loads(pickled)
|
|
227
|
+
|
|
228
|
+
assert isinstance(unpickled, healpix_geo.nested.RangeMOCIndex)
|
|
229
|
+
assert index.depth == unpickled.depth
|
|
230
|
+
np.testing.assert_equal(unpickled.cell_ids(), index.cell_ids())
|
|
231
|
+
|
|
232
|
+
@pytest.mark.parametrize("depth", (0, 2, 10))
|
|
233
|
+
@pytest.mark.parametrize(
|
|
234
|
+
"geom",
|
|
235
|
+
(
|
|
236
|
+
pytest.param(shapely.Point(30, 30), id="point"),
|
|
237
|
+
pytest.param(shapely.box(-25, 15, 25, 35), id="polygon"),
|
|
238
|
+
pytest.param(
|
|
239
|
+
shapely.LineString([(30, 30), (31, 31), (32, 33)]), id="linestring"
|
|
240
|
+
),
|
|
241
|
+
pytest.param(healpix_geo.geometry.Bbox(-25, 15, 25, 35), id="bbox"),
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
@pytest.mark.parametrize("domain", ["full", "partial"])
|
|
245
|
+
def test_query(self, depth, domain, geom):
|
|
246
|
+
import cdshealpix.nested
|
|
247
|
+
from astropy.coordinates import Latitude, Longitude
|
|
248
|
+
|
|
249
|
+
if domain == "full":
|
|
250
|
+
index = healpix_geo.nested.RangeMOCIndex.full_domain(depth)
|
|
251
|
+
cell_ids = index.cell_ids()
|
|
252
|
+
else:
|
|
253
|
+
cell_ids = np.arange(4**depth, dtype="uint64")
|
|
254
|
+
index = healpix_geo.nested.RangeMOCIndex.from_cell_ids(depth, cell_ids)
|
|
255
|
+
|
|
256
|
+
if isinstance(geom, shapely.Point):
|
|
257
|
+
coords = geom.coords[0]
|
|
258
|
+
lon = Longitude([coords[0]], unit="deg")
|
|
259
|
+
lat = Latitude([coords[0]], unit="deg")
|
|
260
|
+
expected = cdshealpix.nested.lonlat_to_healpix(lon, lat, depth=depth)
|
|
261
|
+
elif isinstance(geom, shapely.LineString):
|
|
262
|
+
coords = np.asarray(geom.coords[:])
|
|
263
|
+
lon = Longitude(coords[:, 0], unit="deg")
|
|
264
|
+
lat = Latitude(coords[:, 1], unit="deg")
|
|
265
|
+
|
|
266
|
+
expected_ = np.unique(
|
|
267
|
+
cdshealpix.nested.lonlat_to_healpix(lon, lat, depth=depth)
|
|
268
|
+
)
|
|
269
|
+
expected = expected_[np.isin(expected_, cell_ids)]
|
|
270
|
+
elif isinstance(geom, shapely.Polygon):
|
|
271
|
+
coords = np.asarray(geom.exterior.coords[:])
|
|
272
|
+
lon = Longitude(coords[:, 0], unit="deg")
|
|
273
|
+
lat = Latitude(coords[:, 1], unit="deg")
|
|
274
|
+
expected_, _, _ = cdshealpix.nested.polygon_search(
|
|
275
|
+
lon, lat, depth=depth, flat=True
|
|
276
|
+
)
|
|
277
|
+
expected = expected_[np.isin(expected_, cell_ids)]
|
|
278
|
+
else:
|
|
279
|
+
expected = None
|
|
280
|
+
|
|
281
|
+
multi_slice, moc = index.query(geom)
|
|
282
|
+
|
|
283
|
+
reconstructed = np.concatenate(
|
|
284
|
+
[cell_ids[s.as_pyslice()] for s in multi_slice], axis=0
|
|
285
|
+
)
|
|
286
|
+
actual = moc.cell_ids()
|
|
287
|
+
|
|
288
|
+
if expected is not None:
|
|
289
|
+
np.testing.assert_equal(reconstructed, expected)
|
|
290
|
+
np.testing.assert_equal(actual, reconstructed)
|