26
26
from six import BytesIO
27
27
import shutil
28
28
import os
29
+ import json
29
30
30
31
from . import conf
31
32
from astroquery import log
@@ -40,6 +41,7 @@ class ESAHubbleClass(BaseQuery):
40
41
41
42
data_url = conf .DATA_ACTION
42
43
metadata_url = conf .METADATA_ACTION
44
+ target_url = conf .TARGET_ACTION
43
45
TIMEOUT = conf .TIMEOUT
44
46
calibration_levels = {0 : "AUXILIARY" , 1 : "RAW" , 2 : "CALIBRATED" ,
45
47
3 : "PRODUCT" }
@@ -215,7 +217,8 @@ def get_postcard(self, observation_id, calibration_level="RAW",
215
217
shutil .move (response , filename )
216
218
217
219
def cone_search (self , coordinates , radius = 0.0 , filename = None ,
218
- output_format = 'votable' , save = False , cache = True ):
220
+ output_format = 'votable' , async_job = False ,
221
+ cache = True , verbose = False ):
219
222
"""
220
223
To execute a cone search defined by a coordinate and a radius
221
224
@@ -233,14 +236,14 @@ def cone_search(self, coordinates, radius=0.0, filename=None,
233
236
results format. Options are:
234
237
'votable': str, binary VOTable format
235
238
'csv': str, comma-separated values format
236
- save : bool
237
- optional, default 'False'
238
- Flag to save the result in a file. If the filename
239
- is not defined, it will use a formatted name to save
240
- the file
239
+ async_job : bool, optional, default 'False'
240
+ executes the query (job) in asynchronous/synchronous mode (default
241
+ synchronous)
241
242
cache : bool
242
243
optional, default 'True'
243
244
Flag to save the results in the local cache
245
+ verbose : bool, optional, default 'False'
246
+ flag to display information about the process
244
247
245
248
Returns
246
249
-------
@@ -251,50 +254,158 @@ def cone_search(self, coordinates, radius=0.0, filename=None,
251
254
252
255
ra_hours , dec = commons .coord_to_radec (coord )
253
256
ra = ra_hours * 15.0 # Converts to degrees
254
- payload = {"RESOURCE_CLASS" : "OBSERVATION" ,
255
- "ADQLQUERY" : "SELECT DISTINCT OBSERVATION,OBSERVATION.TYPE,"
256
- "TARGET.MOVING_TARGET"
257
- ",TARGET.TARGET_NAME,TARGET.TARGET_DESCRIPTION,PROPOSAL."
258
- "PROPOSAL_ID,PROPOSAL.PI_"
259
- "NAME,PROPOSAL.PROPOSAL_TITLE,INSTRUMENT.INSTRUMENT_NAME,"
260
- "PLANE.METADATA_PROVENANCE"
261
- ",PLANE.DATA_PRODUCT_TYPE,PLANE.SOFTWARE_VERSION,POSITION"
262
- ".RA,POSITION.DEC,POSITION."
263
- "GAL_LAT,POSITION.GAL_LON,POSITION.ECL_LAT,POSITION.ECL_LON"
264
- ",POSITION.FOV_SIZE,ENERGY."
265
- "WAVE_CENTRAL,ENERGY.WAVE_BANDWIDTH,ENERGY.WAVE_MAX,ENERGY"
266
- ".WAVE_MIN,ENERGY.FILTER FROM"
267
- " FIELD_NOT_USED WHERE OBSERVATION.COLLECTION='HST' AND "
268
- "PLANE.MAIN_SCIENCE_PLANE="
269
- "'true' AND (OBSERVATION.TYPE='HST Composite' OR "
270
- "OBSERVATION.TYPE='HST Singleton')"
271
- " AND INTERSECTS(CIRCLE('ICRS', {0}, {1}, {2}"
272
- "),POSITION)=1 AND PLANE.MAIN_SCIENCE_PLANE='true' "
273
- "ORDER BY PROPOSAL.PROPOSAL_ID "
274
- "DESC" .format (str (ra ), str (dec ), str (radius_in_grades )),
275
- "RETURN_TYPE" : str (output_format )}
276
- response = self ._request ('GET' ,
277
- self .metadata_url ,
278
- params = payload ,
279
- save = save or filename is not None ,
280
- cache = cache ,
281
- timeout = self .TIMEOUT )
282
- if response is None :
283
- table = None
257
+
258
+ query = "select o.observation_id, " \
259
+ "o.start_time, o.end_time, o.start_time_mjd, " \
260
+ "o.end_time_mjd, o.exposure_duration, o.release_date, " \
261
+ "o.run_id, o.program_id, o.set_id, o.collection, " \
262
+ "o.members_number, o.instrument_configuration, " \
263
+ "o.instrument_name, o.obs_type, o.target_moving, " \
264
+ "o.target_name, o.target_description, o.proposal_id, " \
265
+ "o.pi_name, prop.title, pl.metadata_provenance, " \
266
+ "pl.data_product_type, pl.software_version, pos.ra, " \
267
+ "pos.dec, pos.gal_lat, pos.gal_lon, pos.ecl_lat, " \
268
+ "pos.ecl_lon, pos.fov_size, en.wave_central, " \
269
+ "en.wave_bandwidth, en.wave_max, en.wave_min, " \
270
+ "en.filter from ehst.observation o join ehst.proposal " \
271
+ "prop on o.proposal_id=prop.proposal_id join ehst.plane " \
272
+ "pl on pl.observation_id=o.observation_id join " \
273
+ "ehst.position pos on pos.plane_id = pl.plane_id join " \
274
+ "ehst.energy en on en.plane_id=pl.plane_id where " \
275
+ "pl.main_science_plane='true' and 1=CONTAINS(POINT('ICRS', " \
276
+ "pos.ra, pos.dec),CIRCLE('ICRS', {0}, {1}, {2})) order " \
277
+ "by prop.proposal_id desc" .format (str (ra ), str (dec ),
278
+ str (radius_in_grades ))
279
+ if verbose :
280
+ log .info (query )
281
+ table = self .query_hst_tap (query = query , async_job = async_job ,
282
+ output_file = filename ,
283
+ output_format = output_format ,
284
+ verbose = verbose )
285
+ return table
286
+
287
+ def cone_search_criteria (self , target = None , coordinates = None ,
288
+ radius = 0.0 ,
289
+ calibration_level = None ,
290
+ data_product_type = None ,
291
+ intent = None ,
292
+ obs_collection = None ,
293
+ instrument_name = None ,
294
+ filters = None ,
295
+ async_job = True ,
296
+ filename = None ,
297
+ output_format = 'votable' ,
298
+ save = False ,
299
+ cache = True ,
300
+ verbose = False ):
301
+ """
302
+ To execute a cone search defined by a coordinate (an
303
+ astropy.coordinate element or a target name which is resolved),
304
+ a radius and a set of criteria to filter the results. This function
305
+ comprises the outputs of query_target, cone_search and query_criteria
306
+ methods.
307
+
308
+ Parameters
309
+ ----------
310
+ coordinates : astropy.coordinate, mandatory
311
+ coordinates of the center in the cone search
312
+ radius : float, default 0
313
+ radius in arcmin of the cone_search
314
+ calibration_level : str or int, optional
315
+ The identifier of the data reduction/processing applied to the
316
+ data. RAW (1), CALIBRATED (2), PRODUCT (3) or AUXILIARY (0)
317
+ data_product_type : str, optional
318
+ High level description of the product.
319
+ image, spectrum or timeseries.
320
+ intent : str, optional
321
+ The intent of the original observer in acquiring this observation.
322
+ SCIENCE or CALIBRATION
323
+ collection : list of str, optional
324
+ List of collections that are available in eHST catalogue.
325
+ HLA, HST
326
+ instrument_name : list of str, optional
327
+ Name(s) of the instrument(s) used to generate the dataset
328
+ filters : list of str, optional
329
+ Name(s) of the filter(s) used to generate the dataset
330
+ async_job : bool, optional, default 'False'
331
+ executes the query (job) in asynchronous/synchronous mode (default
332
+ synchronous)
333
+ filename : str, default None
334
+ Path and name of the file to store the results.
335
+ If the filename is defined, the file will be
336
+ automatically saved
337
+ output_format : string
338
+ results format. Options are:
339
+ 'votable': str, binary VOTable format
340
+ 'csv': str, comma-separated values format
341
+ save : bool
342
+ optional, default 'False'
343
+ Flag to save the result in a file. If the filename
344
+ is not defined, it will use a formatted name to save
345
+ the file
346
+ cache : bool
347
+ optional, default 'True'
348
+ Flag to save the results in the local cache
349
+ verbose : bool, optional, default 'False'
350
+ flag to display information about the process
351
+
352
+ Returns
353
+ -------
354
+ astropy.table.Table with the result of the cone_search
355
+ """
356
+ crit_query = self .query_criteria (calibration_level = calibration_level ,
357
+ data_product_type = data_product_type ,
358
+ intent = intent ,
359
+ obs_collection = obs_collection ,
360
+ instrument_name = instrument_name ,
361
+ filters = filters ,
362
+ async_job = True ,
363
+ get_query = True )
364
+ if crit_query .endswith (")" ):
365
+ crit_query = crit_query [:- 1 ] + " AND "
284
366
else :
285
- if save or filename is not None :
286
- if filename is None :
287
- filename = "cone." + str (output_format )
288
- shutil .move (response , filename )
289
- table = Table .read (filename , format = output_format )
290
- log .info ("File has been saved in " + os .path .abspath (filename ))
291
- else :
292
- fileobj = BytesIO (response .content )
293
- table = Table .read (fileobj , format = output_format )
294
- # TODO: add "correct units" material here
367
+ crit_query = crit_query + " WHERE ("
368
+
369
+ if (target and coordinates ):
370
+ raise TypeError ("Please use only target or coordinates as"
371
+ "parameter." )
372
+ if (target ):
373
+ try :
374
+ ra , dec = self ._query_tap_target (target )
375
+ except Exception :
376
+ raise ValueError ('This target cannot be resolved' )
377
+ else :
378
+ coord = self ._getCoordInput (coordinates , "coordinate" )
379
+ ra_hours , dec = commons .coord_to_radec (coord )
380
+ ra = ra_hours * 15.0 # Converts to degrees
381
+
382
+ radius_in_grades = float (radius / 60 ) # Converts to degrees
383
+ cone_query = "1=CONTAINS(POINT('ICRS', pos.ra, pos.dec)," \
384
+ "CIRCLE('ICRS', {0}, {1}, {2}))" .\
385
+ format (str (ra ), str (dec ), str (radius_in_grades ))
386
+ query = "{}{})" .format (crit_query , cone_query )
387
+ if verbose :
388
+ log .info (query )
295
389
390
+ table = self .query_hst_tap (query = query , async_job = async_job ,
391
+ output_file = filename ,
392
+ output_format = output_format ,
393
+ verbose = verbose )
296
394
return table
297
395
396
+ def _query_tap_target (self , target ):
397
+ params = {"TARGET_NAME" : target ,
398
+ "RESOLVER_TYPE" : "SN" ,
399
+ "FORMAT" : "json" }
400
+ target_response = self ._request ('GET' ,
401
+ self .target_url ,
402
+ cache = True ,
403
+ params = params )
404
+ target_result = target_response .json ()['data' ][0 ]
405
+ ra = target_result ['RA_DEGREES' ]
406
+ dec = target_result ['DEC_DEGREES' ]
407
+ return ra , dec
408
+
298
409
def query_metadata (self , output_format = 'votable' , verbose = False ):
299
410
return
300
411
@@ -456,9 +567,10 @@ def query_criteria(self, calibration_level=None,
456
567
parameters .append ("(o.instrument_configuration LIKE '%{}%')"
457
568
.format ("%' OR o.instrument_configuration "
458
569
"LIKE '%" .join (filters )))
459
- query = "select o.*, p.calibration_level, p.data_product_type " \
460
- "from ehst.observation AS o LEFT JOIN ehst.plane as p " \
461
- "on o.observation_uuid=p.observation_uuid"
570
+ query = "select o.*, p.calibration_level, p.data_product_type, " \
571
+ "pos.ra, pos.dec from ehst.observation AS o JOIN " \
572
+ "ehst.plane as p on o.observation_uuid=p.observation_uuid " \
573
+ "JOIN ehst.position as pos on p.plane_id = pos.plane_id"
462
574
if parameters :
463
575
query += " where({})" .format (" AND " .join (parameters ))
464
576
table = self .query_hst_tap (query = query , async_job = async_job ,
0 commit comments