Skip to content
Draft
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 @@ -124,6 +124,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
155 changes: 149 additions & 6 deletions astroquery/esa/euclid/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from astropy.table import unique
from astropy.units import Quantity
from astropy.utils import deprecated_renamed_argument
import astroquery.esa.utils.utils as esautils

from requests.exceptions import HTTPError

from astroquery import log
Expand Down Expand Up @@ -52,19 +54,21 @@ class EuclidClass(TapPlus):
__regex_designation = re.compile(r"\s*(\S+)\s(-?\d+)\s*", flags=re.MULTILINE | re.UNICODE)

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 @@ -125,6 +129,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 @@ -667,6 +685,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 @@ -711,6 +731,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 @@ -746,6 +774,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 @@ -1087,7 +1121,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 @@ -1482,6 +1516,115 @@ def __is_multiple(self, value):

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

def get_sia(self, *, coordinates, radius=1.0, search_type='CIRCLE', calibration=2, instrument='ALL', band=None,
collection='sedm', dsr_part1=None, dsr_part2=None, dsr_part3=None, output_file=None, verbose=False):
"""
Query the Euclid Observation Images service through the IVOA SIAP 2.0 interface.

The service provides access to public calibrated and stacked VIS and NISP images, MER mosaics, and Level 1 (raw)
VIS and NISP observations.

Parameters
----------
coordinates: str or SkyCoord, mandatory, default None
Center of the search region.
radius: float or quantity, optional, default value 1.0 degree
Radius of the search region. If a numeric value is provided, it is interpreted in degrees. An
astropy.units.Quantity may also be supplied. If "BOX" uses this value as width
search_type : str, optional, default CIRCLE
Shape of the search region. Supported values are "CIRCLE" and "BOX".
calibration: int, optional, default 2
Calibration level following the ObsCore data model:
- 1: raw instrumental data
- 2: instrumental data in a standard format
- : science-ready data
- 4: enhanced data products
instrument: str, optional, default ALL
Instrument to query. Supported values are "ALL", "VIS", and "NISP".
band: str, optional, default None
Filter name. This parameter is ignored when instrument="ALL". Valid values are:
- 1: "VIS" for the VIS instrument
- 2: "NIR_Y", "NIR_J", "NIR_H", or "NISP" for the NISP instrument
collection : str, optional, default sedm
Name of the data collection.
dsr_part1: str, optional, default None
First component of the dataset release identifier: for OTF environment, the activity code; for REG and IDR,
the target environment
dsr_part2: str, optional, default None
Second component of the dataset release identifier: for OTF environment, the patch id (a positive integer);
for REG and IDR, the activity code
dsr_part3: str, optional, default None
Third component of the dataset release identifier: for OTF, REG and IDR environment, the version (an integer
greater than 1) output_file : string, optional, default None
Output file where the query results are written.
verbose : bool, optional, default 'False'
flag to display information about the process

Returns
-------
astropy.table.Table or str
Query results. If ``output_file`` is specified, the results are also written as a VOTable.
"""

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}")

if radius is not None:
coord = commons.parse_coordinates(coordinates=coordinates)
ra_deg = coord.ra.degree
dec_deg = coord.dec.degree
radius_deg = esautils.get_degree_radius(radius)

if radius_deg <= 0.0:
raise ValueError(f"Search radius is zero or negative: {radius}")
else:
raise ValueError(f"Invalid coordinates or search radius: {coordinates}, {radius}")

params_dict = dict()
params_dict['TAPCLIENT'] = 'ASTROQUERY'
params_dict['POS'] = f"{search_type},{ra_deg}, {dec_deg},{radius_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)

@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