Coverage for python / lsst / afw / geom / _hpxUtils.py: 15%

89 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-25 01:20 -0700

1# This file is part of afw. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21# 

22# This code is partly based on AladinSrc.jar version 11.024. 

23# AladinSrc.jar is licensed with GPLv3, see http://aladin.u-strasbg.fr/COPYING 

24import numpy as np 

25 

26from lsst.daf.base import PropertySet 

27 

28from ._geom import makeSkyWcs 

29 

30 

31def makeHpxWcs(hips_order, pixel, shift_order=9, validate_pixel_id=True): 

32 """ 

33 Make a SkyWcs object with HEALPix grid projection (HPX). 

34 

35 The SkyWcs generated by this function is suitable to be used with a 

36 Hierarchical Progressive Survey (HiPS) FITS image as described in 

37 https://www.ivoa.net/documents/HiPS/20170519/REC-HIPS-1.0-20170519.pdf 

38 

39 A HiPS image covers one HEALPix cell, with the HEALPix nside equal to 

40 2**hips_order. Each cell is 'shift_order' orders deeper than the HEALPix 

41 cell, with 2**shift_order x 2**shift_order sub-pixels on a side, which 

42 defines the target resolution of the HiPS image. The IVOA recommends 

43 shift_order=9, for 2**9=512 pixels on a side. See Notes below to 

44 convert from hips_order to image resolution. 

45 

46 Parameters 

47 ---------- 

48 hips_order : `int` 

49 HiPS order, such that HEALPix nside=2**hips_order. 

50 Must be a positive integer. 

51 pixel : `int` 

52 Pixel number in the nest ordering scheme. 

53 shift_order : `int`, optional 

54 Shift order for subpixels, such that there are 2**shift_order 

55 sub-pixels on a side of the HiPS cell. 

56 Must be a positive integer. 

57 validate_pixel_id : `bool`, optional 

58 If true validate that the pixel number is in range for the given 

59 hips_order. 

60 

61 

62 Returns 

63 ------- 

64 wcs : `lsst.geom.SkyWcs` 

65 

66 Raises 

67 ------ 

68 `ValueError`: Raise if hips_order is <=0, or if shift_order is <=0, or 

69 if pixel number is out of range for the given hips_order 

70 (0 <= pixel < 12*nside*nside) and validate_pixel_id is True. 

71 

72 Notes 

73 ----- 

74 Table 5 from 

75 https://www.ivoa.net/documents/HiPS/20170519/REC-HIPS-1.0-20170519.pdf 

76 shows the relationship between hips_order, number of tiles (full 

77 sky coverage), cell size, and sub-pixel size/image resolution (with 

78 the default shift_order=9): 

79 

80 +------------+-----------------+--------------+------------------+ 

81 | hips_order | Number of Tiles | Cell Size | Image Resolution | 

82 +============+=================+==============+==================+ 

83 | 0 | 12 | 58.63 deg | 6.871 arcmin | 

84 | 1 | 48 | 29.32 deg | 3.435 arcmin | 

85 | 2 | 192 | 14.66 deg | 1.718 arcmin | 

86 | 3 | 768 | 7.329 deg | 51.53 arcsec | 

87 | 4 | 3072 | 3.665 deg | 25.77 arcsec | 

88 | 5 | 12288 | 1.832 deg | 12.88 arcsec | 

89 | 6 | 49152 | 54.97 arcmin | 6.442 arcsec | 

90 | 7 | 196608 | 27.48 arcmin | 3.221 arcsec | 

91 | 8 | 786432 | 13.74 arcmin | 1.61 arcsec | 

92 | 9 | 3145728 | 6.871 arcmin | 805.2mas | 

93 | 10 | 12582912 | 3.435 arcmin | 402.6mas | 

94 | 11 | 50331648 | 1.718 arcmin | 201.3mas | 

95 | 12 | 201326592 | 51.53 arcsec | 100.6mas | 

96 | 13 | 805306368 | 25.77 arcsec | 50.32mas | 

97 +------------+-----------------+--------------+------------------+ 

98 """ 

