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.

@@ -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
+ )