Skip to content

Commit 29a18ae

Browse files
Jorge Fernandez HernandezJorge Fernandez Hernandez
authored andcommitted
EUCLIDSWRQ-250 new method for the image Access Protocol (SIAP)
1 parent 8ad2382 commit 29a18ae

6 files changed

Lines changed: 414 additions & 23 deletions

File tree

CHANGES.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ gaia
129129
- Added ``get_query_payload`` kwarg to return the ADQL query string. [#3539]
130130

131131

132+
esa.euclid
133+
^^^^^^^^^^
134+
135+
- New method get_sia to access the Simple Image Access Protocol (SIAP) v2.0 [#3569]
136+
132137
esa.hubble
133138
^^^^^^^^^^
134139

astroquery/esa/euclid/core.py

Lines changed: 149 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
from astropy.table import unique
2424
from astropy.units import Quantity
2525
from astropy.utils import deprecated_renamed_argument
26+
import astroquery.esa.utils.utils as esautils
27+
2628
from requests.exceptions import HTTPError
2729

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

5456
def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_handler=None, cutout_handler=None,
55-
verbose=False, show_server_messages=True):
57+
sia_handler=None, verbose=False, show_server_messages=True):
5658
"""Constructor for EuclidClass.
5759
5860
Parameters
5961
----------
6062
environment : str, mandatory if no tap, data or cutout hosts is specified, default 'PDR'
6163
The Euclid Science Archive environment: 'PDR', 'IDR', 'OTF' and 'REG'
6264
tap_plus_conn_handler : tap connection handler object, optional, default None
63-
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
64-
datalink_handler : dataliink connection handler object, optional, default None
65-
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
65+
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
66+
datalink_handler : datalink connection handler object, optional, default None
67+
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
6668
cutout_handler : cutout connection handler object, optional, default None
67-
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
69+
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
70+
sia_handler : siap connection handler object, optional, default None
71+
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
6872
verbose : bool, optional, default 'True'
6973
flag to display information about the process
7074
show_server_messages : bool, optional, default 'True'
@@ -125,6 +129,20 @@ def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_ha
125129
else:
126130
self.__euclidcutout = cutout_handler
127131

132+
if sia_handler is None:
133+
self.__euclidsia = TapPlus(url=url_server,
134+
server_context="sas-sia",
135+
tap_context="tap-server",
136+
upload_context="Upload",
137+
table_edit_context="TableTool",
138+
data_context="sia2/query",
139+
datalink_context="datalink",
140+
verbose=verbose,
141+
client_id='ASTROQUERY',
142+
use_names_over_ids=conf.USE_NAMES_OVER_IDS)
143+
else:
144+
self.__euclidsia = sia_handler
145+
128146
if show_server_messages:
129147
self.get_status_messages()
130148

@@ -667,6 +685,8 @@ def login(self, *, user=None, password=None, credentials_file=None, verbose=Fals
667685
self.__eucliddata.login(user=tap_user, password=tap_password, verbose=verbose)
668686
log.info(f"Login to Euclid cutout service: {self.__euclidcutout._TapPlus__getconnhandler().get_host_url()}")
669687
self.__euclidcutout.login(user=tap_user, password=tap_password, verbose=verbose)
688+
log.info(f"Login to Euclid sia service: {self.__euclidsia._TapPlus__getconnhandler().get_host_url()}")
689+
self.__euclidsia.login(user=tap_user, password=tap_password, verbose=verbose)
670690
except HTTPError as err:
671691
log.error('Error logging in data or cutout services: %s' % (str(err)))
672692
log.error("Logging out from TAP server")
@@ -711,6 +731,14 @@ def login_gui(self, verbose=False):
711731
log.error("Logging out from TAP server")
712732
TapPlus.logout(self, verbose=verbose)
713733

734+
try:
735+
log.info(f"Login to Euclid sia server: {self.__euclidsia._TapPlus__getconnhandler().get_host_url()}")
736+
self.__euclidsia.login(user=tap_user, password=tap_password, verbose=verbose)
737+
except HTTPError as err:
738+
log.error('Error logging in sia server: %s' % (str(err)))
739+
log.error("Logging out from TAP server")
740+
TapPlus.logout(self, verbose=verbose)
741+
714742
def logout(self, verbose=False):
715743
"""
716744
Performs a logout
@@ -746,6 +774,12 @@ def logout(self, verbose=False):
746774
except HTTPError as err:
747775
log.error('Error logging out cutout server: %s' % (str(err)))
748776

