Skip to content

Commit 18d9a8d

Browse files
Jorge Fernandez HernandezJorge Fernandez Hernandez
authored andcommitted
EUCLIDSWRQ-250 new method for the image Access Protocol (SIAP)
1 parent 25c4840 commit 18d9a8d

6 files changed

Lines changed: 353 additions & 15 deletions

File tree

CHANGES.rst

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

115115

116+
esa.euclid
117+
^^^^^^^^^^
118+
119+
- New method get_sia to access the Simple Image Access Protocol (SIAP) v2.0 [#3569]
120+
116121
esa.hubble
117122
^^^^^^^^^^
118123

astroquery/esa/euclid/core.py

Lines changed: 142 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,21 @@ class EuclidClass(TapPlus):
5050
__regex_designation = re.compile(r"\s*(\S+)\s(-?\d+)\s*", flags=re.MULTILINE | re.UNICODE)
5151

5252
def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_handler=None, cutout_handler=None,
53-
verbose=False, show_server_messages=True):
53+
sia_handler=None, verbose=False, show_server_messages=True):
5454
"""Constructor for EuclidClass.
5555
5656
Parameters
5757
----------
5858
environment : str, mandatory if no tap, data or cutout hosts is specified, default 'PDR'
5959
The Euclid Science Archive environment: 'PDR', 'IDR', 'OTF' and 'REG'
6060
tap_plus_conn_handler : tap connection handler object, optional, default None
61-
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
62-
datalink_handler : dataliink connection handler object, optional, default None
63-
HTTP(s) connection hander (creator). If no handler is provided, a new one is created.
61+
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
62+
datalink_handler : datalink connection handler object, optional, default None
63+
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
6464
cutout_handler : cutout 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+
sia_handler : siap connection handler object, optional, default None
67+
HTTP(s) connection handler (creator). If no handler is provided, a new one is created.
6668
verbose : bool, optional, default 'True'
6769
flag to display information about the process
6870
show_server_messages : bool, optional, default 'True'
@@ -123,6 +125,20 @@ def __init__(self, *, environment='PDR', tap_plus_conn_handler=None, datalink_ha
123125
else:
124126
self.__euclidcutout = cutout_handler
125127

128+
if sia_handler is None:
129+
self.__euclidsia = TapPlus(url=url_server,
130+
server_context="sas-sia",
131+
tap_context="tap-server",
132+
upload_context="Upload",
133+
table_edit_context="TableTool",
134+
data_context="sia2/query",
135+
datalink_context="datalink",
136+
verbose=verbose,
137+
client_id='ASTROQUERY',
138+
use_names_over_ids=conf.USE_NAMES_OVER_IDS)
139+
else:
140+
self.__euclidsia = sia_handler
141+
126142
if show_server_messages:
127143
self.get_status_messages()
128144

@@ -665,6 +681,8 @@ def login(self, *, user=None, password=None, credentials_file=None, verbose=Fals
665681
self.__eucliddata.login(user=tap_user, password=tap_password, verbose=verbose)
666682
log.info(f"Login to Euclid cutout service: {self.__euclidcutout._TapPlus__getconnhandler().get_host_url()}")
667683
self.__euclidcutout.login(user=tap_user, password=tap_password, verbose=verbose)
684+
log.info(f"Login to Euclid sia service: {self.__euclidsia._TapPlus__getconnhandler().get_host_url()}")
685+
self.__euclidsia.login(user=tap_user, password=tap_password, verbose=verbose)
668686
except HTTPError as err:
669687
log.error('Error logging in data or cutout services: %s' % (str(err)))
670688
log.error("Logging out from TAP server")
@@ -709,6 +727,14 @@ def login_gui(self, verbose=False):
709727
log.error("Logging out from TAP server")
710728
TapPlus.logout(self, verbose=verbose)
711729

730+
try:
731+
log.info(f"Login to Euclid sia server: {self.__euclidsia._TapPlus__getconnhandler().get_host_url()}")
732+
self.__euclidsia.login(user=tap_user, password=tap_password, verbose=verbose)
733+
except HTTPError as err:
734+
log.error('Error logging in sia server: %s' % (str(err)))
735+
log.error("Logging out from TAP server")
736+
TapPlus.logout(self, verbose=verbose)
737+
712738
def logout(self, verbose=False):
713739
"""
714740
Performs a logout
@@ -744,6 +770,12 @@ def logout(self, verbose=False):
744770
except HTTPError as err:
745771
log.error('Error logging out cutout server: %s' % (str(err)))
746772