99 if shift_order <= 0: 

100 raise ValueError(f"shift_order {shift_order} must be positive.") 

101 hips_tilepix = 2**shift_order 

102 

103 if hips_order <= 0: 

104 raise ValueError(f"order {hips_order} must be positive.") 

105 nside_cell = 2**hips_order 

106 

107 if validate_pixel_id and pixel < 0 or pixel >= 12*nside_cell*nside_cell: 

108 raise ValueError(f"pixel value {pixel} out of range.") 

109 

110 # The HEALPix grid projection (HPX) is defined in the FITS standard 

111 # https://fits.gsfc.nasa.gov/standard40/fits_standard40aa-le.pdf 

112 # from Calabretta & Roukema (2007) 

113 # https://ui.adsabs.harvard.edu/abs/2007MNRAS.381..865C/abstract 

114 # which defines the standard H = 4, K = 3 pixelization parameters 

115 # encoded in PV2_1 = H, PV2_2 = K. 

116 # The CRVAL1, CRVAL2 values should always be 0, 0 according to 

117 # the FITS standard. 

118 # The CD matrix is defined in wcslib HPXcvt.c. 

119 # The Calabretta & Roukema (2007) paper and wcslib HPXcvt.c only 

120 # define full-sky HPX projections. For single pixels we 

121 # use the code from AladinSrc.jar Tile2HPX.java to compute 

122 # CRPIX1, CRPIX2. 

123 

124 # The nside of the sub-pixels is the product of the tile nside 

125 # and the number of sub-pixels on a side. 

126 nside_pix = nside_cell*hips_tilepix 

127 # All tiles are rotated 45 degrees. 

128 cos45 = np.sqrt(2.0)/2.0 

129 # This defines the pixel scale. 

130 scale = 90.0/nside_pix/np.sqrt(2.0) 

131 cos45_scale = cos45*scale 

132 # The projected center of the pixel used for the HPX header is 

133 # a non-trivial computation, and typically is outside of the 

134 # tile pixel itself. Therefore, these values are not the same 

135 # as the values computed from HEALPix `pix2ang()`. 

136 cent_ra_proj, cent_dec_proj = _hpx_projected_center(hips_order, pixel, validate_pixel_id) 

137 

138 md = PropertySet() 

139 md['CD1_1'] = -cos45_scale 

140 md['CD1_2'] = -cos45_scale 

141 md['CD2_1'] = cos45_scale 

142 md['CD2_2'] = -cos45_scale 

143 md['CTYPE1'] = 'RA---HPX' 

144 md['CTYPE2'] = 'DEC--HPX' 

145 md['CRVAL1'] = 0.0 

146 md['CRVAL2'] = 0.0 

147 md['PV2_1'] = 4 

148 md['PV2_2'] = 3 

149 md['CRPIX1'] = ((hips_tilepix + 1)/2.0) - 0.5*(-cent_ra_proj/cos45_scale + cent_dec_proj/cos45_scale) 

150 md['CRPIX2'] = ((hips_tilepix + 1)/2.0) - 0.5*(-cent_ra_proj/cos45_scale - cent_dec_proj/cos45_scale) 

151 

152 return makeSkyWcs(md) 

153 

154 

155def _hpx_projected_center(hips_order, pixel, validate_pixel_id): 

