Skip to content

Commit fbc13c9

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

6 files changed

Lines changed: 387 additions & 15 deletions

File tree

CHANGES.rst

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

126126

127+
esa.euclid
128+
^^^^^^^^^^
129+
130+
- New method get_sia to access the Simple Image Access Protocol (SIAP) v2.0 [#3569]
131+
127132
esa.hubble
128133
^^^^^^^^^^
129134

astroquery/esa/euclid/core.py

Lines changed: 140 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,106 @@ 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+
Access the Euclid Observation Images by VO SIAP v2.0. This service will return public images from Calibrated
1523+
and Stacked NISP and VIS images, MER Mosaics from VIS and NISP and Level 1 (RAW) images for NISP and VIS
1524+
1525+
Parameters
1526+
----------
1527+
coordinates: str or SkyCoord, mandatory, default None
1528+
coordinates of the center in the cone search
1529+
radius: float or quantity, optional, default value 1 degree
1530+
radius in degrees for (int, float) or quantity of the cone_search
1531+
search_type : str, mandatory, default CIRCLE
1532+
search region: CIRCLE or BOX
1533+
calibration: int, optional, default 2
1534+
calibration level according to ObsCore VO standard: 0 (raw instrumental data), 1 (instrumental data in a
1535+
standard format), 2 (science ready data) or 3 (enhanced data products).
1536+
instrument: str, mandatory, default ALL
1537+
instrument name: ALL, VIS or NISP
1538+
band: str, optional, default None
1539+
filter name only valid if instrument is different from ALL: VIS for instrument VIS or NIR_H, NIR_J, NIR_Y
1540+
or NISP for instrument NISP
1541+
collection : str, mandatory, default sedm
1542+
the name of the data collection
1543+
dsr_part1: str, optional, default None
1544+
the data set release part 1: for OTF environment, the activity code; for REG and IDR, the target environment
1545+
dsr_part2: str, optional, default None
1546+
the data set release part 2: for OTF environment, the patch id (a positive integer); for REG and IDR,
1547+
the activity code
1548+
dsr_part3: str, optional, default None
1549+
the data set release part 3: for OTF, REG and IDR environment, the version (an integer greater than 1)
1550+
output_file : string, optional, default None
1551+
file where the results are saved.
1552+
verbose : bool, optional, default 'False'
1553+
flag to display information about the process
1554+
1555+
Returns
1556+
-------
1557+
An astropy.table or a votable file
1558+
"""
1559+
1560+
valid_search_types = {'CIRCLE', 'BOX'}
1561+
valid_calibrations = {0: 'CALIB_ZERO', 1: 'CALIB_ONE', 2: 'CALIB_TWO', 3: 'CALIB_THREE'}
1562+
valid_instruments = {'ALL', 'VIS', 'NISP'}
1563+
valid_band_vis = {'VIS'}
1564+
valid_band_nisp = {'NIR_H', 'NIR_J', 'NIR_Y', 'NISP'}
1565+
1566+
if search_type not in valid_search_types:
1567+
raise ValueError(f"Invalid search tyype {search_type}")
1568+
1569+
if calibration is not None and calibration not in valid_calibrations:
1570+
raise ValueError(f"Invalid calibration {calibration}")
1571+
1572+
if instrument not in valid_instruments:
1573+
raise ValueError(f"Invalid instrument {instrument}")
1574+
1575+
if instrument == 'ALL' and band is not None:
1576+
raise ValueError(f"For instrument {instrument} band must be None")
1577+
1578+
if instrument == 'VIS' and band is not None and band not in valid_band_vis:
1579+
raise ValueError(f"Invalid band {band} for instrument {instrument}")
1580+
1581+
if instrument == 'NISP' and band is not None and band not in valid_band_nisp:
1582+
raise ValueError(f"Invalid band {band} for instrument {instrument}")
1583+
1584+
if radius is not None:
1585+
coord = commons.parse_coordinates(coordinates=coordinates)
1586+
ra_deg = coord.ra.degree
1587+
dec_deg = coord.dec.degree
1588+
radius_deg = esautils.get_degree_radius(radius)
1589+
1590+
if radius_deg <= 0.0:
1591+
raise ValueError(f"Search radius is zero or negative: {radius}")
1592+
else:
1593+
raise ValueError(f"Invalid coordinates or search radius: {coordinates}, {radius}")
1594+
1595+
params_dict = dict()
1596+
params_dict['TAPCLIENT'] = 'ASTROQUERY'
1597+
params_dict['POS'] = f"{search_type},{ra_deg}, {dec_deg},{radius_deg}"
1598+
params_dict['INSTRUMENT'] = instrument
1599+
params_dict['COLLECTION'] = collection
1600+
1601+
if calibration is not None:
1602+
params_dict['CALIB'] = valid_calibrations[calibration]
1603+
1604+
if instrument != 'ALL' and band is not None:
1605+
params_dict['BAND'] = band
1606+
1607+
if dsr_part1 is not None:
1608+
params_dict['DSP1'] = dsr_part1
1609+
1610+
if dsr_part2 is not None:
1611+
params_dict['DSP2'] = dsr_part2
1612+
1613+
if dsr_part3 is not None:
1614+
params_dict['DSP3'] = dsr_part3
1615+
1616+
return self.__euclidsia.load_data(params_dict=params_dict, output_file=output_file, http_method='GET',
1617+
verbose=verbose)
1618+
14851619
@deprecated_renamed_argument(('instrument', 'id'), (None, None), since='0.4.12')
14861620
def get_cutout(self, *, file_path=None, coordinate, radius, output_file=None, verbose=False, instrument=None,
14871621
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)