healpix-geo 0.0.7__cp312-cp312-musllinux_1_2_armv7l.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.cpython-312-arm-linux-musleabihf.so +0 -0
- healpix_geo/nested.py +567 -0
- healpix_geo/ring.py +286 -0
- healpix_geo/slices.py +4 -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 +185 -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-0.0.7.dist-info/METADATA +23 -0
- healpix_geo-0.0.7.dist-info/RECORD +19 -0
- healpix_geo-0.0.7.dist-info/WHEEL +4 -0
- healpix_geo-0.0.7.dist-info/licenses/LICENSE +201 -0
- healpix_geo.libs/libgcc_s-0366c7ba.so.1 +0 -0
|
@@ -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)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import cdshealpix
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pytest
|
|
4
|
+
from astropy.coordinates import Latitude, Longitude
|
|
5
|
+
|
|
6
|
+
import healpix_geo
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestHealpixToGeographic:
|
|
10
|
+
@pytest.mark.parametrize(
|
|
11
|
+
["cell_ids", "depth", "indexing_scheme"],
|
|
12
|
+
(
|
|
13
|
+
pytest.param(np.array([0, 4, 5, 7, 9]), 0, "ring", id="level0-ring"),
|
|
14
|
+
pytest.param(np.array([1, 2, 3, 8]), 0, "nested", id="level0-nested"),
|
|
15
|
+
pytest.param(
|
|
16
|
+
np.array([3, 19, 54, 63, 104, 127]), 4, "ring", id="level4-ring"
|
|
17
|
+
),
|
|
18
|
+
pytest.param(
|
|
19
|
+
np.array([22, 89, 134, 154, 190]), 4, "nested", id="level4-nested"
|
|
20
|
+
),
|
|
21
|
+
),
|
|
22
|
+
)
|
|
23
|
+
def test_spherical(self, cell_ids, depth, indexing_scheme):
|
|
24
|
+
if indexing_scheme == "ring":
|
|
25
|
+
param_cds = 2**depth
|
|
26
|
+
hg_healpix_to_lonlat = healpix_geo.ring.healpix_to_lonlat
|
|
27
|
+
cds_healpix_to_lonlat = cdshealpix.ring.healpix_to_lonlat
|
|
28
|
+
else:
|
|
29
|
+
param_cds = depth
|
|
30
|
+
hg_healpix_to_lonlat = healpix_geo.nested.healpix_to_lonlat
|
|
31
|
+
cds_healpix_to_lonlat = cdshealpix.nested.healpix_to_lonlat
|
|
32
|
+
|
|
33
|
+
actual_lon, actual_lat = hg_healpix_to_lonlat(
|
|
34
|
+
cell_ids, depth, ellipsoid="sphere"
|
|
35
|
+
)
|
|
36
|
+
expected_lon_, expected_lat_ = cds_healpix_to_lonlat(cell_ids, param_cds)
|
|
37
|
+
expected_lon = np.asarray(expected_lon_.to("degree"))
|
|
38
|
+
expected_lat = np.asarray(expected_lat_.to("degree"))
|
|
39
|
+
|
|
40
|
+
np.testing.assert_allclose(actual_lon, expected_lon)
|
|
41
|
+
np.testing.assert_allclose(actual_lat, expected_lat)
|
|
42
|
+
|
|
43
|
+
@pytest.mark.parametrize("ellipsoid", ["unitsphere", "sphere", "WGS84", "bessel"])
|
|
44
|
+
@pytest.mark.parametrize("depth", [0, 1, 9])
|
|
45
|
+
@pytest.mark.parametrize("indexing_scheme", ["ring", "nested"])
|
|
46
|
+
def test_ellipsoidal(self, depth, indexing_scheme, ellipsoid):
|
|
47
|
+
cell_ids = np.arange(12)
|
|
48
|
+
if indexing_scheme == "ring":
|
|
49
|
+
param_cds = 2**depth
|
|
50
|
+
hg_healpix_to_lonlat = healpix_geo.ring.healpix_to_lonlat
|
|
51
|
+
cds_healpix_to_lonlat = cdshealpix.ring.healpix_to_lonlat
|
|
52
|
+
else:
|
|
53
|
+
param_cds = depth
|
|
54
|
+
hg_healpix_to_lonlat = healpix_geo.nested.healpix_to_lonlat
|
|
55
|
+
cds_healpix_to_lonlat = cdshealpix.nested.healpix_to_lonlat
|
|
56
|
+
|
|
57
|
+
actual_lon, actual_lat = hg_healpix_to_lonlat(
|
|
58
|
+
cell_ids, depth, ellipsoid=ellipsoid
|
|
59
|
+
)
|
|
60
|
+
expected_lon_, expected_lat_ = cds_healpix_to_lonlat(cell_ids, param_cds)
|
|
61
|
+
expected_lon = np.asarray(expected_lon_.to("degree"))
|
|
62
|
+
expected_lat = np.asarray(expected_lat_.to("degree"))
|
|
63
|
+
|
|
64
|
+
np.testing.assert_allclose(actual_lon, expected_lon)
|
|
65
|
+
|
|
66
|
+
diff_lat = actual_lat - expected_lat
|
|
67
|
+
assert np.all(abs(diff_lat) < 0.3)
|
|
68
|
+
|
|
69
|
+
signs = np.array([-1, 1])
|
|
70
|
+
actual = signs[(actual_lat >= 0).astype(int)]
|
|
71
|
+
expected_ = np.sign(diff_lat)
|
|
72
|
+
expected = np.where(expected_ == 0, 1, expected_)
|
|
73
|
+
assert np.all(diff_lat == 0) or np.all(actual == expected)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestGeographicToHealpix:
|
|
77
|
+
@pytest.mark.parametrize(
|
|
78
|
+
["lon", "lat", "depth", "indexing_scheme"],
|
|
79
|
+
(
|
|
80
|
+
pytest.param(
|
|
81
|
+
np.array([-170.0, 10.0, 30.0, 124.0, 174.0]),
|
|
82
|
+
np.array([-48.0, -30.0, -5.0, 15.0, 30.0]),
|
|
83
|
+
0,
|
|
84
|
+
"ring",
|
|
85
|
+
id="level0-ring",
|
|
86
|
+
),
|
|
87
|
+
pytest.param(
|
|
88
|
+
np.array([-170.0, 10.0, 30.0, 124.0, 174.0]),
|
|
89
|
+
np.array([-48.0, -30.0, -5.0, 15.0, 30.0]),
|
|
90
|
+
0,
|
|
91
|
+
"nested",
|
|
92
|
+
id="level0-nested",
|
|
93
|
+
),
|
|
94
|
+
pytest.param(
|
|
95
|
+
np.array([-70.0, 135.0, 150.0]),
|
|
96
|
+
np.array([-65.0, 0.0, 65.0]),
|
|
97
|
+
4,
|
|
98
|
+
"ring",
|
|
99
|
+
id="level4-ring",
|
|
100
|
+
),
|
|
101
|
+
pytest.param(
|
|
102
|
+
np.array([-70.0, 135.0, 150.0]),
|
|
103
|
+
np.array([-65.0, 0.0, 65.0]),
|
|
104
|
+
4,
|
|
105
|
+
"nested",
|
|
106
|
+
id="level4-nested",
|
|
107
|
+
),
|
|
108
|
+
),
|
|
109
|
+
)
|
|
110
|
+
def test_spherical(self, lon, lat, depth, indexing_scheme):
|
|
111
|
+
if indexing_scheme == "ring":
|
|
112
|
+
param_cds = 2**depth
|
|
113
|
+
hg_lonlat_to_healpix = healpix_geo.ring.lonlat_to_healpix
|
|
114
|
+
cds_lonlat_to_healpix = cdshealpix.ring.lonlat_to_healpix
|
|
115
|
+
else:
|
|
116
|
+
param_cds = depth
|
|
117
|
+
hg_lonlat_to_healpix = healpix_geo.nested.lonlat_to_healpix
|
|
118
|
+
cds_lonlat_to_healpix = cdshealpix.nested.lonlat_to_healpix
|
|
119
|
+
|
|
120
|
+
actual = hg_lonlat_to_healpix(lon, lat, depth, ellipsoid="sphere")
|
|
121
|
+
lon_ = Longitude(lon, unit="degree")
|
|
122
|
+
lat_ = Latitude(lat, unit="degree")
|
|
123
|
+
expected = cds_lonlat_to_healpix(lon_, lat_, param_cds)
|
|
124
|
+
|
|
125
|
+
np.testing.assert_equal(actual, expected)
|
|
126
|
+
|
|
127
|
+
@pytest.mark.parametrize("ellipsoid", ["unitsphere", "sphere", "WGS84", "bessel"])
|
|
128
|
+
@pytest.mark.parametrize("depth", [0, 1, 9])
|
|
129
|
+
@pytest.mark.parametrize("indexing_scheme", ["ring", "nested"])
|
|
130
|
+
def test_ellipsoidal(self, ellipsoid, depth, indexing_scheme):
|
|
131
|
+
lat = np.linspace(-90, 90, 50)
|
|
132
|
+
lon = np.full_like(lat, fill_value=45.0)
|
|
133
|
+
|
|
134
|
+
if indexing_scheme == "ring":
|
|
135
|
+
param_cds = 2**depth
|
|
136
|
+
hg = healpix_geo.ring.lonlat_to_healpix
|
|
137
|
+
cds = cdshealpix.ring.lonlat_to_healpix
|
|
138
|
+
else:
|
|
139
|
+
param_cds = depth
|
|
140
|
+
hg = healpix_geo.nested.lonlat_to_healpix
|
|
141
|
+
cds = cdshealpix.nested.lonlat_to_healpix
|
|
142
|
+
|
|
143
|
+
actual = hg(lon, lat, depth, ellipsoid=ellipsoid)
|
|
144
|
+
|
|
145
|
+
lon_ = Longitude(lon, unit="degree")
|
|
146
|
+
lat_ = Latitude(lat, unit="degree")
|
|
147
|
+
expected = cds(lon_, lat_, param_cds)
|
|
148
|
+
|
|
149
|
+
assert actual.dtype == "uint64"
|
|
150
|
+
assert expected.dtype == "uint64"
|
|
151
|
+
|
|
152
|
+
# TODO: this is currently a smoke check, try more thorough checks
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class TestVertices:
|
|
156
|
+
@pytest.mark.parametrize(
|
|
157
|
+
["cell_ids", "depth", "indexing_scheme"],
|
|
158
|
+
(
|
|
159
|
+
pytest.param(np.array([0, 4, 5, 7, 9]), 0, "ring", id="level0-ring"),
|
|
160
|
+
pytest.param(np.array([1, 2, 3, 8]), 0, "nested", id="level0-nested"),
|
|
161
|
+
pytest.param(
|
|
162
|
+
np.array([3, 19, 54, 63, 104, 127]), 4, "ring", id="level4-ring"
|
|
163
|
+
),
|
|
164
|
+
pytest.param(
|
|
165
|
+
np.array([22, 89, 134, 154, 190]), 4, "nested", id="level4-nested"
|
|
166
|
+
),
|
|
167
|
+
),
|
|
168
|
+
)
|
|
169
|
+
def test_spherical(self, cell_ids, depth, indexing_scheme):
|
|
170
|
+
if indexing_scheme == "ring":
|
|
171
|
+
param_cds = 2**depth
|
|
172
|
+
hg_vertices = healpix_geo.ring.vertices
|
|
173
|
+
cds_vertices = cdshealpix.ring.vertices
|
|
174
|
+
else:
|
|
175
|
+
param_cds = depth
|
|
176
|
+
hg_vertices = healpix_geo.nested.vertices
|
|
177
|
+
cds_vertices = cdshealpix.nested.vertices
|
|
178
|
+
|
|
179
|
+
actual_lon, actual_lat = hg_vertices(cell_ids, depth, ellipsoid="sphere")
|
|
180
|
+
expected_lon_, expected_lat_ = cds_vertices(cell_ids, param_cds)
|
|
181
|
+
expected_lon = np.asarray(expected_lon_.to("degree"))
|
|
182
|
+
expected_lat = np.asarray(expected_lat_.to("degree"))
|
|
183
|
+
|
|
184
|
+
np.testing.assert_allclose(actual_lon, expected_lon)
|
|
185
|
+
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
|