1- import shutil
2- import zipfile
31import numpy as np
4- import pandas as pd
52from pathlib import Path
63
7- from astropy import wcs
84import astropy .units as u
95from astropy .io import fits
6+ from astropy .wcs import WCS
7+ from astropy .nddata import Cutout2D
108from astropy .coordinates import SkyCoord
119
12- from pyvo .dal import sia
1310from astroquery .esa .hubble import ESAHubble # HST
1411
1512from hostphot ._constants import workdir
16- from hostphot .utils import check_work_dir
17- from hostphot .surveys_utils import check_HST_filters
13+ from hostphot .utils import check_work_dir , suppress_stdout
14+ from hostphot .surveys_utils import check_HST_filters , survey_pixel_scale
1815
1916import warnings
2017from astropy .utils .exceptions import AstropyWarning
@@ -34,7 +31,7 @@ def update_HST_header(hdu: fits.hdu.ImageHDU) -> None:
3431 warnings .simplefilter ("ignore" , AstropyWarning )
3532 if "PHOTPLAM" not in hdu [0 ].header :
3633 # MAST image: move things to hdu[0] to homogenise
37- img_wcs = wcs . WCS (hdu [1 ].header )
34+ img_wcs = WCS (hdu [1 ].header )
3835 hdu [0 ].header .update (img_wcs .to_header ())
3936 hdu [0 ].header ["PHOTFLAM" ] = hdu [1 ].header ["PHOTFLAM" ]
4037 hdu [0 ].header ["PHOTPLAM" ] = hdu [1 ].header ["PHOTPLAM" ]
@@ -66,6 +63,7 @@ def set_HST_image(file: str, filt: str, name: str) -> None:
6663 """
6764 # check output directory
6865 check_work_dir (workdir )
66+ check_HST_filters (filt )
6967 obj_dir = Path (workdir , name , "HST" )
7068 if obj_dir .is_dir () is False :
7169 obj_dir .mkdir (parents = True , exist_ok = True )
@@ -76,36 +74,24 @@ def set_HST_image(file: str, filt: str, name: str) -> None:
7674 hdu .writeto (outfile , overwrite = True )
7775
7876def get_HST_images (ra : float , dec : float , size : float | u .Quantity = 3 ,
79- filt : str = "WFC3_UVIS_F225W" ) -> list [fits .ImageHDU ]:
77+ filters : list = [ "WFC3_UVIS_F225W" ] ) -> list [fits .ImageHDU ]:
8078 """Downloads a set of HST fits images for a given set
81- of coordinates and filters using the MAST archive .
79+ of coordinates and filters using astroquery .
8280
8381 Parameters
8482 ----------
8583 ra: Right ascension in degrees.
8684 dec: Declination in degrees.
8785 size: Image size. If a float is given, the units are assumed to be arcmin.
88- filt: Filter to use, e.g. ``WFC3_UVIS_F225W``.
86+ filters: Filters to use, e.g. ``WFC3_UVIS_F225W``.
8987
9088 Return
9189 ------
9290 hdu_list: List with fits image for the given filter. ``None`` is returned if no image is found.
9391 """
9492 esahubble = ESAHubble ()
9593 esahubble .get_status_messages ()
96- check_HST_filters (filt )
97-
98- # separate the instrument name from the actual filter
99- split_filt = filt .split ("_" )
100- if len (split_filt ) == 2 :
101- filt = split_filt [- 1 ]
102- instrument = split_filt [0 ]
103- elif len (split_filt ) == 3 :
104- filt = split_filt [- 1 ]
105- instrument = f"{ split_filt [0 ]} /{ split_filt [1 ]} "
106- else :
107- raise ValueError (f"Incorrect filter name: { filt } " )
108-
94+
10995 if isinstance (size , (float , int )):
11096 size_arcsec = (size * u .arcmin ).to (u .arcsec )
11197 else :
@@ -116,43 +102,43 @@ def get_HST_images(ra: float, dec: float, size: float | u.Quantity = 3,
116102 coords = SkyCoord (
117103 ra = ra , dec = dec , unit = (u .degree , u .degree ), frame = "icrs"
118104 )
119-
120- version = None
121- if version == "HLA" :
122- # This does not seem to be faster
123- fov = 0.2 # field-of-view in degrees
124- access_url = " https://hla.stsci.edu/cgi-bin/hlaSIAP.cgi"
125- svc = sia .SIAService (access_url )
126- imgs_table = svc .search (
127- (ra , dec ), (fov / np .cos (dec * np .pi / 180 ), fov ), verbosity = 2
128- )
129- obs_df = pd .DataFrame (imgs_table )
130- obs_df = obs_df [obs_df .Mode == "IMAGE" ]
131- obs_df = obs_df [obs_df .Format .str .endswith ("fits" )]
132- obs_df = obs_df [obs_df .Detector == instrument ]
133- obs_df = obs_df [obs_df .Spectral_Elt == filt ]
134- obs_df = obs_df [obs_df .ExpTime == obs_df .ExpTime .max ()]
135- hdu = fits .open (obs_df .URL .values [0 ])
136- else :
105+
106+ # query observations at the given coordinates
107+ with suppress_stdout ():
137108 result = esahubble .cone_search_criteria (
138109 radius = 3 ,
139110 coordinates = coords ,
140111 calibration_level = "PRODUCT" ,
141112 data_product_type = "image" ,
142- instrument_name = instrument ,
143- filters = filt ,
113+ # instrument_name=instrument,
114+ # filters=filt,
144115 async_job = True ,
145116 )
146-
147- obs_df = result .to_pandas ()
148- obs_df = obs_df [obs_df ["filter" ] == filt ]
117+ results_df = result .to_pandas ()
118+
119+ hdu_list = []
120+ for filt in filters :
121+ check_HST_filters (filt )
122+ # separate the instrument name from the actual filter
123+ split_filt = filt .split ("_" )
124+ if len (split_filt ) == 2 :
125+ filt = split_filt [- 1 ]
126+ instrument = split_filt [0 ]
127+ elif len (split_filt ) == 3 :
128+ filt = split_filt [- 1 ]
129+ instrument = f"{ split_filt [0 ]} /{ split_filt [1 ]} "
130+ else :
131+ raise ValueError (f"Incorrect filter name: { filt } " )
132+ # filter by filter and instrument
133+ obs_df = results_df [results_df ["filter" ] == filt ]
134+ obs_df = obs_df [obs_df .instrument_name == instrument ]
149135 # get only exposures shorter than one hour
150136 obs_df = obs_df [obs_df .exposure_duration < 3600 ]
151137 obs_df .sort_values (
152138 by = ["exposure_duration" ], ascending = False , inplace = True
153139 )
154140
155- print ( "Looking for HST images..." )
141+ # start download
156142 filename = f"HST_tmp_{ ra } _{ dec } " # the extension is added below
157143 for obs_id in obs_df .observation_id :
158144 try :
@@ -167,14 +153,24 @@ def get_HST_images(ra: float, dec: float, size: float | u.Quantity = 3,
167153 pass
168154 temp_file = Path (f"{ filename } .fits.gz" )
169155 if temp_file .is_file () is False :
170- return None
171- temp_dir = Path (filename ) # same name as the extensionless file above
172- with zipfile .ZipFile (temp_file , "r" ) as zip_ref :
173- zip_ref .extractall (temp_dir )
174- fits_file = [file for file in temp_dir .rglob ("*.gz" )][0 ]
175- hdu = fits .open (fits_file )
176- # remove the temporary files and directory
156+ hdu_list .append (None )
157+ continue
158+ hdu = fits .open (temp_file )
159+ # remove the temporary files
177160 temp_file .unlink ()
178- shutil .rmtree (temp_dir , ignore_errors = True )
179- update_HST_header (hdu )
180- return [hdu ]
161+ # add necessary information to the header
162+ update_HST_header (hdu )
163+ hdu_list .append (hdu )
164+ # HST images are large so need to be trimmed
165+ for hdu , filt in zip (hdu_list , filters ):
166+ if hdu is None :
167+ continue
168+ pixel_scale = survey_pixel_scale ("HST" , filt ) # same pixel scale for all filters
169+ size_pixels = int (size_arcsec / pixel_scale )
170+ with warnings .catch_warnings ():
171+ warnings .simplefilter ("ignore" , AstropyWarning )
172+ img_wcs = WCS (hdu [0 ].header )
173+ trimmed_data = Cutout2D (hdu [0 ].data , coords , size_pixels , img_wcs )
174+ hdu [0 ].data = trimmed_data .data
175+ hdu [0 ].header .update (trimmed_data .wcs .to_header ())
176+ return hdu_list
0 commit comments