Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ gaia
- Added ``get_query_payload`` kwarg to return the ADQL query string. [#3539]


esa.euclid
^^^^^^^^^^

- New method get_sia to access the Simple Image Access Protocol (SIAP) v2.0 [#3569]

esa.hubble
^^^^^^^^^^

Expand Down
148 changes: 142 additions & 6 deletions astroquery/esa/euclid/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,21 @@ class EuclidClass(TapPlus):
__VALID_LINKING_PARAMETERS = conf.VALID_LINKING_PARAMETERS

def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_handler=None, cutout_handler=None,
verbose=False, show_server_messages=True):
sia_handler=None, verbose=False, show_server_messages=True):
"""Constructor for EuclidClass.

Parameters
----------
environment : str, mandatory if no tap, data or cutout hosts is specified, default 'PDR'
The Euclid Science Archive environment: 'PDR', 'IDR', 'OTF' and 'REG'
tap_plus_conn_handler : tap connection handler object, optional, default None
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
datalink_handler : dataliink connection handler object, optional, default None
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
datalink_handler : datalink connection handler object, optional, default None
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
cutout_handler : cutout connection handler object, optional, default None
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
sia_handler : siap connection handler object, optional, default None
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
verbose : bool, optional, default 'True'
flag to display information about the process
show_server_messages : bool, optional, default 'True'
Expand Down Expand Up @@ -120,6 +122,20 @@ def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_ha
else:
self.__euclidcutout = cutout_handler

if sia_handler is None:
self.__euclidsia = TapPlus(url=url_server,
server_context="sas-sia",
tap_context="tap-server",
upload_context="Upload",
table_edit_context="TableTool",
data_context="sia2/query",
datalink_context="datalink",
verbose=verbose,
client_id='ASTROQUERY',
use_names_over_ids=conf.USE_NAMES_OVER_IDS)
else:
self.__euclidsia = sia_handler

if show_server_messages:
self.get_status_messages()

Expand Down Expand Up @@ -662,6 +678,8 @@ def login(self, *, user=None, password=None, credentials_file=None, verbose=Fals
self.__eucliddata.login(user=tap_user, password=tap_password, verbose=verbose)
log.info(f"Login to Euclid cutout service: {self.__euclidcutout._TapPlus__getconnhandler().get_host_url()}")
self.__euclidcutout.login(user=tap_user, password=tap_password, verbose=verbose)
log.info(f"Login to Euclid sia service: {self.__euclidsia._TapPlus__getconnhandler().get_host_url()}")
self.__euclidsia.login(user=tap_user, password=tap_password, verbose=verbose)
except HTTPError as err:
log.error('Error logging in data or cutout services: %s' % (str(err)))
log.error("Logging out from TAP server")
Expand Down Expand Up @@ -706,6 +724,14 @@ def login_gui(self, verbose=False):
log.error("Logging out from TAP server")
TapPlus.logout(self, verbose=verbose)

try:
log.info(f"Login to Euclid sia server: {self.__euclidsia._TapPlus__getconnhandler().get_host_url()}")
self.__euclidsia.login(user=tap_user, password=tap_password, verbose=verbose)
except HTTPError as err:
log.error('Error logging in sia server: %s' % (str(err)))
log.error("Logging out from TAP server")
TapPlus.logout(self, verbose=verbose)

def logout(self, verbose=False):
"""
Performs a logout
Expand Down Expand Up @@ -741,6 +767,12 @@ def logout(self, verbose=False):
except HTTPError as err:
log.error('Error logging out cutout server: %s' % (str(err)))

try:
self.__euclidsia.logout(verbose=verbose)
log.info("Euclid sia server logout OK")
except HTTPError as err:
log.error('Error logging out sia server: %s' % (str(err)))