773+
try:
774+
self.__euclidsia.logout(verbose=verbose)
775+
log.info("Euclid sia server logout OK")
776+
except HTTPError as err:
777+
log.error('Error logging out sia server: %s' % (str(err)))
778+
747779
@staticmethod
748780
def __get_quantity_input(value, msg):
749781
if value is None:
@@ -1059,7 +1091,7 @@ def get_product_list(self, *, observation_id=None, tile_index=None, product_type
10591091
observation id for observations. It is not compatible with parameter tile_index.
10601092
10611093
Searchable products by observation_id: 'dpdVisRawFrame', 'dpdNispRawFrame',
1062-
,'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
1094+
'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
10631095
'DpdVisStackedFrameCatalog',
10641096
'DpdNirCalibratedFrame', 'DpdNirCalibratedFrameCatalog', 'DpdNirStackedFrameCatalog', 'DpdNirStackedFrame',
10651097
'DpdMerSegmentationMap', 'dpdMerFinalCatalog',
@@ -1442,6 +1474,110 @@ def __is_multiple(self, value):
14421474

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

1477+
def get_sia(self, *, search_type='CIRCLE', ra, dec, radius, calibration=2, instrument='ALL', band=None,
1478+
collection='sedm', dsr_part1=None, dsr_part2=None, dsr_part3=None, output_file=None, verbose=False):
1479+
"""
1480+
Access the Euclid Observation Images by VO SIAP v2.0. This service will return public images from Calibrated
1481+
and Stacked NISP and VIS images, MER Mosaics from VIS and NISP and Level 1 (RAW) images for NISP and VIS
1482+
1483+
Parameters
1484+
----------
1485+
search_type : str, mandatory, default None
1486+
search region: CIRCLE or BOX
1487+
ra : float (degrees), str or astropy.coordinate, mandatory
1488+
right ascension
1489+
dec : float (degrees), str or astropy.coordinate, mandatory
1490+
declination
1491+
radius : float (degrees), str or astropy.coordinate, mandatory
1492+
search radius of the cutout to generate
1493+
calibration: int, optional, default 2
1494+
calibration level according to ObsCore VO standard: 0 (raw instrumental data), 1 (instrumental data in a
1495+
standard format), 2 (science ready data) or 3 (enhanced data products).
1496+
instrument: str, mandatory, default ALL
1497+
instrument name: ALL, VIS or NISP
1498+
band: str, optional, default None
1499+
filter name only valid if instrument is different from ALL: VIS for instrument VIS or NIR_H, NIR_J, NIR_Y
1500+
or NISP for instrument NISP
1501+
collection : str, mandatory, default sedm
1502+
the name of the data collection
1503+
dsr_part1: str, optional, default None
1504+
the data set release part 1: for OTF environment, the activity code; for REG and IDR, the target environment
1505+
dsr_part2: str, optional, default None
1506+
the data set release part 2: for OTF environment, the patch id (a positive integer); for REG and IDR,
1507+
the activity code
1508+
dsr_part3: str, optional, default None
1509+
the data set release part 3: for OTF, REG and IDR environment, the version (an integer greater than 1)
1510+
output_file : string, optional, default None
1511+
file where the results are saved.
1512+
verbose : bool, optional, default 'False'
1513+
flag to display information about the process
1514+
1515+
Returns
1516+
-------
1517+
A table object or votable file
1518+
"""
1519+
1520+
valid_search_types = {'CIRCLE', 'BOX'}
1521+
valid_calibrations = {0: 'CALIB_ZERO', 1: 'CALIB_ONE', 2: 'CALIB_TWO', 3: 'CALIB_THREE'}
1522+
valid_instruments = {'ALL', 'VIS', 'NISP'}
1523+
valid_band_vis = {'VIS'}
1524+
valid_band_nisp = {'NIR_H', 'NIR_J', 'NIR_Y', 'NISP'}
1525+
1526+
if search_type not in valid_search_types:
1527+
raise ValueError(f"Invalid search tyype {search_type}")
1528+
1529+
if calibration is not None and calibration not in valid_calibrations:
1530+
raise ValueError(f"Invalid calibration {calibration}")
1531+
1532+
if instrument not in valid_instruments:
1533+
raise ValueError(f"Invalid instrument {instrument}")
1534+
1535+
if instrument == 'ALL' and band is not None:
1536+
raise ValueError(f"For instrument {instrument} band must be None")
1537+
1538+
if instrument == 'VIS' and band is not None and band not in valid_band_vis:
1539+
raise ValueError(f"Invalid band {band} for instrument {instrument}")
1540+
1541+
if instrument == 'NISP' and band is not None and band not in valid_band_nisp:
1542+
raise ValueError(f"Invalid band {band} for instrument {instrument}")
1543+
1544+
ra_deg = self.coordinates_degrees(ra)
1545+
dec_deg = self.coordinates_degrees(dec)
1546+
radius_deg = self.coordinates_degrees(radius)
1547+
1548+
params_dict = dict()
1549+
params_dict['TAPCLIENT'] = 'ASTROQUERY'
1550+
params_dict[
1551+
'POS'] = f"{search_type},{ra_deg.to_value(u.deg)},{dec_deg.to_value(u.deg)},{radius_deg.to_value(u.deg)}"
1552+
params_dict['INSTRUMENT'] = instrument
1553+
params_dict['COLLECTION'] = collection
1554+
1555+
if calibration is not None:
1556+
params_dict['CALIB'] = valid_calibrations[calibration]
1557+
1558+
if instrument != 'ALL' and band is not None:
1559+
params_dict['BAND'] = band
1560+
1561+
if dsr_part1 is not None:
1562+
params_dict['DSP1'] = dsr_part1
1563+
1564+
if dsr_part2 is not None:
1565+
params_dict['DSP2'] = dsr_part2
1566+
1567+
if dsr_part3 is not None:
1568+
params_dict['DSP3'] = dsr_part3
1569+
1570+
return self.__euclidsia.load_data(params_dict=params_dict, output_file=output_file, http_method='GET',
1571+
verbose=verbose)
1572+
1573+
def coordinates_degrees(self, coord):
1574+
1575+
if not isinstance(coord, units.Quantity):
1576+
radius_quantity = Quantity(value=coord, unit=u.deg)
1577+
else:
1578+
radius_quantity = coord.to(u.deg)
1579+
return radius_quantity
1580+
14451581
@deprecated_renamed_argument(('instrument', 'id'), (None, None), since='0.4.12')
14461582
def get_cutout(self, *, file_path=None, coordinate, radius, output_file=None, verbose=False, instrument=None,
14471583
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)