@@ -47,19 +47,21 @@ class EuclidClass(TapPlus):
4747 __VALID_LINKING_PARAMETERS = conf .VALID_LINKING_PARAMETERS
4848
4949 def __init__ (self , * , environment = 'PDR' , tap_plus_conn_handler = None , datalink_handler = None , cutout_handler = None ,
50- verbose = False , show_server_messages = True ):
50+ sia_handler = None , verbose = False , show_server_messages = True ):
5151 """Constructor for EuclidClass.
5252
5353 Parameters
5454 ----------
5555 environment : str, mandatory if no tap, data or cutout hosts is specified, default 'PDR'
5656 The Euclid Science Archive environment: 'PDR', 'IDR', 'OTF' and 'REG'
5757 tap_plus_conn_handler : tap connection handler object, optional, default None
58- HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
59- datalink_handler : dataliink connection handler object, optional, default None
60- HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
58+ HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
59+ datalink_handler : datalink connection handler object, optional, default None
60+ HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
6161 cutout_handler : cutout connection handler object, optional, default None
62- HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
62+ HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
63+ sia_handler : siap connection handler object, optional, default None
64+ HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
6365 verbose : bool, optional, default 'True'
6466 flag to display information about the process
6567 show_server_messages : bool, optional, default 'True'
@@ -120,6 +122,20 @@ def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_ha
120122 else :
121123 self .__euclidcutout = cutout_handler
122124
125+ if sia_handler is None :
126+ self .__euclidsia = TapPlus (url = url_server ,
127+ server_context = "sas-sia" ,
128+ tap_context = "tap-server" ,
129+ upload_context = "Upload" ,
130+ table_edit_context = "TableTool" ,
131+ data_context = "sia2/query" ,
132+ datalink_context = "datalink" ,
133+ verbose = verbose ,
134+ client_id = 'ASTROQUERY' ,
135+ use_names_over_ids = conf .USE_NAMES_OVER_IDS )
136+ else :
137+ self .__euclidsia = sia_handler
138+
123139 if show_server_messages :
124140 self .get_status_messages ()
125141
@@ -662,6 +678,8 @@ def login(self, *, user=None, password=None, credentials_file=None, verbose=Fals
662678 self .__eucliddata .login (user = tap_user , password = tap_password , verbose = verbose )
663679 log .info (f"Login to Euclid cutout service: { self .__euclidcutout ._TapPlus__getconnhandler ().get_host_url ()} " )
664680 self .__euclidcutout .login (user = tap_user , password = tap_password , verbose = verbose )
681+ log .info (f"Login to Euclid sia service: { self .__euclidsia ._TapPlus__getconnhandler ().get_host_url ()} " )
682+ self .__euclidsia .login (user = tap_user , password = tap_password , verbose = verbose )
665683 except HTTPError as err :
666684 log .error ('Error logging in data or cutout services: %s' % (str (err )))
667685 log .error ("Logging out from TAP server" )
@@ -706,6 +724,14 @@ def login_gui(self, verbose=False):
706724 log .error ("Logging out from TAP server" )
707725 TapPlus .logout (self , verbose = verbose )
708726
727+ try :
728+ log .info (f"Login to Euclid sia server: { self .__euclidsia ._TapPlus__getconnhandler ().get_host_url ()} " )
729+ self .__euclidsia .login (user = tap_user , password = tap_password , verbose = verbose )
730+ except HTTPError as err :
731+ log .error ('Error logging in sia server: %s' % (str (err )))
732+ log .error ("Logging out from TAP server" )
733+ TapPlus .logout (self , verbose = verbose )
734+
709735 def logout (self , verbose = False ):
710736 """
711737 Performs a logout
@@ -741,6 +767,12 @@ def logout(self, verbose=False):
741767 except HTTPError as err :
742768 log .error ('Error logging out cutout server: %s' % (str (err )))
743769
770+ try :
771+ self .__euclidsia .logout (verbose = verbose )
772+ log .info ("Euclid sia server logout OK" )
773+ except HTTPError as err :
774+ log .error ('Error logging out sia server: %s' % (str (err )))
775+
744776 @staticmethod
745777 def __get_quantity_input (value , msg ):
746778 if value is None :
@@ -831,6 +863,7 @@ def __extract_file(output_file_full_path, output_dir, files):
831863 # single file: return it
832864 files .append (output_file_full_path )
833865 return files
866+ return None
834867
835868 def get_observation_products (self , * , id = None , schema = "sedm" , product_type = None , product_subtype = "STK" ,
836869 filter = "VIS" , dsr_part1 = None , dsr_part2 = None , dsr_part3 = None , output_file = None ,
@@ -1037,7 +1070,7 @@ def get_product_list(self, *, observation_id=None, tile_index=None, product_type
10371070 observation id for observations. It is not compatible with parameter tile_index.
10381071
10391072 Searchable products by observation_id: 'dpdVisRawFrame', 'dpdNispRawFrame',
1040- , 'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
1073+ 'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
10411074 'DpdVisStackedFrameCatalog',
10421075 'DpdNirCalibratedFrame', 'DpdNirCalibratedFrameCatalog', 'DpdNirStackedFrameCatalog', 'DpdNirStackedFrame',
10431076 'DpdMerSegmentationMap', 'dpdMerFinalCatalog',
@@ -1399,6 +1432,110 @@ def get_product(self, *, file_name=None, product_id=None, schema='sedm', output_
13991432
14001433 return files
14011434
1435+ def get_sia (self , * , search_type = 'CIRCLE' , ra , dec , radius , calibration = 2 , instrument = 'ALL' , band = None ,
1436+ collection = 'sedm' , dsr_part1 = None , dsr_part2 = None , dsr_part3 = None , output_file = None , verbose = False ):
1437+ """
1438+ Access the Euclid Observation Images by VO SIAP v2.0. This service will return public images from Calibrated
1439+ and Stacked NISP and VIS images, MER Mosaics from VIS and NISP and Level 1 (RAW) images for NISP and VIS
1440+
1441+ Parameters
1442+ ----------
1443+ search_type : str, mandatory, default None
1444+ search region: CIRCLE or BOX
1445+ ra : float (degrees), str or astropy.coordinate, mandatory
1446+ right ascension
1447+ dec : float (degrees), str or astropy.coordinate, mandatory
1448+ declination
1449+ radius : float (degrees), str or astropy.coordinate, mandatory
1450+ search radius of the cutout to generate
1451+ calibration: int, optional, default 2
1452+ calibration level according to ObsCore VO standard: 0 (raw instrumental data), 1 (instrumental data in a
1453+ standard format), 2 (science ready data) or 3 (enhanced data products).
1454+ instrument: str, mandatory, default ALL
1455+ instrument name: ALL, VIS or NISP
1456+ band: str, optional, default None
1457+ filter name only valid if instrument is different from ALL: VIS for instrument VIS or NIR_H, NIR_J, NIR_Y
1458+ or NISP for instrument NISP
1459+ collection : str, mandatory, default sedm
1460+ the name of the data collection
1461+ dsr_part1: str, optional, default None
1462+ the data set release part 1: for OTF environment, the activity code; for REG and IDR, the target environment
1463+ dsr_part2: str, optional, default None
1464+ the data set release part 2: for OTF environment, the patch id (a positive integer); for REG and IDR,
1465+ the activity code
1466+ dsr_part3: str, optional, default None
1467+ the data set release part 3: for OTF, REG and IDR environment, the version (an integer greater than 1)
1468+ output_file : string, optional, default None
1469+ file where the results are saved.
1470+ verbose : bool, optional, default 'False'
1471+ flag to display information about the process
1472+
1473+ Returns
1474+ -------
1475+ A table object or votable file
1476+ """
1477+
1478+ valid_search_types = {'CIRCLE' , 'BOX' }
1479+ valid_calibrations = {0 : 'CALIB_ZERO' , 1 : 'CALIB_ONE' , 2 : 'CALIB_TWO' , 3 : 'CALIB_THREE' }
1480+ valid_instruments = {'ALL' , 'VIS' , 'NISP' }
1481+ valid_band_vis = {'VIS' }
1482+ valid_band_nisp = {'NIR_H' , 'NIR_J' , 'NIR_Y' , 'NISP' }
1483+
1484+ if search_type not in valid_search_types :
1485+ raise ValueError (f"Invalid search tyype { search_type } " )
1486+
1487+ if calibration is not None and calibration not in valid_calibrations :
1488+ raise ValueError (f"Invalid calibration { calibration } " )
1489+
1490+ if instrument not in valid_instruments :
1491+ raise ValueError (f"Invalid instrument { instrument } " )
1492+
1493+ if instrument == 'ALL' and band is not None :
1494+ raise ValueError (f"For instrument { instrument } band must be None" )
1495+
1496+ if instrument == 'VIS' and band is not None and band not in valid_band_vis :
1497+ raise ValueError (f"Invalid band { band } for instrument { instrument } " )
1498+
1499+ if instrument == 'NISP' and band is not None and band not in valid_band_nisp :
1500+ raise ValueError (f"Invalid band { band } for instrument { instrument } " )
1501+
1502+ ra_deg = self .coordinates_degrees (ra )
1503+ dec_deg = self .coordinates_degrees (dec )
1504+ radius_deg = self .coordinates_degrees (radius )
1505+
1506+ params_dict = dict ()
1507+ params_dict ['TAPCLIENT' ] = 'ASTROQUERY'
1508+ params_dict [
1509+ 'POS' ] = f"{ search_type } ,{ ra_deg .to_value (u .deg )} ,{ dec_deg .to_value (u .deg )} ,{ radius_deg .to_value (u .deg )} "
1510+ params_dict ['INSTRUMENT' ] = instrument
1511+ params_dict ['COLLECTION' ] = collection
1512+
1513+ if calibration is not None :
1514+ params_dict ['CALIB' ] = valid_calibrations [calibration ]
1515+
1516+ if instrument != 'ALL' and band is not None :
1517+ params_dict ['BAND' ] = band
1518+
1519+ if dsr_part1 is not None :
1520+ params_dict ['DSP1' ] = dsr_part1
1521+
1522+ if dsr_part2 is not None :
1523+ params_dict ['DSP2' ] = dsr_part2
1524+
1525+ if dsr_part3 is not None :
1526+ params_dict ['DSP3' ] = dsr_part3
1527+
1528+ return self .__euclidsia .load_data (params_dict = params_dict , output_file = output_file , http_method = 'GET' ,
1529+ verbose = verbose )
1530+
1531+ def coordinates_degrees (self , coord ):
1532+
1533+ if not isinstance (coord , units .Quantity ):
1534+ radius_quantity = Quantity (value = coord , unit = u .deg )
1535+ else :
1536+ radius_quantity = coord .to (u .deg )
1537+ return radius_quantity
1538+
14021539 @deprecated_renamed_argument (('instrument' , 'id' ), (None , None ), since = '0.4.12' )
14031540 def get_cutout (self , * , file_path = None , coordinate , radius , output_file = None ,
14041541 verbose = False , instrument = None , id = None ):
0 commit comments