@staticmethod
def __get_quantity_input(value, msg):
if value is None:
Expand Down Expand Up @@ -1056,7 +1088,7 @@ def get_product_list(self, *, observation_id=None, tile_index=None, product_type
observation id for observations. It is not compatible with parameter tile_index.

Searchable products by observation_id: 'dpdVisRawFrame', 'dpdNispRawFrame',
,'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
'DpdVisStackedFrameCatalog',
'DpdNirCalibratedFrame', 'DpdNirCalibratedFrameCatalog', 'DpdNirStackedFrameCatalog', 'DpdNirStackedFrame',
'DpdMerSegmentationMap', 'dpdMerFinalCatalog',
Expand Down Expand Up @@ -1439,6 +1471,110 @@ def __is_multiple(self, value):

return (isinstance(value, (list, tuple)) and len(value) > 1) or ',' in value

def get_sia(self, *, search_type='CIRCLE', ra, dec, radius, calibration=2, instrument='ALL', band=None,
collection='sedm', dsr_part1=None, dsr_part2=None, dsr_part3=None, output_file=None, verbose=False):
"""
Access the Euclid Observation Images by VO SIAP v2.0. This service will return public images from Calibrated
and Stacked NISP and VIS images, MER Mosaics from VIS and NISP and Level 1 (RAW) images for NISP and VIS

Parameters
----------
search_type : str, mandatory, default None
search region: CIRCLE or BOX
ra : float (degrees), str or astropy.coordinate, mandatory
right ascension
dec : float (degrees), str or astropy.coordinate, mandatory
declination
radius : float (degrees), str or astropy.coordinate, mandatory
search radius of the cutout to generate
calibration: int, optional, default 2
calibration level according to ObsCore VO standard: 0 (raw instrumental data), 1 (instrumental data in a
standard format), 2 (science ready data) or 3 (enhanced data products).
instrument: str, mandatory, default ALL
instrument name: ALL, VIS or NISP
band: str, optional, default None
filter name only valid if instrument is different from ALL: VIS for instrument VIS or NIR_H, NIR_J, NIR_Y
or NISP for instrument NISP
collection : str, mandatory, default sedm
the name of the data collection
dsr_part1: str, optional, default None
the data set release part 1: for OTF environment, the activity code; for REG and IDR, the target environment
dsr_part2: str, optional, default None
the data set release part 2: for OTF environment, the patch id (a positive integer); for REG and IDR,
the activity code
dsr_part3: str, optional, default None
the data set release part 3: for OTF, REG and IDR environment, the version (an integer greater than 1)
output_file : string, optional, default None
file where the results are saved.
verbose : bool, optional, default 'False'
flag to display information about the process

Returns
-------
A table object or votable file
"""

valid_search_types = {'CIRCLE', 'BOX'}
valid_calibrations = {0: 'CALIB_ZERO', 1: 'CALIB_ONE', 2: 'CALIB_TWO', 3: 'CALIB_THREE'}
valid_instruments = {'ALL', 'VIS', 'NISP'}
valid_band_vis = {'VIS'}
valid_band_nisp = {'NIR_H', 'NIR_J', 'NIR_Y', 'NISP'}

if search_type not in valid_search_types:
raise ValueError(f"Invalid search tyype {search_type}")

if calibration is not None and calibration not in valid_calibrations:
raise ValueError(f"Invalid calibration {calibration}")

if instrument not in valid_instruments:
raise ValueError(f"Invalid instrument {instrument}")

if instrument == 'ALL' and band is not None:
raise ValueError(f"For instrument {instrument} band must be None")

if instrument == 'VIS' and band is not None and band not in valid_band_vis:
raise ValueError(f"Invalid band {band} for instrument {instrument}")

if instrument == 'NISP' and band is not None and band not in valid_band_nisp:
raise ValueError(f"Invalid band {band} for instrument {instrument}")

ra_deg = self.coordinates_degrees(ra)
dec_deg = self.coordinates_degrees(dec)
radius_deg = self.coordinates_degrees(radius)

params_dict = dict()
params_dict['TAPCLIENT'] = 'ASTROQUERY'
params_dict[
'POS'] = f"{search_type},{ra_deg.to_value(u.deg)},{dec_deg.to_value(u.deg)},{radius_deg.to_value(u.deg)}"
params_dict['INSTRUMENT'] = instrument
params_dict['COLLECTION'] = collection

if calibration is not None:
params_dict['CALIB'] = valid_calibrations[calibration]

if instrument != 'ALL' and band is not None:
params_dict['BAND'] = band

if dsr_part1 is not None:
params_dict['DSP1'] = dsr_part1

if dsr_part2 is not None:
params_dict['DSP2'] = dsr_part2

if dsr_part3 is not None:
params_dict['DSP3'] = dsr_part3

return self.__euclidsia.load_data(params_dict=params_dict, output_file=output_file, http_method='GET',
verbose=verbose)

def coordinates_degrees(self, coord):

if not isinstance(coord, units.Quantity):
radius_quantity = Quantity(value=coord, unit=u.deg)
else:
radius_quantity = coord.to(u.deg)
return radius_quantity

@deprecated_renamed_argument(('instrument', 'id'), (None, None), since='0.4.12')
def get_cutout(self, *, file_path=None, coordinate, radius, output_file=None, verbose=False, instrument=None,
id=None):
Expand Down
56 changes: 56 additions & 0 deletions astroquery/esa/euclid/tests/data/sia_test.vot
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<VOTABLE version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.4 http://www.ivoa.net/xml/VOTable/v1.4" xmlns="http://www.ivoa.net/xml/VOTable/v1.4">
<RESOURCE type="results">
<INFO name="QUERY_STATUS" value="OK" />
<INFO name="PROVIDER" value=""></INFO>
<TABLE>
<FIELD name="cutout_access_url" ucd="meta.ref.url" datatype="char" arraysize="*"/>
<FIELD name="facility_name" ucd="meta.id;instr.tel" datatype="char" arraysize="*"/>
<FIELD name="file_name" ucd="pos.eq.dec" datatype="char" arraysize="*"/>
<FIELD name="instrument_name" ucd="meta.id;instr" datatype="char" arraysize="*"/>
<FIELD name="filter" ucd="meta.id;band" datatype="char" arraysize="*"/>
<FIELD name="s_region" ucd="phys.angArea;obs" datatype="char" arraysize="*"/>
<FIELD name="s_ra" ucd="pos.eq.ra" datatype="char" arraysize="*"/>
<FIELD name="s_dec" ucd="pos.eq.dec" datatype="char" arraysize="*"/>
<FIELD name="obs_id" ucd="meta.id" datatype="char" arraysize="*"/>
<FIELD name="obs_collection" ucd="meta.id" datatype="char" arraysize="*"/>
<FIELD name="dataproduct_type" ucd="meta.id" datatype="char" arraysize="*"/>
<FIELD name="dataproduct_subtype" ucd="meta.id" datatype="char" arraysize="*"/>
<FIELD name="calib_level" ucd="meta.id" datatype="char" arraysize="*"/>
<DATA>
<TABLEDATA>
<TR>
<TD><![CDATA[https://easdev.esac.esa.int/sas-cutout/cutout?filepath=/data_03/repository_otf/MER/101007315/VIS/EUC_MER_BGSUB-MOSAIC-VIS_TILE101007315-D84386_20230826T000856.482420Z_00.00.fits.gz&collection=NISP&tileindex=101007315&POS=CIRCLE,89.0,-66.0,1.0]]></TD>
<TD></TD>
<TD>EUC_MER_BGSUB-MOSAIC-VIS_TILE101007315-D84386_20230826T000856.482420Z_00.00.fits.gz</TD>
<TD>NISP</TD>
<TD>NIR_J</TD>
<TD>{(1.56878970716861 , -1.15654637163971),(1.54566457897093 , -1.15654636650839),(1.54590379663453 , -1.14723910521964),(1.568550514417 , -1.14723911022404)}</TD>
<TD>89.2225775443200035</TD>
<TD>-66</TD>
<TD>null</TD>
<TD>sedm</TD>
<TD>mosaic</TD>
<TD>DpdMerBksMosaic</TD>
<TD>3</TD>
</TR>
<TR>
<TD><![CDATA[https://easdev.esac.esa.int/sas-cutout/cutout?filepath=/data_03/repository_otf/NIR/65602/EUC_NIR_W-CAL-IMAGE_H-65602-17_20230906T190444.924367Z.fits&collection=NISP&obsid=65602&POS=CIRCLE,89.0,-66.0,1.0]]></TD>
<TD></TD>
<TD>EUC_NIR_W-CAL-IMAGE_H-65602-17_20230906T190444.924367Z.fits</TD>
<TD>NISP</TD>
<TD>NIR_H</TD>
<TD>{(1.59364461496529 , -1.16117316244116),(1.5877646080787 , -1.16334176247736),(1.58179954392353 , -1.16549550886951),(1.5757606932609 , -1.16763184447562),(1.57013973108981 , -1.1695759346524),(1.5643381526667 , -1.16701623505239),(1.5587172508289 , -1.1645004743295),(1.55386389053321 , -1.16228607475105),(1.55304135179527 , -1.16190988595972),(1.54825944937331 , -1.15969489664624),(1.57153509266763 , -1.15142605710669)}</TD>
<TD>90.0032000000000068</TD>
<TD>-66.498500000000007</TD>
<TD>65602</TD>
<TD>sedm</TD>
<TD>image</TD>
<TD>DpdNirCalibratedFrame</TD>
<TD>2</TD>
</TR>
</TABLEDATA>
</DATA>
</TABLE>
</RESOURCE>
</VOTABLE>
Loading
Loading