156 """ 

157 Compute the projected center for use in HPX WCS headers. 

158 

159 The values of cent_ra_proj, cent_dec_proj computed by this function are 

160 typically outside of the cell pixel itself, and are not the same as 

161 the values computed from HEALPix `pix2ang()'. 

162 

163 Code is adapted from AladinSrc.jar version 11.024, Tile2HPX.java. 

164 AladinSrc.jar is licensed with GPLv3, see 

165 http://aladin.u-strasbg.fr/COPYING 

166 

167 Parameters 

168 ---------- 

169 hips_order : `int` 

170 HiPS order, such that HEALPix nside=2**hips_order. 

171 pixel : `int` 

172 Pixel number in the nest ordering scheme. 

173 validate_pixel_id : `bool`, optional 

174 If true validate that the pixel number is in range for the given 

175 hips_order. 

176 

177 

178 Returns 

179 ------- 

180 cent_ra_proj, cent_dec_proj : `float` 

181 Projected center ra/dec in degrees. 

182 

183 Raises 

184 ------ 

185 `ValueError`: Raised if hips_order is <=0, or if pixel number is out of 

186 range for the given order (0 < 12*nside*nside). 

187 """ 

188 if hips_order <= 0: 

189 raise ValueError(f"hips_order {hips_order} must be positive.") 

190 nside_cell = 2**hips_order 

191 

192 if validate_pixel_id and pixel < 0 or pixel >= 12*nside_cell*nside_cell: 

193 raise ValueError(f"pixel value {pixel} out of range.") 

194 

195 twice_depth = np.left_shift(hips_order, 1) 

196 xy_mask = np.left_shift(1, twice_depth) - 1 

197 fc = _ZOrderCurve2DInt() 

198 

199 d0h = np.int32(np.right_shift(pixel, twice_depth)) 

200 _hash = fc.hash2ij(pixel & xy_mask) 

201 i_in_d0h = fc.ij2i(_hash) 

202 j_in_d0h = fc.ij2j(_hash) 

203 # Compute coordinates from the center of the base pixel 

204 # with x-axis = W-->E, y-axis = S-->N 

205 l_in_d0h = i_in_d0h - j_in_d0h 

206 h_in_d0h = i_in_d0h + j_in_d0h - (nside_cell - 1) 

207 # Compute coordinates of the base pixel in the projection plane 

208 d0h_by_4_quotient = np.right_shift(d0h, 2) 

209 d0h_mod_4 = d0h - np.left_shift(d0h_by_4_quotient, 2) 

210 h_d0h = 1 - d0h_by_4_quotient 

211 l_d0h = np.left_shift(d0h_mod_4, 1) 

212 if ((h_d0h == 0) and ((l_d0h == 6) or ((l_d0h == 4) and (l_in_d0h > 0)))): 

213 # Equatorial region 

214 l_d0h -= 8 

215 elif (h_d0h != 0): 

216 # Polar caps regions 

217 l_d0h += 1 

218 if (l_d0h > 3): 

219 l_d0h -= 8 

220 # Finalize 

221 return (np.rad2deg((np.pi/4.)*(l_d0h + l_in_d0h/float(nside_cell))), 

222 np.rad2deg((np.pi/4.)*(h_d0h + h_in_d0h/float(nside_cell)))) 

223 

224 

225class _ZOrderCurve2DInt(object): 

226 """ 

227 Z-Order 2D curve for 32-bit integer values. 

228 

229 Code is ported from AladinSrc.jar version 11.024, 

230 ZOrderCurve2DImpls.java. 

231 AladinSrc.jar is licensed with GPLv3, see 

232 http://aladin.u-strasbg.fr/COPYING 

233 

234 From the original documentation: 

235 "Z-Order Curve (ZOC) implementation in which the vertical coordinate 

236 carry the most significant bit (VMSB). This implementation is based 

237 on a lookup table (LOOKUP). We assume that each discritized 

238 coordinates is coded on maximum 32 bits (INT)." 

239 """ 

240 LUPT_TO_HASH = np.array([ 

241 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, 

242 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 

243 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 

244 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, 0x0445, 

245 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 

246 0x0515, 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, 0x1000, 0x1001, 

247 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 

248 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 

249 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, 

250 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 

251 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 0x1540, 

252 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, 0x4005, 

253 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 

254 0x4055, 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 

255 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 

256 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 

257 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 

258 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 

259 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 

260 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144, 0x5145, 

261 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 

262 0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 

263 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 

264 0x5551, 0x5554, 0x5555], dtype=np.int16) 

