1111import pprint
1212import tarfile
1313import zipfile
14+ from collections .abc import Iterable
15+ from datetime import datetime
16+
1417from astropy import units
1518from astropy import units as u
1619from astropy .coordinates import Angle
1720from astropy .units import Quantity
18- from collections .abc import Iterable
19- from datetime import datetime
2021from requests .exceptions import HTTPError
2122
2223from astroquery import log
@@ -43,7 +44,7 @@ class EuclidClass(TapPlus):
4344 __VALID_DATALINK_RETRIEVAL_TYPES = conf .VALID_DATALINK_RETRIEVAL_TYPES
4445
4546 def __init__ (self , * , environment = 'PDR' , tap_plus_conn_handler = None , datalink_handler = None , cutout_handler = None ,
46- verbose = False , show_server_messages = True ):
47+ sia_handler = None , verbose = False , show_server_messages = True ):
4748 """Constructor for EuclidClass.
4849
4950 Parameters
@@ -56,6 +57,8 @@ def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_ha
5657 HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
5758 cutout_handler : cutout connection handler object, optional, default None
5859 HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
60+ sia_handler : siap connection handler object, optional, default None
61+ HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
5962 verbose : bool, optional, default 'True'
6063 flag to display information about the process
6164 show_server_messages : bool, optional, default 'True'
@@ -70,6 +73,9 @@ def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_ha
7073 self .main_table = conf .ENVIRONMENTS [self .environment ]['main_table' ]
7174 self .main_table_ra = conf .ENVIRONMENTS [self .environment ]['main_table_ra_column' ]
7275 self .main_table_dec = conf .ENVIRONMENTS [self .environment ]['main_table_dec_column' ]
76+ self .dsr_1 = conf .ENVIRONMENTS [self .environment ]['data_set_release_part1' ]
77+ self .dsr_2 = conf .ENVIRONMENTS [self .environment ]['data_set_release_part2' ]
78+ self .dsr_3 = conf .ENVIRONMENTS [self .environment ]['data_set_release_part3' ]
7379
7480 url_server = conf .ENVIRONMENTS [environment ]['url_server' ]
7581
@@ -113,6 +119,20 @@ def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_ha
113119 else :
114120 self .__euclidcutout = cutout_handler
115121
122+ if sia_handler is None :
123+ self .__euclidsia = TapPlus (url = url_server ,
124+ server_context = "sas-sia" ,
125+ tap_context = "tap-server" ,
126+ upload_context = "Upload" ,
127+ table_edit_context = "TableTool" ,
128+ data_context = "sia2/query" ,
129+ datalink_context = "datalink" ,
130+ verbose = verbose ,
131+ client_id = 'ASTROQUERY' ,
132+ use_names_over_ids = conf .USE_NAMES_OVER_IDS )
133+ else :
134+ self .__euclidsia = sia_handler
135+
116136 if show_server_messages :
117137 self .get_status_messages ()
118138
@@ -632,6 +652,8 @@ def login(self, *, user=None, password=None, credentials_file=None, verbose=Fals
632652 self .__eucliddata .login (user = tap_user , password = tap_password , verbose = verbose )
633653 log .info (f"Login to Euclid cutout service: { self .__euclidcutout ._TapPlus__getconnhandler ().get_host_url ()} " )
634654 self .__euclidcutout .login (user = tap_user , password = tap_password , verbose = verbose )
655+ log .info (f"Login to Euclid sia service: { self .__euclidsia ._TapPlus__getconnhandler ().get_host_url ()} " )
656+ self .__euclidsia .login (user = tap_user , password = tap_password , verbose = verbose )
635657 except HTTPError as err :
636658 log .error ('Error logging in data or cutout services: %s' % (str (err )))
637659 log .error ("Logging out from TAP server" )
@@ -676,6 +698,14 @@ def login_gui(self, verbose=False):
676698 log .error ("Logging out from TAP server" )
677699 TapPlus .logout (self , verbose = verbose )
678700
701+ try :
702+ log .info (f"Login to Euclid sia server: { self .__euclidsia ._TapPlus__getconnhandler ().get_host_url ()} " )
703+ self .__euclidsia .login (user = tap_user , password = tap_password , verbose = verbose )
704+ except HTTPError as err :
705+ log .error ('Error logging in sia server: %s' % (str (err )))
706+ log .error ("Logging out from TAP server" )
707+ TapPlus .logout (self , verbose = verbose )
708+
679709 def logout (self , verbose = False ):
680710 """
681711 Performs a logout
@@ -711,6 +741,12 @@ def logout(self, verbose=False):
711741 except HTTPError as err :
712742 log .error ('Error logging out cutout server: %s' % (str (err )))
713743
744+ try :
745+ self .__euclidsia .logout (verbose = verbose )
746+ log .info ("Euclid sia server logout OK" )
747+ except HTTPError as err :
748+ log .error ('Error logging out sia server: %s' % (str (err )))
749+
714750 @staticmethod
715751 def __get_quantity_input (value , msg ):
716752 if value is None :
@@ -1235,6 +1271,113 @@ def get_product(self, *, file_name=None, product_id=None, schema='sedm', output_
12351271
12361272 return files
12371273
1274+ def get_sia (self , * , search_type = 'CIRCLE' , ra , dec , radius , calibration = 2 , instrument = 'ALL' , band = None ,
1275+ collection = 'sedm' , dsr_part1 = None , dsr_part2 = None , dsr_part3 = None , output_file = None , verbose = False ):
1276+ """
1277+ Description
1278+ -----------
1279+
1280+ Access the Euclid Observation Images by VO SIAP v2.0. This service will return public images from Calibrated
1281+ and Stacked NISP and VIS images, MER Mosaics from VIS and NISP and Level 1 (RAW) images for NISP and VIS
1282+
1283+ Parameters
1284+ ----------
1285+ search_type : str, mandatory, default None
1286+ search region: CIRCLE or BOX
1287+ ra : float (degrees), str or astropy.coordinate, mandatory
1288+ right ascension
1289+ dec : float (degrees), str or astropy.coordinate, mandatory
1290+ declination
1291+ radius : float (degrees), str or astropy.coordinate, mandatory
1292+ search radius of the cutout to generate
1293+ calibration: int, optional, default 2
1294+ calibration level according to ObsCore VO standard: 0 (raw instrumental data), 1 (instrumental data in a
1295+ standard format), 2 (science ready data) or 3 (enhanced data products).
1296+ instrument: str, mandatory, default ALL
1297+ instrument name: ALL, VIS or NISP
1298+ band: str, optional, default None
1299+ filter name only valid if instrument is different from ALL: VIS for instrument VIS or NIR_H, NIR_J, NIR_Y
1300+ or NISP for instrument NISP
1301+ collection : str, mandatory, default sedm
1302+ the name of the data collection
1303+ dsr_part1: str, optional, default None
1304+ the data set release part 1: for OTF environment, the activity code; for REG and IDR, the target environment
1305+ dsr_part2: str, optional, default None
1306+ the data set release part 2: for OTF environment, the patch id (a positive integer); for REG and IDR,
1307+ the activity code
1308+ dsr_part3: str, optional, default None
1309+ the data set release part 3: for OTF, REG and IDR environment, the version (a integer greater than 1)
1310+ output_file : string, optional, default None
1311+ file where the results are saved.
1312+ verbose : bool, optional, default 'False'
1313+ flag to display information about the process
1314+
1315+ Returns
1316+ -------
1317+ A table object or votable file
1318+ """
1319+
1320+ valid_search_types = {'CIRCLE' , 'BOX' }
1321+ valid_calibrations = {0 : 'CALIB_ZERO' , 1 : 'CALIB_ONE' , 2 : 'CALIB_TWO' , 3 : 'CALIB_THREE' }
1322+ valid_instruments = {'ALL' , 'VIS' , 'NISP' }
1323+ valid_band_vis = {'VIS' }
1324+ valid_band_nisp = {'NIR_H' , 'NIR_J' , 'NIR_Y' , 'NISP' }
1325+
1326+ if search_type not in valid_search_types :
1327+ raise ValueError (f"Invalid search tyype { search_type } " )
1328+
1329+ if calibration is not None and calibration not in valid_calibrations :
1330+ raise ValueError (f"Invalid calibration { calibration } " )
1331+
1332+ if instrument not in valid_instruments :
1333+ raise ValueError (f"Invalid instrument { instrument } " )
1334+
1335+ if instrument == 'ALL' and band is not None :
1336+ raise ValueError (f"For instrument { instrument } band must be None" )
1337+
1338+ if instrument == 'VIS' and band is not None and band not in valid_band_vis :
1339+ raise ValueError (f"Invalid band { band } for instrument { instrument } " )
1340+
1341+ if instrument == 'NISP' and band is not None and band not in valid_band_nisp :
1342+ raise ValueError (f"Invalid band { band } for instrument { instrument } " )
1343+
1344+ ra_deg = self .coordinates_degrees (ra )
1345+ dec_deg = self .coordinates_degrees (dec )
1346+ radius_deg = self .coordinates_degrees (radius )
1347+
1348+ params_dict = dict ()
1349+ params_dict ['TAPCLIENT' ] = 'ASTROQUERY'
1350+ params_dict [
1351+ 'POS' ] = f"{ search_type } ,{ ra_deg .to_value (u .deg )} ,{ dec_deg .to_value (u .deg )} ,{ radius_deg .to_value (u .deg )} "
1352+ params_dict ['INSTRUMENT' ] = instrument
1353+ params_dict ['COLLECTION' ] = collection
1354+
1355+ if calibration is not None :
1356+ params_dict ['CALIB' ] = valid_calibrations [calibration ]
1357+
1358+ if instrument != 'ALL' and band is not None :
1359+ params_dict ['BAND' ] = band
1360+
1361+ if dsr_part1 is not None :
1362+ params_dict ['DSP1' ] = dsr_part1
1363+
1364+ if dsr_part2 is not None :
1365+ params_dict ['DSP2' ] = dsr_part2
1366+
1367+ if dsr_part3 is not None :
1368+ params_dict ['DSP3' ] = dsr_part3
1369+
1370+ return self .__euclidsia .load_data (params_dict = params_dict , output_file = output_file , http_method = 'GET' ,
1371+ verbose = verbose )
1372+
1373+ def coordinates_degrees (self , coord ):
1374+
1375+ if not isinstance (coord , units .Quantity ):
1376+ radius_quantity = Quantity (value = coord , unit = u .deg )
1377+ else :
1378+ radius_quantity = coord .to (u .deg )
1379+ return radius_quantity
1380+
12381381 def get_cutout (self , * , file_path = None , instrument = None , id = None , coordinate , radius , output_file = None ,
12391382 verbose = False ):
12401383 """
0 commit comments