Skip to content

Commit c98b8e9

Browse files
Jorge Fernandez HernandezJorge Fernandez Hernandez
authored andcommitted
EUCLIDSWRQ-250 new method for the image Access Protocol (SIAP)
1 parent 234c624 commit c98b8e9

File tree

6 files changed

+353
-15
lines changed

6 files changed

+353
-15
lines changed

CHANGES.rst

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

9292

93+
esa.euclid
94+
^^^^^^^^^^
95+
96+
- New method get_sia to access the Simple Image Access Protocol (SIAP) v2.0 [#3569]
97+
9398
esa.hubble
9499
^^^^^^^^^^
95100

astroquery/esa/euclid/core.py

Lines changed: 142 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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:
@@ -1056,7 +1088,7 @@ def get_product_list(self, *, observation_id=None, tile_index=None, product_type
10561088
observation id for observations. It is not compatible with parameter tile_index.
10571089
10581090
Searchable products by observation_id: 'dpdVisRawFrame', 'dpdNispRawFrame',
1059-
,'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
1091+
'DpdVisCalibratedQuadFrame','DpdVisCalibratedFrameCatalog', 'DpdVisStackedFrame',
10601092
'DpdVisStackedFrameCatalog',
10611093
'DpdNirCalibratedFrame', 'DpdNirCalibratedFrameCatalog', 'DpdNirStackedFrameCatalog', 'DpdNirStackedFrame',
10621094
'DpdMerSegmentationMap', 'dpdMerFinalCatalog',
@@ -1439,6 +1471,110 @@ def __is_multiple(self, value):
14391471

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

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