777+
try:
778+
self.__euclidsia.logout(verbose=verbose)
779+
log.info("Euclid sia server logout OK")
780+
except HTTPError as err:
781+
log.error('Error logging out sia server: %s' % (str(err)))
782+
749783
@staticmethod
750784
def __get_quantity_input(value, msg):
751785
if value is None:
@@ -1087,7 +1121,7 @@ def get_product_list(self, *, observation_id=None, tile_index=None, product_type
10871121
observation id for observations. It is not compatible with parameter tile_index.
10881122
10891123
Searchable products by observation_id: 'dpdVisRawFrame', 'dpdNispRawFrame',
1090-
,'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
1124+
'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
10911125
'DpdVisStackedFrameCatalog',
10921126
'DpdNirCalibratedFrame', 'DpdNirCalibratedFrameCatalog', 'DpdNirStackedFrameCatalog', 'DpdNirStackedFrame',
10931127
'DpdMerSegmentationMap', 'dpdMerFinalCatalog',
@@ -1482,6 +1516,115 @@ def __is_multiple(self, value):
14821516

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

1519+
def get_sia(self, *, coordinates, radius=1.0, search_type='CIRCLE', calibration=2, instrument='ALL', band=None,
1520+
collection='sedm', dsr_part1=None, dsr_part2=None, dsr_part3=None, output_file=None, verbose=False):
1521+
"""
1522+
Query the Euclid Observation Images service through the IVOA SIAP 2.0 interface.
1523+
1524+
The service provides access to public calibrated and stacked VIS and NISP images, MER mosaics, and Level 1 (raw)
1525+
VIS and NISP observations.
1526+
1527+
Parameters
1528+
----------
1529+
coordinates: str or SkyCoord, mandatory, default None
1530+
Center of the search region.
1531+
radius: float or quantity, optional, default value 1.0 degree
1532+
Radius of the search region. If a numeric value is provided, it is interpreted in degrees. An
1533+
astropy.units.Quantity may also be supplied. If "BOX" uses this value as width
1534+
search_type : str, optional, default CIRCLE
1535+
Shape of the search region. Supported values are "CIRCLE" and "BOX".
1536+
calibration: int, optional, default 2
1537+
Calibration level following the ObsCore data model:
1538+
- 1: raw instrumental data
1539+
- 2: instrumental data in a standard format
1540+
- : science-ready data
1541+
- 4: enhanced data products
1542+
instrument: str, optional, default ALL
1543+
Instrument to query. Supported values are "ALL", "VIS", and "NISP".
1544+
band: str, optional, default None
1545+
Filter name. This parameter is ignored when instrument="ALL". Valid values are:
1546+
- 1: "VIS" for the VIS instrument
1547+
- 2: "NIR_Y", "NIR_J", "NIR_H", or "NISP" for the NISP instrument
1548+
collection : str, optional, default sedm
1549+
Name of the data collection.
1550+
dsr_part1: str, optional, default None
1551+
First component of the dataset release identifier: for OTF environment, the activity code; for REG and IDR,
1552+
the target environment
1553+
dsr_part2: str, optional, default None
1554+
Second component of the dataset release identifier: for OTF environment, the patch id (a positive integer);
1555+
for REG and IDR, the activity code
1556+
dsr_part3: str, optional, default None
1557+
Third component of the dataset release identifier: for OTF, REG and IDR environment, the version (an integer
1558+
greater than 1) output_file : string, optional, default None
1559+
Output file where the query results are written.
1560+
verbose : bool, optional, default 'False'
1561+
flag to display information about the process
1562+
1563+
Returns
1564+
-------
1565+
astropy.table.Table or str
1566+
Query results. If ``output_file`` is specified, the results are also written as a VOTable.
1567+
"""
1568+
1569+
valid_search_types = {'CIRCLE', 'BOX'}
1570+
valid_calibrations = {0: 'CALIB_ZERO', 1: 'CALIB_ONE', 2: 'CALIB_TWO', 3: 'CALIB_THREE'}
1571+
valid_instruments = {'ALL', 'VIS', 'NISP'}
1572+
valid_band_vis = {'VIS'}
1573+
valid_band_nisp = {'NIR_H', 'NIR_J', 'NIR_Y', 'NISP'}
1574+
1575+
if search_type not in valid_search_types:
1576+
raise ValueError(f"Invalid search tyype {search_type}")
1577+
1578+
if calibration is not None and calibration not in valid_calibrations:
1579+
raise ValueError(f"Invalid calibration {calibration}")
1580+
1581+
if instrument not in valid_instruments:
1582+
raise ValueError(f"Invalid instrument {instrument}")
1583+
1584+
if instrument == 'ALL' and band is not None:
1585+
raise ValueError(f"For instrument {instrument} band must be None")
1586+
1587+
if instrument == 'VIS' and band is not None and band not in valid_band_vis:
1588+
raise ValueError(f"Invalid band {band} for instrument {instrument}")
1589+
1590+
if instrument == 'NISP' and band is not None and band not in valid_band_nisp:
1591+
raise ValueError(f"Invalid band {band} for instrument {instrument}")
1592+
1593+
if coordinates is not None and radius is not None:
1594+
coord = commons.parse_coordinates(coordinates=coordinates)
1595+
ra_deg = coord.ra.degree
1596+
dec_deg = coord.dec.degree
1597+
radius_deg = esautils.get_degree_radius(radius)
1598+
1599+
if radius_deg <= 0.0:
1600+
raise ValueError(f"Search radius is zero or negative: {radius}")
1601+
else:
1602+
raise ValueError(f"Invalid coordinates or search radius: {coordinates}, {radius}")
1603+
1604+
params_dict = dict()
1605+
params_dict['TAPCLIENT'] = 'ASTROQUERY'
1606+
params_dict['POS'] = f"{search_type},{ra_deg}, {dec_deg},{radius_deg}"
1607+
params_dict['INSTRUMENT'] = instrument
1608+
params_dict['COLLECTION'] = collection
1609+
1610+
if calibration is not None:
1611+
params_dict['CALIB'] = valid_calibrations[calibration]
1612+
1613+
if instrument != 'ALL' and band is not None:
1614+
params_dict['BAND'] = band
1615+
1616+
if dsr_part1 is not None:
1617+
params_dict['DSP1'] = dsr_part1
1618+
1619+
if dsr_part2 is not None:
1620+
params_dict['DSP2'] = dsr_part2
1621+
1622+
if dsr_part3 is not None:
1623+
params_dict['DSP3'] = dsr_part3
1624+
1625+
return self.__euclidsia.load_data(params_dict=params_dict, output_file=output_file, http_method='GET',
1626+
verbose=verbose)
1627+
14851628
@deprecated_renamed_argument(('instrument', 'id'), (None, None), since='0.4.12')
14861629
def get_cutout(self, *, file_path=None, coordinate, radius, output_file=None, verbose=False, instrument=None,
14871630
id=None):
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<RESOURCE type="results">
4+
<INFO name="QUERY_STATUS" value="OK" />
5+
<INFO name="PROVIDER" value=""></INFO>
6+
<TABLE>
7+
<FIELD name="cutout_access_url" ucd="meta.ref.url" datatype="char" arraysize="*"/>
8+
<FIELD name="facility_name" ucd="meta.id;instr.tel" datatype="char" arraysize="*"/>
9+
<FIELD name="file_name" ucd="pos.eq.dec" datatype="char" arraysize="*"/>
10+
<FIELD name="instrument_name" ucd="meta.id;instr" datatype="char" arraysize="*"/>
11+
<FIELD name="filter" ucd="meta.id;band" datatype="char" arraysize="*"/>
12+
<FIELD name="s_region" ucd="phys.angArea;obs" datatype="char" arraysize="*"/>
13+
<FIELD name="s_ra" ucd="pos.eq.ra" datatype="char" arraysize="*"/>
14+
<FIELD name="s_dec" ucd="pos.eq.dec" datatype="char" arraysize="*"/>
15+
<FIELD name="obs_id" ucd="meta.id" datatype="char" arraysize="*"/>
16+
<FIELD name="obs_collection" ucd="meta.id" datatype="char" arraysize="*"/>
17+
<FIELD name="dataproduct_type" ucd="meta.id" datatype="char" arraysize="*"/>
18+
<FIELD name="dataproduct_subtype" ucd="meta.id" datatype="char" arraysize="*"/>
19+
<FIELD name="calib_level" ucd="meta.id" datatype="char" arraysize="*"/>
20+
<DATA>
21+
<TABLEDATA>
22+
<TR>
23+
<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>
24+
<TD></TD>
25+
<TD>EUC_MER_BGSUB-MOSAIC-VIS_TILE101007315-D84386_20230826T000856.482420Z_00.00.fits.gz</TD>
26+
<TD>NISP</TD>
27+
<TD>NIR_J</TD>
28+
<TD>{(1.56878970716861 , -1.15654637163971),(1.54566457897093 , -1.15654636650839),(1.54590379663453 , -1.14723910521964),(1.568550514417 , -1.14723911022404)}</TD>
29+
<TD>89.2225775443200035</TD>
30+
<TD>-66</TD>
31+
<TD>null</TD>
32+
<TD>sedm</TD>
33+
<TD>mosaic</TD>
34+
<TD>DpdMerBksMosaic</TD>
35+
<TD>3</TD>
36+
</TR>
37+
<TR>
38+
<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>
39+
<TD></TD>
40+
<TD>EUC_NIR_W-CAL-IMAGE_H-65602-17_20230906T190444.924367Z.fits</TD>
41+
<TD>NISP</TD>
42+
<TD>NIR_H</TD>
43+
<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>
44+
<TD>90.0032000000000068</TD>
45+
<TD>-66.498500000000007</TD>
46+
<TD>65602</TD>
47+
<TD>sedm</TD>
48+
<TD>image</TD>
49+
<TD>DpdNirCalibratedFrame</TD>
50+
<TD>2</TD>
51+
</TR>
52+
</TABLEDATA>
53+
</DATA>
54+
</TABLE>
55+
</RESOURCE>
56+
</VOTABLE>

0 commit comments

Comments
 (0)