Skip to content

Commit 1bb557a

Browse files
committed
Added initial dask class to represent HiPS datasets
1 parent 684c8ca commit 1bb557a

File tree

3 files changed

+116
-15
lines changed

3 files changed

+116
-15
lines changed

reproject/hips/dask_array.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import os
2+
import urllib
3+
4+
import numpy as np
5+
from astropy.io import fits
6+
from astropy.wcs import WCS
7+
from astropy_healpix import HEALPix, level_to_nside
8+
9+
from .utils import is_url, load_properties, tile_filename
10+
11+
12+
class HiPSArray:
13+
14+
def __init__(self, directory_or_url, level=None):
15+
16+
self._directory_or_url = directory_or_url
17+
18+
self._is_url = is_url(directory_or_url)
19+
20+
self._properties = load_properties(directory_or_url)
21+
22+
self._tile_size = int(self._properties["hips_tile_width"])
23+
self._order = int(self._properties["hips_order"])
24+
self._level = self._order if level is None else level
25+
26+
self._tile_format = self._properties["hips_tile_format"]
27+
28+
self._nside = level_to_nside(self._level)
29+
self._hp = HEALPix(nside=self._nside, frame="icrs", order="nested")
30+
self._cdelt = 45 / self._tile_size / 2**self._level * 2**0.5
31+
32+
image_size = 5 * self._nside * self._tile_size
33+
34+
self.wcs = WCS(naxis=2)
35+
self.wcs.wcs.ctype = "RA---HPX", "DEC--HPX"
36+
self.wcs.wcs.crval = 0, 0
37+
self.wcs.wcs.cdelt = self._cdelt, self._cdelt
38+
self.wcs.wcs.crpix = image_size / 2, image_size / 2
39+
self.wcs.wcs.crota = 0, 45
40+
self.wcs.wcs.set()
41+
42+
self.shape = (image_size, image_size)
43+
self.dtype = float
44+
self.ndim = 2
45+
46+
self.chunksize = (self._tile_size, self._tile_size)
47+
48+
self._nan = np.nan * np.ones(self.chunksize, dtype=self.dtype)
49+
50+
def __getitem__(self, item):
51+
52+
# For now assume item is a list of slices. Find
53+
54+
imid = (item[0].start + item[0].stop) // 2
55+
jmid = (item[1].start + item[1].stop) // 2
56+
57+
# Convert pixel coordinates to HEALPix indices
58+
59+
index = self._hp.skycoord_to_healpix(self.wcs.pixel_to_world(imid, jmid))
60+
61+
if index == -1:
62+
return self._nan
63+
64+
return self._get_tile(level=self._level, index=index)
65+
66+
def _get_tile(self, *, level, index):
67+
68+
filename = tile_filename(
69+
level=self._level,
70+
index=index,
71+
output_directory=self._directory_or_url,
72+
extension="fits",
73+
)
74+
75+
if self._is_url:
76+
try:
77+
return fits.getdata(filename).astype(float)[::-1]
78+
except urllib.error.HTTPError:
79+
return self._nan
80+
else:
81+
if os.path.exists(filename):
82+
# FIXME: why flip vertically?
83+
return fits.getdata(filename).astype(float)[::-1]
84+
else:
85+
return self._nan

reproject/hips/high_level.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
from ..wcs_utils import has_celestial
2222
from .utils import (
2323
determine_healpix_level,
24+
load_properties,
2425
make_tile_folders,
26+
save_properties,
2527
tile_filename,
2628
tile_header,
2729
)
@@ -401,21 +403,6 @@ def save_index(directory):
401403
f.write(INDEX_HTML)
402404

403405

404-
def save_properties(directory, properties):
405-
with open(os.path.join(directory, "properties"), "w") as f:
406-
for key, value in properties.items():
407-
f.write(f"{key:20s} = {value}\n")
408-
409-
410-
def load_properties(directory):
411-
properties = {}
412-
with open(os.path.join(directory, "properties")) as f:
413-
for line in f:
414-
key, value = line.split("=")
415-
properties[key.strip()] = value.strip()
416-
return properties
417-
418-
419406
def coadd_hips(input_directories, output_directory):
420407
"""
421408
Given multiple HiPS directories, combine these into a single HiPS.

reproject/hips/utils.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import urllib
23

34
import numpy as np
45
from astropy.wcs import WCS
@@ -103,3 +104,31 @@ def determine_healpix_level(wcs_in, tile_size):
103104
target_level = nside_to_level(target_nside)
104105

105106
return target_level
107+
108+
109+
def _is_url(directory):
110+
return directory.startswith("http://") or directory.startswith("https://")
111+
112+
113+
def save_properties(directory, properties):
114+
with open(os.path.join(directory, "properties"), "w") as f:
115+
for key, value in properties.items():
116+
f.write(f"{key:20s} = {value}\n")
117+
118+
119+
def load_properties(directory_or_url):
120+
121+
if _is_url(directory_or_url):
122+
properties_filename, _ = urllib.request.urlretrieve(f"{directory_or_url}/properties")
123+
else:
124+
properties_filename = os.path.join(directory_or_url, "properties")
125+
126+
properties = {}
127+
with open(properties_filename) as f:
128+
for line in f:
129+
if line.startswith("#"):
130+
continue
131+
key, value = line.split("=", 1)
132+
properties[key.strip()] = value.strip()
133+
134+
return properties

0 commit comments

Comments
 (0)