1313
1414__all__ = ['SvoFpsClass' , 'SvoFps' ]
1515
16- # Valid query parameters taken from
16+
17+ # Parameters the SVO service accepts as either ``Name`` (base) or as a
18+ # range pair ``Name_min``/``Name_max``.
19+ RANGE_BASES = {"wavelength_ref" , "wavelength_mean" , "wavelength_eff" ,
20+ "wavelength_min" , "wavelength_max" , "width_eff" , "fwhm" }
21+
22+ # Base mapping from public (snake_case, lowercase) keyword names to the
23+ # CamelCase parameter names the SVO FPS server actually accepts. The SVO
24+ # service is case-sensitive: lowercase parameters silently fall through
25+ # (the server returns the full unfiltered response), so every value sent
26+ # in a query must come from this mapping. See
1727# https://svo2.cab.inta-csic.es/theory/fps/index.php?mode=voservice
18- _params_with_range = {"WavelengthRef" , "WavelengthMean" , "WavelengthEff" ,
19- "WavelengthMin" , "WavelengthMax" , "WidthEff" , "FWHM" }
20- QUERY_PARAMETERS = _params_with_range .copy ()
21- for suffix in ("_min" , "_max" ):
22- QUERY_PARAMETERS .update (param + suffix for param in _params_with_range )
23- QUERY_PARAMETERS .update (("Instrument" , "Facility" , "PhotSystem" , "ID" , "PhotCalID" ,
24- "FORMAT" , "VERB" ))
28+ BASE_PARAM_NAMES = {
29+ "wavelength_ref" : "WavelengthRef" ,
30+ "wavelength_mean" : "WavelengthMean" ,
31+ "wavelength_eff" : "WavelengthEff" ,
32+ "wavelength_min" : "WavelengthMin" ,
33+ "wavelength_max" : "WavelengthMax" ,
34+ "width_eff" : "WidthEff" ,
35+ "fwhm" : "FWHM" ,
36+ "instrument" : "Instrument" ,
37+ "facility" : "Facility" ,
38+ "phot_system" : "PhotSystem" ,
39+ "id" : "ID" ,
40+ "phot_cal_id" : "PhotCalID" ,
41+ "format" : "FORMAT" ,
42+ "verb" : "VERB" ,
43+ }
44+
45+ # Full mapping including the range variants, so a single dict lookup
46+ # resolves any user-facing kwarg.
47+ SVO_PARAM_NAMES = {
48+ ** BASE_PARAM_NAMES ,
49+ ** {f"{ k } _min" : f"{ v } _min"
50+ for k , v in BASE_PARAM_NAMES .items () if k in RANGE_BASES },
51+ ** {f"{ k } _max" : f"{ v } _max"
52+ for k , v in BASE_PARAM_NAMES .items () if k in RANGE_BASES },
53+ }
54+
55+ # Set of every valid public keyword name (used to validate **kwargs
56+ # passed to ``get_filter_metadata``).
57+ QUERY_PARAMETERS = set (SVO_PARAM_NAMES )
58+
59+ ALLOWED_QUERY_PARAMETERS = {
60+ "verb" : {0 , 1 , 2 },
61+ "format" : {"metadata" , None }
62+ }
63+
64+
65+ def to_svo_query (local_params ):
66+ """Translate a dict of public (snake_case) kwargs to the SVO native
67+ parameter names the server expects. ``None`` values are dropped so
68+ they aren't sent over the wire."""
69+ return {SVO_PARAM_NAMES [k ]: v for k , v in local_params .items ()
70+ if v is not None }
2571
2672
2773class SvoFpsClass (BaseQuery ):
@@ -31,21 +77,88 @@ class SvoFpsClass(BaseQuery):
3177 SVO_MAIN_URL = conf .base_url
3278 TIMEOUT = conf .timeout
3379
34- def data_from_svo (self , query , * , cache = True , timeout = None ,
35- error_msg = 'No data found for requested query' ):
80+ def data_from_svo (self ,
81+ * ,
82+ wavelength_ref_min = None ,
83+ wavelength_ref_max = None ,
84+ wavelength_mean_min = None ,
85+ wavelength_mean_max = None ,
86+ wavelength_eff_min = None ,
87+ wavelength_eff_max = None ,
88+ wavelength_min_min = None ,
89+ wavelength_min_max = None ,
90+ wavelength_max_min = None ,
91+ wavelength_max_max = None ,
92+ width_eff_min = None ,
93+ width_eff_max = None ,
94+ fwhm_min = None ,
95+ fwhm_max = None ,
96+ instrument = None ,
97+ facility = None ,
98+ phot_system = None ,
99+ id = None ,
100+ phot_cal_id = None ,
101+ format = None ,
102+ verb = 2 ,
103+ cache = True , timeout = None ,
104+ error_msg = 'No data found for requested query' ,
105+ ):
36106 """Get data in response to the query send to SVO FPS.
37107 This method is not generally intended for users, but it can be helpful
38108 if you want something very specific from the SVO FPS service.
39109 If you don't know what you're doing, try `get_filter_index`,
40110 `get_filter_list`, and `get_transmission_data` instead.
41111
112+ Description of search parameters can be found at
113+ https://svo2.cab.inta-csic.es/theory/fps/index.php?mode=voservice
114+
115+
42116 Parameters
43117 ----------
44- query : dict
45- Used to create a HTTP query string i.e. send to SVO FPS to get data.
46- In dictionary, specify keys as search parameters (str) and
47- values as required. Description of search parameters can be found at
48- https://svo2.cab.inta-csic.es/theory/fps/index.php?mode=voservice
118+ wavelength_ref_min : float, optional
119+ Min value for WavelengthRef parameter
120+ wavelength_ref_max : float, optional
121+ Max value for WavelengthRef parameter
122+ wavelength_mean_min : float, optional
123+ Min value for WavelengthMean parameter
124+ wavelength_mean_max : float, optional
125+ Max value for WavelengthMean parameter
126+ wavelength_eff_min : float, optional
127+ Min value for WavelengthEff parameter
128+ wavelength_eff_max : float, optional
129+ Max value for WavelengthEff parameter
130+ wavelength_min_min : float, optional
131+ Min value for WavelengthMin parameter
132+ wavelength_min_max : float, optional
133+ Max value for WavelengthMin parameter
134+ wavelength_max_min : float, optional
135+ Min value for WavelengthMax parameter
136+ wavelength_max_max : float, optional
137+ Max value for WavelengthMax parameter
138+ width_eff_min : float, optional
139+ Min value for WidthEff parameter
140+ width_eff_max : float, optional
141+ Max value for WidthEff parameter
142+ fwhm_min : float, optional
143+ Min value for FWHM parameter
144+ fwhm_max : float, optional
145+ Max value for FWHM parameter
146+ instrument : str, optional
147+ Instrument for filters (default is None). Leave empty if there are no instruments for specified facility
148+ facility : str, optional
149+ Facility for filters (default is None)
150+ phot_system : str, optional
151+ Photometric system for filters (default is None)
152+ id : str, optional
153+ Filter ID (default is None)
154+ phot_cal_id : str, optional
155+ Photometric calibration ID (default is None)
156+ format : str, optional
157+ Format of the output. Default includes all data, ``metadata`` includes only metadata.
158+ verb : 0, 1, or 2
159+ 0: The resulting VOTable won't include the transmission curve or PARAM descriptions.
160+ 1: The resulting VOTable won't include the transmission curve but it will include PARAM descriptions.
161+ 2: The resulting VOTable will include the transmission curve and PARAM descriptions.
49162 error_msg : str, optional
50163 Error message to be shown in case no table element found in the
51164 responded VOTable. Use this to make error message verbose in context
@@ -59,14 +172,40 @@ def data_from_svo(self, query, *, cache=True, timeout=None,
59172 astropy.table.table.Table object
60173 Table containing data fetched from SVO (in response to query)
61174 """
62- bad_params = [param for param in query if param not in QUERY_PARAMETERS ]
63- if bad_params :
64- raise InvalidQueryError (
65- f"parameter{ 's' if len (bad_params ) > 1 else '' } "
66- f"{ ', ' .join (bad_params )} { 'are' if len (bad_params ) > 1 else 'is' } "
67- f"invalid. For a description of valid query parameters see "
68- "https://svo2.cab.inta-csic.es/theory/fps/index.php?mode=voservice"
69- )
175+
176+ local_params = {
177+ 'wavelength_ref_min' : wavelength_ref_min ,
178+ 'wavelength_ref_max' : wavelength_ref_max ,
179+ 'wavelength_mean_min' : wavelength_mean_min ,
180+ 'wavelength_mean_max' : wavelength_mean_max ,
181+ 'wavelength_eff_min' : wavelength_eff_min ,
182+ 'wavelength_eff_max' : wavelength_eff_max ,
183+ 'wavelength_min_min' : wavelength_min_min ,
184+ 'wavelength_min_max' : wavelength_min_max ,
185+ 'wavelength_max_min' : wavelength_max_min ,
186+ 'wavelength_max_max' : wavelength_max_max ,
187+ 'width_eff_min' : width_eff_min ,
188+ 'width_eff_max' : width_eff_max ,
189+ 'fwhm_min' : fwhm_min ,
190+ 'fwhm_max' : fwhm_max ,
191+ 'instrument' : instrument ,
192+ 'facility' : facility ,
193+ 'phot_system' : phot_system ,
194+ 'id' : id ,
195+ 'phot_cal_id' : phot_cal_id ,
196+ 'format' : format ,
197+ 'verb' : verb ,
198+ }
199+
200+ # check validity of query parameters with limited allowed values
201+ for key in ALLOWED_QUERY_PARAMETERS :
202+ if key in local_params and local_params [key ] not in ALLOWED_QUERY_PARAMETERS [key ]:
203+ raise InvalidQueryError (
204+ f"Invalid value for parameter { key } . Allowed values are "
205+ f"{ ALLOWED_QUERY_PARAMETERS [key ]} "
206+ )
207+
208+ query = to_svo_query (local_params )
70209 response = self ._request ("GET" , self .SVO_MAIN_URL , params = query ,
71210 timeout = timeout or self .TIMEOUT ,
72211 cache = cache )
@@ -97,18 +236,21 @@ def get_filter_index(self, wavelength_eff_min, wavelength_eff_max, **kwargs):
97236 astropy.table.table.Table object
98237 Table containing data fetched from SVO (in response to query)
99238 """
100- query = {'WavelengthEff_min' : wavelength_eff_min .to_value (u .angstrom ),
101- 'WavelengthEff_max' : wavelength_eff_max .to_value (u .angstrom )}
102239 error_msg = 'No filter found for requested Wavelength Effective range'
103240 try :
104- return self .data_from_svo (query = query , error_msg = error_msg , ** kwargs )
241+ return self .data_from_svo (
242+ wavelength_eff_min = wavelength_eff_min .to_value (u .angstrom ),
243+ wavelength_eff_max = wavelength_eff_max .to_value (u .angstrom ),
244+ error_msg = error_msg ,
245+ ** kwargs
246+ )
105247 except requests .ReadTimeout :
106248 raise TimeoutError (
107249 "Query did not finish fast enough. A smaller wavelength range might "
108250 "succeed. Try increasing the timeout limit if a large range is needed."
109251 )
110252
111- def get_filter_metadata (self , filter_id , * , cache = True , timeout = None ):
253+ def get_filter_metadata (self , filter_id , * , cache = True , timeout = None , ** kwargs ):
112254 """Get metadata/parameters for the requested Filter ID from SVO
113255
114256 Parameters
@@ -122,13 +264,27 @@ def get_filter_metadata(self, filter_id, *, cache=True, timeout=None):
122264 See :ref:`caching documentation <astroquery_cache>`.
123265 timeout : int
124266 Timeout in seconds. If not specified, defaults to ``conf.timeout``.
267+ kwargs : dict
268+ Appended to the ``query`` dictionary sent to SVO. See the API
269+ documentation of `data_from_svo` for the valid parameter names.
125270
126271 Returns
127272 -------
128273 params : dict
129274 Dictionary of VOTable PARAM names and values.
130275 """
131- query = {'ID' : filter_id , 'VERB' : 0 }
276+ local_params = {'id' : filter_id , 'verb' : 0 }
277+ local_params .update (kwargs )
278+
279+ bad_params = [param for param in local_params if param not in QUERY_PARAMETERS ]
280+ if bad_params :
281+ raise InvalidQueryError (
282+ f"parameter{ 's' if len (bad_params ) > 1 else '' } "
283+ f"{ ', ' .join (bad_params )} { 'are' if len (bad_params ) > 1 else 'is' } "
284+ f"invalid. For a description of valid query parameters see the docstring for SvoFps.data_from_svo"
285+ )
286+
287+ query = to_svo_query (local_params )
132288 response = self ._request ("GET" , self .SVO_MAIN_URL , params = query ,
133289 timeout = timeout or self .TIMEOUT ,
134290 cache = cache )
@@ -143,6 +299,47 @@ def get_filter_metadata(self, filter_id, *, cache=True, timeout=None):
143299 params [param .name ] = param .value
144300 return params
145301
302+ def get_zeropoint (self , filter_id , * , mag_system = 'Vega' , ** kwargs ):
303+ """
304+ Get the zero point for a specififed filter in a specified system.
305+
306+ This is a highly-specific downselection of the metadata returned by
307+ `get_filter_metadata`; the full metadata includes the zero point with
308+ ``Vega`` as the default system.
309+
310+ Parameters
311+ ----------
312+ filter_id : str
313+ Filter ID in the format SVO specifies it: 'facilty/instrument.filter'.
314+ This is returned by `get_filter_list` and `get_filter_index` as the
315+ ``filterID`` column.
316+ mag_system : 'Vega' (default), 'AB', or 'ST'
317+ The magnitude system for which to return the zero point.
318+ kwargs : dict
319+ Appended to the ``query`` dictionary sent to SVO. See the API
320+ documentation of `data_from_svo` for the valid parameter names.
321+
322+ Examples
323+ --------
324+ >>> from astroquery.svo_fps import SvoFps # doctest: +REMOTE_DATA
325+ >>> SvoFps.get_zeropoint(filter_id='2MASS/2MASS.J', mag_system='AB') # doctest: +REMOTE_DATA
326+ {'MagSys': 'AB',
327+ 'ZeroPoint': <Quantity 3631. Jy>,
328+ 'ZeroPointUnit': 'Jy',
329+ 'ZeroPointType': 'Pogson'}
330+ """
331+ if mag_system not in ['Vega' , 'AB' , 'ST' ]:
332+ raise InvalidQueryError ("Invalid magnitude system. Allowed values are 'Vega', 'AB', and 'ST'." )
333+
334+ metadata = self .get_filter_metadata (filter_id = filter_id ,
335+ phot_cal_id = f'{ filter_id } /{ mag_system } ' , ** kwargs )
336+
337+ zeropoint_keys = ['MagSys' , 'ZeroPoint' , 'ZeroPointUnit' , 'ZeroPointType' ]
338+
339+ zp = {key : metadata [key ] for key in zeropoint_keys if key in metadata }
340+
341+ return zp
342+
146343 def get_transmission_data (self , filter_id , ** kwargs ):
147344 """Get transmission data for the requested Filter ID from SVO
148345
@@ -160,9 +357,8 @@ def get_transmission_data(self, filter_id, **kwargs):
160357 astropy.table.table.Table object
161358 Table containing data fetched from SVO (in response to query)
162359 """
163- query = {'ID' : filter_id }
164360 error_msg = 'No filter found for requested Filter ID'
165- return self .data_from_svo (query = query , error_msg = error_msg , ** kwargs )
361+ return self .data_from_svo (id = filter_id , error_msg = error_msg , ** kwargs )
166362
167363 def get_filter_list (self , facility , * , instrument = None , ** kwargs ):
168364 """Get filters data for requested facilty and instrument from SVO
@@ -182,10 +378,13 @@ def get_filter_list(self, facility, *, instrument=None, **kwargs):
182378 astropy.table.table.Table object
183379 Table containing data fetched from SVO (in response to query)
184380 """
185- query = {'Facility' : facility ,
186- 'Instrument' : instrument }
187381 error_msg = 'No filter found for requested Facilty (and Instrument)'
188- return self .data_from_svo (query = query , error_msg = error_msg , ** kwargs )
382+ return self .data_from_svo (
383+ facility = facility ,
384+ instrument = instrument ,
385+ error_msg = error_msg ,
386+ ** kwargs
387+ )
189388
190389
191390SvoFps = SvoFpsClass ()
0 commit comments