265 

266 LUPT_TO_IJ_INT = np.array([ 

267 0x000000000, 0x000000001, 0x100000000, 0x100000001, 0x000000002, 0x000000003, 

268 0x100000002, 0x100000003, 0x200000000, 0x200000001, 0x300000000, 0x300000001, 

269 0x200000002, 0x200000003, 0x300000002, 0x300000003, 0x000000004, 0x000000005, 

270 0x100000004, 0x100000005, 0x000000006, 0x000000007, 0x100000006, 0x100000007, 

271 0x200000004, 0x200000005, 0x300000004, 0x300000005, 0x200000006, 0x200000007, 

272 0x300000006, 0x300000007, 0x400000000, 0x400000001, 0x500000000, 0x500000001, 

273 0x400000002, 0x400000003, 0x500000002, 0x500000003, 0x600000000, 0x600000001, 

274 0x700000000, 0x700000001, 0x600000002, 0x600000003, 0x700000002, 0x700000003, 

275 0x400000004, 0x400000005, 0x500000004, 0x500000005, 0x400000006, 0x400000007, 

276 0x500000006, 0x500000007, 0x600000004, 0x600000005, 0x700000004, 0x700000005, 

277 0x600000006, 0x600000007, 0x700000006, 0x700000007, 0x000000008, 0x000000009, 

278 0x100000008, 0x100000009, 0x00000000A, 0x00000000B, 0x10000000A, 0x10000000B, 

279 0x200000008, 0x200000009, 0x300000008, 0x300000009, 0x20000000A, 0x20000000B, 

280 0x30000000A, 0x30000000B, 0x00000000C, 0x00000000D, 0x10000000C, 0x10000000D, 

281 0x00000000E, 0x00000000F, 0x10000000E, 0x10000000F, 0x20000000C, 0x20000000D, 

282 0x30000000C, 0x30000000D, 0x20000000E, 0x20000000F, 0x30000000E, 0x30000000F, 

283 0x400000008, 0x400000009, 0x500000008, 0x500000009, 0x40000000A, 0x40000000B, 

284 0x50000000A, 0x50000000B, 0x600000008, 0x600000009, 0x700000008, 0x700000009, 

285 0x60000000A, 0x60000000B, 0x70000000A, 0x70000000B, 0x40000000C, 0x40000000D, 

286 0x50000000C, 0x50000000D, 0x40000000E, 0x40000000F, 0x50000000E, 0x50000000F, 

287 0x60000000C, 0x60000000D, 0x70000000C, 0x70000000D, 0x60000000E, 0x60000000F, 

288 0x70000000E, 0x70000000F, 0x800000000, 0x800000001, 0x900000000, 0x900000001, 

289 0x800000002, 0x800000003, 0x900000002, 0x900000003, 0xA00000000, 0xA00000001, 

290 0xB00000000, 0xB00000001, 0xA00000002, 0xA00000003, 0xB00000002, 0xB00000003, 

291 0x800000004, 0x800000005, 0x900000004, 0x900000005, 0x800000006, 0x800000007, 

292 0x900000006, 0x900000007, 0xA00000004, 0xA00000005, 0xB00000004, 0xB00000005, 

293 0xA00000006, 0xA00000007, 0xB00000006, 0xB00000007, 0xC00000000, 0xC00000001, 

294 0xD00000000, 0xD00000001, 0xC00000002, 0xC00000003, 0xD00000002, 0xD00000003, 

295 0xE00000000, 0xE00000001, 0xF00000000, 0xF00000001, 0xE00000002, 0xE00000003, 

296 0xF00000002, 0xF00000003, 0xC00000004, 0xC00000005, 0xD00000004, 0xD00000005, 

297 0xC00000006, 0xC00000007, 0xD00000006, 0xD00000007, 0xE00000004, 0xE00000005, 

298 0xF00000004, 0xF00000005, 0xE00000006, 0xE00000007, 0xF00000006, 0xF00000007, 

299 0x800000008, 0x800000009, 0x900000008, 0x900000009, 0x80000000A, 0x80000000B, 

300 0x90000000A, 0x90000000B, 0xA00000008, 0xA00000009, 0xB00000008, 0xB00000009, 

301 0xA0000000A, 0xA0000000B, 0xB0000000A, 0xB0000000B, 0x80000000C, 0x80000000D, 

302 0x90000000C, 0x90000000D, 0x80000000E, 0x80000000F, 0x90000000E, 0x90000000F, 

303 0xA0000000C, 0xA0000000D, 0xB0000000C, 0xB0000000D, 0xA0000000E, 0xA0000000F, 

304 0xB0000000E, 0xB0000000F, 0xC00000008, 0xC00000009, 0xD00000008, 0xD00000009, 

305 0xC0000000A, 0xC0000000B, 0xD0000000A, 0xD0000000B, 0xE00000008, 0xE00000009, 

306 0xF00000008, 0xF00000009, 0xE0000000A, 0xE0000000B, 0xF0000000A, 0xF0000000B, 

307 0xC0000000C, 0xC0000000D, 0xD0000000C, 0xD0000000D, 0xC0000000E, 0xC0000000F, 

308 0xD0000000E, 0xD0000000F, 0xE0000000C, 0xE0000000D, 0xF0000000C, 0xF0000000D, 

309 0xE0000000E, 0xE0000000F, 0xF0000000E, 0xF0000000F], dtype=np.int64) 

