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,393 @@
|
|
|
1
|
+
from contextlib import nullcontext
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
import cdshealpix.nested
|
|
5
|
+
import cdshealpix.ring
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pytest
|
|
8
|
+
from astropy.coordinates import Latitude, Longitude
|
|
9
|
+
|
|
10
|
+
import healpix_geo
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Sphere:
|
|
15
|
+
radius: float
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class Ellipsoid:
|
|
20
|
+
semimajor_axis: float
|
|
21
|
+
inverse_flattening: float
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.mark.parametrize(
|
|
25
|
+
["ellipsoid_like", "error_handler"],
|
|
26
|
+
(
|
|
27
|
+
pytest.param("WGS84", nullcontext(), id="named-existing"),
|
|
28
|
+
pytest.param(
|
|
29
|
+
"unknown-ellipsoid",
|
|
30
|
+
pytest.raises(ValueError, match="Operator 'unknown-ellipsoid' not found"),
|
|
31
|
+
id="named-not_existing",
|
|
32
|
+
),
|
|
33
|
+
pytest.param(Sphere(radius=1), nullcontext(), id="object-sphere"),
|
|
34
|
+
pytest.param(
|
|
35
|
+
Ellipsoid(semimajor_axis=1, inverse_flattening=10),
|
|
36
|
+
nullcontext(),
|
|
37
|
+
id="object-ellipsoid",
|
|
38
|
+
),
|
|
39
|
+
pytest.param(
|
|
40
|
+
object(),
|
|
41
|
+
pytest.raises(TypeError, match="failed to extract enum"),
|
|
42
|
+
id="object-unknown",
|
|
43
|
+
),
|
|
44
|
+
pytest.param({"radius": 1}, nullcontext(), id="dict-sphere"),
|
|
45
|
+
pytest.param(
|
|
46
|
+
{"semimajor_axis": 1, "inverse_flattening": 10},
|
|
47
|
+
nullcontext(),
|
|
48
|
+
id="dict-ellipsoid",
|
|
49
|
+
),
|
|
50
|
+
pytest.param(
|
|
51
|
+
{"abc": 2},
|
|
52
|
+
pytest.raises(TypeError, match="failed to extract enum"),
|
|
53
|
+
id="dict-unknown",
|
|
54
|
+
),
|
|
55
|
+
pytest.param(
|
|
56
|
+
{"radius": -1},
|
|
57
|
+
pytest.raises(
|
|
58
|
+
ValueError, match="The radius must be greater than 0, but got -1.0"
|
|
59
|
+
),
|
|
60
|
+
id="dict-ellipsoid-low_radius",
|
|
61
|
+
),
|
|
62
|
+
pytest.param(
|
|
63
|
+
{"semimajor_axis": 1, "inverse_flattening": 0.5},
|
|
64
|
+
pytest.raises(
|
|
65
|
+
ValueError,
|
|
66
|
+
match="The inverse flattening must be greater than or equal to 2, but got 0.5",
|
|
67
|
+
),
|
|
68
|
+
id="dict-ellipsoid-low_inverse_flattening",
|
|
69
|
+
),
|
|
70
|
+
pytest.param(
|
|
71
|
+
{"semimajor_axis": 0, "inverse_flattening": 10},
|
|
72
|
+
pytest.raises(
|
|
73
|
+
ValueError,
|
|
74
|
+
match="The semimajor axis must be greater than 0, but got 0.0",
|
|
75
|
+
),
|
|
76
|
+
id="dict-ellipsoid-low_semimajor_axis",
|
|
77
|
+
),
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
def test_ellipsoid_like(ellipsoid_like, error_handler):
|
|
81
|
+
cell_ids = np.arange(12)
|
|
82
|
+
depth = 0
|
|
83
|
+
|
|
84
|
+
with error_handler:
|
|
85
|
+
healpix_geo.nested.healpix_to_lonlat(cell_ids, depth, ellipsoid=ellipsoid_like)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class TestHealpixToGeographic:
|
|
89
|
+
@pytest.mark.parametrize(
|
|
90
|
+
["cell_ids", "depth", "indexing_scheme"],
|
|
91
|
+
(
|
|
92
|
+
pytest.param(np.array([0, 4, 5, 7, 9]), 0, "ring", id="level0-ring"),
|
|
93
|
+
pytest.param(np.array([1, 2, 3, 8]), 0, "nested", id="level0-nested"),
|
|
94
|
+
pytest.param(
|
|
95
|
+
np.array(
|
|
96
|
+
[
|
|
97
|
+
864691128455135232,
|
|
98
|
+
1441151880758558720,
|
|
99
|
+
2017612633061982208,
|
|
100
|
+
4899916394579099648,
|
|
101
|
+
],
|
|
102
|
+
dtype="uint64",
|
|
103
|
+
),
|
|
104
|
+
0,
|
|
105
|
+
"zuniq",
|
|
106
|
+
id="level0-zuniq",
|
|
107
|
+
),
|
|
108
|
+
pytest.param(
|
|
109
|
+
np.array([3, 19, 54, 63, 104, 127]), 4, "ring", id="level4-ring"
|
|
110
|
+
),
|
|
111
|
+
pytest.param(
|
|
112
|
+
np.array([22, 89, 134, 154, 190]), 4, "nested", id="level4-nested"
|
|
113
|
+
),
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
def test_spherical(self, cell_ids, depth, indexing_scheme):
|
|
117
|
+
if indexing_scheme == "ring":
|
|
118
|
+
param_cds = 2**depth
|
|
119
|
+
hg_healpix_to_lonlat = healpix_geo.ring.healpix_to_lonlat
|
|
120
|
+
cds_healpix_to_lonlat = cdshealpix.ring.healpix_to_lonlat
|
|
121
|
+
elif indexing_scheme == "zuniq":
|
|
122
|
+
|
|
123
|
+
def hg_healpix_to_lonlat(cell_ids, depth, ellipsoid):
|
|
124
|
+
return healpix_geo.zuniq.healpix_to_lonlat(
|
|
125
|
+
cell_ids, ellipsoid=ellipsoid
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def cds_healpix_to_lonlat(cell_ids, depth):
|
|
129
|
+
cell_ids, depths = healpix_geo.zuniq.to_nested(cell_ids)
|
|
130
|
+
|
|
131
|
+
return cdshealpix.nested.healpix_to_lonlat(cell_ids, depths)
|
|
132
|
+
|
|
133
|
+
param_cds = depth
|
|
134
|
+
else:
|
|
135
|
+
param_cds = depth
|
|
136
|
+
hg_healpix_to_lonlat = healpix_geo.nested.healpix_to_lonlat
|
|
137
|
+
cds_healpix_to_lonlat = cdshealpix.nested.healpix_to_lonlat
|
|
138
|
+
|
|
139
|
+
actual_lon, actual_lat = hg_healpix_to_lonlat(
|
|
140
|
+
cell_ids, depth, ellipsoid="sphere"
|
|
141
|
+
)
|
|
142
|
+
expected_lon_, expected_lat_ = cds_healpix_to_lonlat(cell_ids, param_cds)
|
|
143
|
+
expected_lon = np.asarray(expected_lon_.to("degree"))
|
|
144
|
+
expected_lat = np.asarray(expected_lat_.to("degree"))
|
|
145
|
+
|
|
146
|
+
np.testing.assert_allclose(actual_lon, expected_lon)
|
|
147
|
+
np.testing.assert_allclose(actual_lat, expected_lat)
|
|
148
|
+
|
|
149
|
+
@pytest.mark.parametrize(
|
|
150
|
+
"ellipsoid",
|
|
151
|
+
[
|
|
152
|
+
"unitsphere",
|
|
153
|
+
"sphere",
|
|
154
|
+
"WGS84",
|
|
155
|
+
pytest.param({"radius": 1}, id="unitsphere-dict"),
|
|
156
|
+
pytest.param(
|
|
157
|
+
{"semimajor_axis": 6378388.0, "inverse_flattening": 297.0},
|
|
158
|
+
id="intl-dict",
|
|
159
|
+
),
|
|
160
|
+
pytest.param(Sphere(radius=6370997.0), id="sphere-obj"),
|
|
161
|
+
pytest.param(
|
|
162
|
+
Ellipsoid(semimajor_axis=6378388.0, inverse_flattening=297.0),
|
|
163
|
+
id="intl-obj",
|
|
164
|
+
),
|
|
165
|
+
],
|
|
166
|
+
)
|
|
167
|
+
@pytest.mark.parametrize("depth", [0, 1, 9])
|
|
168
|
+
@pytest.mark.parametrize("indexing_scheme", ["ring", "nested", "zuniq"])
|
|
169
|
+
def test_ellipsoidal(self, depth, indexing_scheme, ellipsoid):
|
|
170
|
+
cell_ids = np.arange(12)
|
|
171
|
+
if indexing_scheme == "ring":
|
|
172
|
+
param_cds = 2**depth
|
|
173
|
+
hg_healpix_to_lonlat = healpix_geo.ring.healpix_to_lonlat
|
|
174
|
+
cds_healpix_to_lonlat = cdshealpix.ring.healpix_to_lonlat
|
|
175
|
+
elif indexing_scheme == "zuniq":
|
|
176
|
+
|
|
177
|
+
def hg_healpix_to_lonlat(cell_ids, depth, ellipsoid):
|
|
178
|
+
return healpix_geo.zuniq.healpix_to_lonlat(
|
|
179
|
+
cell_ids, ellipsoid=ellipsoid
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def cds_healpix_to_lonlat(cell_ids, depth):
|
|
183
|
+
cell_ids, depths = healpix_geo.zuniq.to_nested(cell_ids)
|
|
184
|
+
|
|
185
|
+
return cdshealpix.nested.healpix_to_lonlat(cell_ids, depths)
|
|
186
|
+
|
|
187
|
+
cell_ids = healpix_geo.zuniq.from_nested(cell_ids, depth)
|
|
188
|
+
param_cds = depth
|
|
189
|
+
else:
|
|
190
|
+
param_cds = depth
|
|
191
|
+
hg_healpix_to_lonlat = healpix_geo.nested.healpix_to_lonlat
|
|
192
|
+
cds_healpix_to_lonlat = cdshealpix.nested.healpix_to_lonlat
|
|
193
|
+
|
|
194
|
+
actual_lon, actual_lat = hg_healpix_to_lonlat(
|
|
195
|
+
cell_ids, depth, ellipsoid=ellipsoid
|
|
196
|
+
)
|
|
197
|
+
expected_lon_, expected_lat_ = cds_healpix_to_lonlat(cell_ids, param_cds)
|
|
198
|
+
expected_lon = np.asarray(expected_lon_.to("degree"))
|
|
199
|
+
expected_lat = np.asarray(expected_lat_.to("degree"))
|
|
200
|
+
|
|
201
|
+
np.testing.assert_allclose(actual_lon, expected_lon)
|
|
202
|
+
|
|
203
|
+
diff_lat = actual_lat - expected_lat
|
|
204
|
+
assert np.all(abs(diff_lat) < 0.3)
|
|
205
|
+
|
|
206
|
+
signs = np.array([-1, 1])
|
|
207
|
+
actual = signs[(actual_lat >= 0).astype(int)]
|
|
208
|
+
expected_ = np.sign(diff_lat)
|
|
209
|
+
expected = np.where(expected_ == 0, 1, expected_)
|
|
210
|
+
assert np.all(diff_lat == 0) or np.all(actual == expected)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class TestGeographicToHealpix:
|
|
214
|
+
@pytest.mark.parametrize(
|
|
215
|
+
["lon", "lat", "depth", "indexing_scheme"],
|
|
216
|
+
(
|
|
217
|
+
pytest.param(
|
|
218
|
+
np.array([-170.0, 10.0, 30.0, 124.0, 174.0]),
|
|
219
|
+
np.array([-48.0, -30.0, -5.0, 15.0, 30.0]),
|
|
220
|
+
0,
|
|
221
|
+
"ring",
|
|
222
|
+
id="level0-ring",
|
|
223
|
+
),
|
|
224
|
+
pytest.param(
|
|
225
|
+
np.array([-170.0, 10.0, 30.0, 124.0, 174.0]),
|
|
226
|
+
np.array([-48.0, -30.0, -5.0, 15.0, 30.0]),
|
|
227
|
+
0,
|
|
228
|
+
"nested",
|
|
229
|
+
id="level0-nested",
|
|
230
|
+
),
|
|
231
|
+
pytest.param(
|
|
232
|
+
np.array([-170.0, 10.0, 30.0, 124.0, 174.0]),
|
|
233
|
+
np.array([-48.0, -30.0, -5.0, 15.0, 30.0]),
|
|
234
|
+
0,
|
|
235
|
+
"zuniq",
|
|
236
|
+
id="level0-zuniq",
|
|
237
|
+
),
|
|
238
|
+
pytest.param(
|
|
239
|
+
np.array([-70.0, 135.0, 150.0]),
|
|
240
|
+
np.array([-65.0, 0.0, 65.0]),
|
|
241
|
+
4,
|
|
242
|
+
"ring",
|
|
243
|
+
id="level4-ring",
|
|
244
|
+
),
|
|
245
|
+
pytest.param(
|
|
246
|
+
np.array([-70.0, 135.0, 150.0]),
|
|
247
|
+
np.array([-65.0, 0.0, 65.0]),
|
|
248
|
+
4,
|
|
249
|
+
"nested",
|
|
250
|
+
id="level4-nested",
|
|
251
|
+
),
|
|
252
|
+
pytest.param(
|
|
253
|
+
np.array([-70.0, 135.0, 150.0]),
|
|
254
|
+
np.array([-65.0, 0.0, 65.0]),
|
|
255
|
+
4,
|
|
256
|
+
"zuniq",
|
|
257
|
+
id="level4-zuniq",
|
|
258
|
+
),
|
|
259
|
+
),
|
|
260
|
+
)
|
|
261
|
+
def test_spherical(self, lon, lat, depth, indexing_scheme):
|
|
262
|
+
if indexing_scheme == "ring":
|
|
263
|
+
param_cds = 2**depth
|
|
264
|
+
hg_lonlat_to_healpix = healpix_geo.ring.lonlat_to_healpix
|
|
265
|
+
cds_lonlat_to_healpix = cdshealpix.ring.lonlat_to_healpix
|
|
266
|
+
elif indexing_scheme == "zuniq":
|
|
267
|
+
|
|
268
|
+
def cds_lonlat_to_healpix(lon, lat, depth):
|
|
269
|
+
cell_ids = cdshealpix.nested.lonlat_to_healpix(lon, lat, depth)
|
|
270
|
+
return healpix_geo.zuniq.from_nested(cell_ids, depth)
|
|
271
|
+
|
|
272
|
+
param_cds = depth
|
|
273
|
+
hg_lonlat_to_healpix = healpix_geo.zuniq.lonlat_to_healpix
|
|
274
|
+
else:
|
|
275
|
+
param_cds = depth
|
|
276
|
+
hg_lonlat_to_healpix = healpix_geo.nested.lonlat_to_healpix
|
|
277
|
+
cds_lonlat_to_healpix = cdshealpix.nested.lonlat_to_healpix
|
|
278
|
+
|
|
279
|
+
actual = hg_lonlat_to_healpix(lon, lat, depth, ellipsoid="sphere")
|
|
280
|
+
lon_ = Longitude(lon, unit="degree")
|
|
281
|
+
lat_ = Latitude(lat, unit="degree")
|
|
282
|
+
expected = cds_lonlat_to_healpix(lon_, lat_, param_cds)
|
|
283
|
+
|
|
284
|
+
np.testing.assert_equal(actual, expected)
|
|
285
|
+
|
|
286
|
+
@pytest.mark.parametrize("ellipsoid", ["unitsphere", "sphere", "WGS84", "bessel"])
|
|
287
|
+
@pytest.mark.parametrize("depth", [0, 1, 9])
|
|
288
|
+
@pytest.mark.parametrize("indexing_scheme", ["ring", "nested", "zuniq"])
|
|
289
|
+
def test_ellipsoidal(self, ellipsoid, depth, indexing_scheme):
|
|
290
|
+
lat = np.linspace(-90, 90, 50)
|
|
291
|
+
lon = np.full_like(lat, fill_value=45.0)
|
|
292
|
+
|
|
293
|
+
if indexing_scheme == "ring":
|
|
294
|
+
param_cds = 2**depth
|
|
295
|
+
hg = healpix_geo.ring.lonlat_to_healpix
|
|
296
|
+
cds = cdshealpix.ring.lonlat_to_healpix
|
|
297
|
+
elif indexing_scheme == "zuniq":
|
|
298
|
+
|
|
299
|
+
def cds(lon, lat, depth):
|
|
300
|
+
cell_ids = cdshealpix.nested.lonlat_to_healpix(lon, lat, depth)
|
|
301
|
+
return healpix_geo.zuniq.from_nested(cell_ids, depth)
|
|
302
|
+
|
|
303
|
+
param_cds = depth
|
|
304
|
+
hg = healpix_geo.zuniq.lonlat_to_healpix
|
|
305
|
+
else:
|
|
306
|
+
param_cds = depth
|
|
307
|
+
hg = healpix_geo.nested.lonlat_to_healpix
|
|
308
|
+
cds = cdshealpix.nested.lonlat_to_healpix
|
|
309
|
+
|
|
310
|
+
actual = hg(lon, lat, depth, ellipsoid=ellipsoid)
|
|
311
|
+
|
|
312
|
+
lon_ = Longitude(lon, unit="degree")
|
|
313
|
+
lat_ = Latitude(lat, unit="degree")
|
|
314
|
+
expected = cds(lon_, lat_, param_cds)
|
|
315
|
+
|
|
316
|
+
assert actual.dtype == "uint64"
|
|
317
|
+
assert expected.dtype == "uint64"
|
|
318
|
+
|
|
319
|
+
# TODO: this is currently a smoke check, try more thorough checks
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class TestVertices:
|
|
323
|
+
@pytest.mark.parametrize(
|
|
324
|
+
["cell_ids", "depth", "indexing_scheme"],
|
|
325
|
+
(
|
|
326
|
+
pytest.param(np.array([0, 4, 5, 7, 9]), 0, "ring", id="level0-ring"),
|
|
327
|
+
pytest.param(np.array([1, 2, 3, 8]), 0, "nested", id="level0-nested"),
|
|
328
|
+
pytest.param(
|
|
329
|
+
np.array(
|
|
330
|
+
[
|
|
331
|
+
864691128455135232,
|
|
332
|
+
1441151880758558720,
|
|
333
|
+
2017612633061982208,
|
|
334
|
+
4899916394579099648,
|
|
335
|
+
],
|
|
336
|
+
dtype="uint64",
|
|
337
|
+
),
|
|
338
|
+
None,
|
|
339
|
+
"zuniq",
|
|
340
|
+
id="level0-zuniq",
|
|
341
|
+
),
|
|
342
|
+
pytest.param(np.array([0, 4, 5, 7, 9]), 0, "ring", id="level0-ring"),
|
|
343
|
+
pytest.param(np.array([1, 2, 3, 8]), 0, "nested", id="level0-nested"),
|
|
344
|
+
pytest.param(
|
|
345
|
+
np.array([3, 19, 54, 63, 104, 127]), 4, "ring", id="level4-ring"
|
|
346
|
+
),
|
|
347
|
+
pytest.param(
|
|
348
|
+
np.array([22, 89, 134, 154, 190]), 4, "nested", id="level4-nested"
|
|
349
|
+
),
|
|
350
|
+
pytest.param(
|
|
351
|
+
np.array(
|
|
352
|
+
[
|
|
353
|
+
50665495807918080,
|
|
354
|
+
201536083324829696,
|
|
355
|
+
302867074940665856,
|
|
356
|
+
347903071214370816,
|
|
357
|
+
428967864507039744,
|
|
358
|
+
]
|
|
359
|
+
),
|
|
360
|
+
4,
|
|
361
|
+
"zuniq",
|
|
362
|
+
id="level4-zuniq",
|
|
363
|
+
),
|
|
364
|
+
),
|
|
365
|
+
)
|
|
366
|
+
def test_spherical(self, cell_ids, depth, indexing_scheme):
|
|
367
|
+
if indexing_scheme == "ring":
|
|
368
|
+
param_cds = 2**depth
|
|
369
|
+
hg_vertices = healpix_geo.ring.vertices
|
|
370
|
+
cds_vertices = cdshealpix.ring.vertices
|
|
371
|
+
elif indexing_scheme == "zuniq":
|
|
372
|
+
|
|
373
|
+
def cds_vertices(cell_ids, depth):
|
|
374
|
+
cell_ids, depths = healpix_geo.zuniq.to_nested(cell_ids)
|
|
375
|
+
|
|
376
|
+
return cdshealpix.nested.vertices(cell_ids, depths)
|
|
377
|
+
|
|
378
|
+
def hg_vertices(cell_ids, depth, ellipsoid):
|
|
379
|
+
return healpix_geo.zuniq.vertices(cell_ids, ellipsoid=ellipsoid)
|
|
380
|
+
|
|
381
|
+
param_cds = depth
|
|
382
|
+
else:
|
|
383
|
+
param_cds = depth
|
|
384
|
+
hg_vertices = healpix_geo.nested.vertices
|
|
385
|
+
cds_vertices = cdshealpix.nested.vertices
|
|
386
|
+
|
|
387
|
+
actual_lon, actual_lat = hg_vertices(cell_ids, depth, ellipsoid="sphere")
|
|
388
|
+
expected_lon_, expected_lat_ = cds_vertices(cell_ids, param_cds)
|
|
389
|
+
expected_lon = np.asarray(expected_lon_.to("degree"))
|
|
390
|
+
expected_lat = np.asarray(expected_lat_.to("degree"))
|
|
391
|
+
|
|
392
|
+
np.testing.assert_allclose(actual_lon, expected_lon)
|
|
393
|
+
np.testing.assert_allclose(actual_lat, expected_lat)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import cdshealpix.nested
|
|
2
|
+
import cdshealpix.ring
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
import healpix_geo
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.parametrize("depth", [2, 8])
|
|
10
|
+
@pytest.mark.parametrize("ring", [0, 1])
|
|
11
|
+
@pytest.mark.parametrize(
|
|
12
|
+
"indexing_scheme",
|
|
13
|
+
[
|
|
14
|
+
"nested",
|
|
15
|
+
"ring",
|
|
16
|
+
],
|
|
17
|
+
)
|
|
18
|
+
def test_kth_neighbourhood(depth, ring, indexing_scheme):
|
|
19
|
+
if indexing_scheme == "nested":
|
|
20
|
+
kth_neighbourhood = healpix_geo.nested.kth_neighbourhood
|
|
21
|
+
neighbours = cdshealpix.nested.neighbours
|
|
22
|
+
elif indexing_scheme == "ring":
|
|
23
|
+
kth_neighbourhood = healpix_geo.ring.kth_neighbourhood
|
|
24
|
+
|
|
25
|
+
def neighbours(ipix, depth):
|
|
26
|
+
return cdshealpix.to_ring(
|
|
27
|
+
cdshealpix.nested.neighbours(cdshealpix.from_ring(ipix, depth), depth),
|
|
28
|
+
depth=depth,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
ipixels = np.array([50, 100], dtype="int64")
|
|
32
|
+
|
|
33
|
+
actual = kth_neighbourhood(depth=depth, ipix=ipixels, ring=ring)
|
|
34
|
+
if ring == 0:
|
|
35
|
+
expected = np.reshape(ipixels, (-1, 1))
|
|
36
|
+
else:
|
|
37
|
+
expected = neighbours(ipix=ipixels, depth=depth)
|
|
38
|
+
|
|
39
|
+
np.testing.assert_equal(np.sort(actual, axis=-1), np.sort(expected, axis=-1))
|
|
40
|
+
np.testing.assert_equal(actual[:, 0], ipixels)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from healpix_geo import slices
|
|
4
|
+
|
|
5
|
+
missing = object()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestSlice:
|
|
9
|
+
@pytest.mark.parametrize("start", [0, None, 10])
|
|
10
|
+
@pytest.mark.parametrize("stop", [3, None, 10])
|
|
11
|
+
@pytest.mark.parametrize("step", [1, None, 2, missing])
|
|
12
|
+
def test_init(self, start, stop, step):
|
|
13
|
+
if step is missing:
|
|
14
|
+
vals = (start, stop)
|
|
15
|
+
step = None
|
|
16
|
+
else:
|
|
17
|
+
vals = (start, stop, step)
|
|
18
|
+
|
|
19
|
+
actual = slices.Slice(*vals)
|
|
20
|
+
|
|
21
|
+
assert actual.start == start
|
|
22
|
+
assert actual.stop == stop
|
|
23
|
+
assert actual.step == step
|
|
24
|
+
|
|
25
|
+
@pytest.mark.parametrize("start", [0, None, 10])
|
|
26
|
+
@pytest.mark.parametrize("stop", [3, None, 10])
|
|
27
|
+
@pytest.mark.parametrize("step", [1, None, 2, -1])
|
|
28
|
+
def test_repr(self, start, stop, step):
|
|
29
|
+
slice_ = slices.Slice(start, stop, step)
|
|
30
|
+
actual = repr(slice_)
|
|
31
|
+
|
|
32
|
+
expected = repr(slice(start, stop, step)).title()
|
|
33
|
+
|
|
34
|
+
assert actual == expected
|
|
35
|
+
|
|
36
|
+
@pytest.mark.parametrize(
|
|
37
|
+
"pyslice",
|
|
38
|
+
(
|
|
39
|
+
slice(None),
|
|
40
|
+
slice(None, 2),
|
|
41
|
+
slice(3, None),
|
|
42
|
+
slice(None, None, -1),
|
|
43
|
+
slice(10, None, -1),
|
|
44
|
+
slice(3, -2),
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
def test_from_pyslice(self, pyslice):
|
|
48
|
+
actual = slices.Slice.from_pyslice(pyslice)
|
|
49
|
+
|
|
50
|
+
assert actual.start == pyslice.start
|
|
51
|
+
assert actual.start == pyslice.start
|
|
52
|
+
assert actual.start == pyslice.start
|
|
53
|
+
|
|
54
|
+
@pytest.mark.parametrize(
|
|
55
|
+
"pyslice",
|
|
56
|
+
(
|
|
57
|
+
slice(None),
|
|
58
|
+
slice(None, 2),
|
|
59
|
+
slice(3, None),
|
|
60
|
+
slice(None, None, -1),
|
|
61
|
+
slice(10, None, -1),
|
|
62
|
+
slice(3, -2),
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
@pytest.mark.parametrize("size", (3, 8, 13))
|
|
66
|
+
def test_roundtrip_pyslice(self, pyslice, size):
|
|
67
|
+
slice_ = slices.Slice.from_pyslice(pyslice)
|
|
68
|
+
|
|
69
|
+
actual = slice_.as_pyslice()
|
|
70
|
+
assert actual == pyslice
|
|
71
|
+
|
|
72
|
+
@pytest.mark.parametrize(
|
|
73
|
+
"pyslice",
|
|
74
|
+
(
|
|
75
|
+
slice(None),
|
|
76
|
+
slice(None, 2),
|
|
77
|
+
slice(3, None),
|
|
78
|
+
slice(None, None, -1),
|
|
79
|
+
slice(10, None, -1),
|
|
80
|
+
slice(3, -2),
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
@pytest.mark.parametrize("size", (3, 8, 13))
|
|
84
|
+
def test_as_concrete(self, pyslice, size):
|
|
85
|
+
slice_ = slices.Slice(pyslice.start, pyslice.stop, pyslice.step)
|
|
86
|
+
|
|
87
|
+
actual = slice_.as_concrete(size)
|
|
88
|
+
expected = slice(*pyslice.indices(size))
|
|
89
|
+
|
|
90
|
+
assert actual.start == expected.start
|
|
91
|
+
assert actual.stop == expected.stop
|
|
92
|
+
assert actual.step == expected.step
|
|
93
|
+
|
|
94
|
+
def test_in_dict(self):
|
|
95
|
+
slice1 = slices.Slice(0, 4)
|
|
96
|
+
slice2 = slices.Slice(4, 6)
|
|
97
|
+
|
|
98
|
+
d = {slice1: 1, slice2: 2}
|
|
99
|
+
|
|
100
|
+
assert d[slice1] == 1
|
|
101
|
+
assert d[slice2] == 2
|
|
102
|
+
|
|
103
|
+
@pytest.mark.parametrize(
|
|
104
|
+
["vals", "expected"],
|
|
105
|
+
(
|
|
106
|
+
((0, 4), True),
|
|
107
|
+
((1, 4), False),
|
|
108
|
+
((0, 4, 1), False),
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
def test_compare(self, vals, expected):
|
|
112
|
+
slice_ = slices.Slice(0, 4)
|
|
113
|
+
other = slices.Slice(*vals)
|
|
114
|
+
|
|
115
|
+
actual = slice_ == other
|
|
116
|
+
assert actual == expected
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
import healpix_geo
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.parametrize(
|
|
8
|
+
["depth", "new_depth", "indexing_scheme"],
|
|
9
|
+
(
|
|
10
|
+
pytest.param(1, 1, "nested", id="identity"),
|
|
11
|
+
pytest.param(1, 0, "nested", id="parents-one step-base cells"),
|
|
12
|
+
pytest.param(2, 0, "nested", id="parents-two step-base cells"),
|
|
13
|
+
pytest.param(2, 1, "nested", id="parents-one step-normal"),
|
|
14
|
+
pytest.param(1, 2, "nested", id="children-one step"),
|
|
15
|
+
pytest.param(0, 2, "nested", id="children-two step-base cells"),
|
|
16
|
+
),
|
|
17
|
+
)
|
|
18
|
+
def test_zoom_to(depth, new_depth, indexing_scheme):
|
|
19
|
+
cell_ids = np.arange(12 * 4**depth)
|
|
20
|
+
if depth == new_depth:
|
|
21
|
+
expected = cell_ids
|
|
22
|
+
elif depth > new_depth:
|
|
23
|
+
relative_depth = depth - new_depth
|
|
24
|
+
expected = np.repeat(
|
|
25
|
+
np.arange(12 * 4**new_depth),
|
|
26
|
+
4**relative_depth,
|
|
27
|
+
)
|
|
28
|
+
elif depth < new_depth:
|
|
29
|
+
expected = np.reshape(np.arange(12 * 4**new_depth), (cell_ids.size, -1))
|
|
30
|
+
|
|
31
|
+
if indexing_scheme == "nested":
|
|
32
|
+
zoom_to = healpix_geo.nested.zoom_to
|
|
33
|
+
|
|
34
|
+
actual = zoom_to(cell_ids, depth, new_depth)
|
|
35
|
+
|
|
36
|
+
np.testing.assert_equal(actual, expected)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@pytest.mark.parametrize(
|
|
40
|
+
["cell_ids", "depth", "indexing_scheme"],
|
|
41
|
+
(
|
|
42
|
+
pytest.param(
|
|
43
|
+
np.arange(12 * 4, dtype="uint64"), 1, "nested", id="nested-normal"
|
|
44
|
+
),
|
|
45
|
+
pytest.param(
|
|
46
|
+
np.array([1, 15, 53, 67, 150], dtype="uint64"),
|
|
47
|
+
2,
|
|
48
|
+
"nested",
|
|
49
|
+
id="nested-normal-subset",
|
|
50
|
+
),
|
|
51
|
+
pytest.param(
|
|
52
|
+
np.arange(12, dtype="uint64"), 0, "nested", id="nested-base cells"
|
|
53
|
+
),
|
|
54
|
+
pytest.param(
|
|
55
|
+
np.array([0, 4, 6, 11], dtype="uint64"),
|
|
56
|
+
0,
|
|
57
|
+
"nested",
|
|
58
|
+
id="nested-base cells-subset",
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
def test_siblings(cell_ids, depth, indexing_scheme):
|
|
63
|
+
|
|
64
|
+
if depth != 0:
|
|
65
|
+
first = cell_ids // 4 * 4
|
|
66
|
+
expected = first[:, None] + np.arange(4)
|
|
67
|
+
else:
|
|
68
|
+
expected = np.repeat(
|
|
69
|
+
np.arange(12, dtype="uint64")[None, ...], cell_ids.size, axis=0
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if indexing_scheme == "nested":
|
|
73
|
+
siblings = healpix_geo.nested.siblings
|
|
74
|
+
|
|
75
|
+
actual = siblings(cell_ids, depth)
|
|
76
|
+
np.testing.assert_equal(actual, expected)
|
healpix_geo/utils.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _check_depth(depth):
|
|
5
|
+
ravel_depth = np.ravel(np.atleast_1d(depth))
|
|
6
|
+
if any(ravel_depth < 0) or any(ravel_depth > 29):
|
|
7
|
+
raise ValueError("Depth must be in the [0, 29] closed range")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _check_ipixels(data, depth):
|
|
11
|
+
npix = 12 * 4**depth
|
|
12
|
+
if (data >= npix).any() or (data < 0).any():
|
|
13
|
+
raise ValueError(
|
|
14
|
+
f"The input HEALPix cells contains value out of [0, {npix - 1}]"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _check_ring(depth, ring):
|
|
19
|
+
nside = 2**depth
|
|
20
|
+
|
|
21
|
+
if ring > nside:
|
|
22
|
+
raise ValueError(
|
|
23
|
+
"Crossing base cell boundaries more than once is not supported."
|
|
24
|
+
f" Received ring={ring}, but expected an integer in the range of [0, {nside}]."
|
|
25
|
+
)
|