310 

311 def __init__(self): 

312 pass 

313 

314 def xy2hash(self, x, y): 

315 """ 

316 Compute the hash value from x/y. 

317 

318 Parameters 

319 ---------- 

320 x : `float` 

321 x coordinate along the horizontal axis. 

322 Must fit within the 32-bit integer range. 

323 y : `float` 

324 y coordinate along the vertical axis. 

325 Must fit within the 32-bit integer range. 

326 

327 Returns 

328 ------- 

329 hash : `numpy.int64` 

330 The space-filling hash value associated with the 

331 given coordinates. 

332 """ 

333 return self.ij2hash(np.int32(x), np.int32(y)) 

334 

335 def ij2hash(self, i, j): 

336 """ 

337 Compute the hash value from discretized i, j. 

338 

339 Parameters 

340 ---------- 

341 i : `int` 

342 i discretized coordinate along the horizontal axis. 

343 Must fit within the 32-bit integer range. 

344 j : `int` 

345 j discretized coordinate along the vertical axis. 

346 Must fit within the 32-bit integer range. 

347 

348 Returns 

349 ------- 

350 hash : `numpy.int64` 

351 The space-filling hash value associated with the 

352 given coordinates. 

353 """ 

354 return (self.i02hash(np.int32(j)) << 1) | self.i02hash(np.int32(i)) 

355 

356 def i02hash(self, i): 

357 """ 

358 Special case of ij2hash in which the discretized coordinate along 

359 the vertical axis equals zero. 

360 

361 Parameters 

362 ---------- 

363 i : `int` 

364 i discretized coordinate along the horizontal axis. 

365 Must fit within the 32-bit integer range. 

366 

367 Returns 

368 ------- 

369 hash : `numpy.int64` 

370 The space-filling hash value associated with the 

371 given coordinate. 

372 """ 

373 val1 = np.int64(self.LUPT_TO_HASH[np.uint32(i) >> np.uint32(24)] << np.int64(48)) 

374 val2 = np.int64(self.LUPT_TO_HASH[(np.uint32(i) & 0x00FF0000) >> np.uint32(16)] << np.uint64(32)) 

375 val3 = np.int64(self.LUPT_TO_HASH[(np.uint32(i) & 0x0000FF00) >> np.uint32(8)] << np.uint64(16)) 

376 val4 = np.int64(self.LUPT_TO_HASH[np.uint32(i) & 0x000000FF]) 

377 return val1 | val2 | val3 | val4 

378 

379 def hash2ij(self, h): 

380 """ 

381 Transforms the given space-filling hash value into a single value 

382 from which the 2d coordinates can be extracted using ij2i and ij2j. 

383 

384 Parameters 

385 ---------- 

386 h : `int` 

387 Space-filling hash value 

388 

389 Returns 

390 ------- 

391 ij : `np.int64` 

392 Single value from which 2d coordinates can be extracted. 

393 """ 

394 val1 = self.LUPT_TO_IJ_INT[ 

395 np.int32((np.uint64(h) 

396 & np.uint64(0xFF00000000000000)) >> np.uint64(56))] << np.int64(28) 

397 val2 = self.LUPT_TO_IJ_INT[ 

398 np.int32((np.uint64(h) 

399 & np.uint64(0x00FF000000000000)) >> np.uint64(48))] << np.int64(24) 

400 val3 = self.LUPT_TO_IJ_INT[ 

401 np.int32((np.uint64(h) 

402 & np.uint64(0x0000FF0000000000)) >> np.uint64(40))] << np.int64(20) 

403 val4 = self.LUPT_TO_IJ_INT[ 

404 np.int32((np.uint64(h) 

405 & np.uint64(0x000000FF00000000)) >> np.uint64(32))] << np.int64(16) 

406 val5 = self.LUPT_TO_IJ_INT[ 

407 np.int32((np.uint64(h) 

408 & np.uint64(0x00000000FF000000)) >> np.uint64(24))] << np.int64(12) 

409 val6 = self.LUPT_TO_IJ_INT[ 

410 np.int32((np.uint64(h) 

411 & np.uint64(0x0000000000FF0000)) >> np.uint64(16))] << np.int64(8) 

412 val7 = self.LUPT_TO_IJ_INT[ 

413 np.int32((np.uint64(h) 

414 & np.uint64(0x000000000000FF00)) >> np.uint64(8))] << np.int64(4) 

415 val8 = self.LUPT_TO_IJ_INT[ 

416 np.int32((np.uint64(h) 

417 & np.uint64(0x00000000000000FF)))] 

418 return val1 | val2 | val3 | val4 | val5 | val6 | val7 | val8 

419 

420 def hash2i0(self, _hash): 

421 """ 

422 Special case of hash2ij in which the discretized coordinate along 

423 the vertical axis is zero. 

424 

425 Parameters 

426 ---------- 

427 _hash : `int` 

428 Space-filling hash value. 

429 

430 Returns 

431 ------- 

432 ij : `np.int64` 

433 Single value from which 2d coordinates can be extracted. 

434 """ 

435 assert (0xFFFFFFFF33333333 & np.int64(_hash)) == 0 

436 return self.hash2ij(_hash) 

437 

438 def ij2i(self, ij): 

439 """ 

440 Extract the discretized horizontal coordinate from hash2ij. 

441 

442 Parameters 

443 ---------- 

444 ij : `int` 

445 The ij result of hash2ij. 

446 

447 Returns 

448 ------- 

449 i : `np.int32` 

450 Discretized horizontal coordinate stored in ij. 

451 """ 

452 return np.int32(ij) 

453 

454 def ij2j(self, ij): 

455 """ 

456 Extract the discretized vertical coordinate from hash2ij. 

457 

458 Parameters 

459 ---------- 

460 ij : `int` 

461 The ij result of hash2ij. 

462 

463 Returns 

464 ------- 

465 j : `np.int32` 

466 Discretized vertical coordinate stored in ij. 

467 """ 

468 return np.int32(np.uint64(ij) >> np.uint64(32))