diff --git a/CHANGES.rst b/CHANGES.rst index 9be6958c7a..c13f80e842 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -48,6 +48,7 @@ svo_fps ^^^^^^^ - Add ``get_filter_metadata`` to allow retrieval of filter metadata. [#3528] +- Add ``get_zeropoint`` to allow retrieval of filter zeropoints and allow kwarg passing to ``get_filter_metadata``. [#3545] heasarc ^^^^^^^ diff --git a/astroquery/svo_fps/core.py b/astroquery/svo_fps/core.py index e8686ada8c..b2717b51a1 100644 --- a/astroquery/svo_fps/core.py +++ b/astroquery/svo_fps/core.py @@ -108,7 +108,7 @@ def get_filter_index(self, wavelength_eff_min, wavelength_eff_max, **kwargs): "succeed. Try increasing the timeout limit if a large range is needed." ) - def get_filter_metadata(self, filter_id, *, cache=True, timeout=None): + def get_filter_metadata(self, filter_id, *, cache=True, timeout=None, **kwargs): """Get metadata/parameters for the requested Filter ID from SVO Parameters @@ -122,6 +122,8 @@ def get_filter_metadata(self, filter_id, *, cache=True, timeout=None): See :ref:`caching documentation `. timeout : int Timeout in seconds. If not specified, defaults to ``conf.timeout``. + kwargs : dict + Appended to the ``query`` dictionary sent to SVO. Returns ------- @@ -129,6 +131,17 @@ def get_filter_metadata(self, filter_id, *, cache=True, timeout=None): Dictionary of VOTable PARAM names and values. """ query = {'ID': filter_id, 'VERB': 0} + query.update(kwargs) + + bad_params = [param for param in query if param not in QUERY_PARAMETERS] + if bad_params: + raise InvalidQueryError( + f"parameter{'s' if len(bad_params) > 1 else ''} " + f"{', '.join(bad_params)} {'are' if len(bad_params) > 1 else 'is'} " + f"invalid. For a description of valid query parameters see " + "https://svo2.cab.inta-csic.es/theory/fps/index.php?mode=voservice" + ) + response = self._request("GET", self.SVO_MAIN_URL, params=query, timeout=timeout or self.TIMEOUT, cache=cache) @@ -143,6 +156,53 @@ def get_filter_metadata(self, filter_id, *, cache=True, timeout=None): params[param.name] = param.value return params + def get_zeropoint(self, filter_id, mag_system='Vega', **kwargs): + """ + Get the zero point for a specififed filter in a specified system. + + This is a highly-specific downselection of the metadata returned by + `get_filter_metadata`; the full metadata includes the zero point with + ``Vega`` as the default system. + + Parameters + ---------- + filter_id : str + Filter ID in the format SVO specifies it: 'facilty/instrument.filter'. + This is returned by `get_filter_list` and `get_filter_index` as the + ``filterID`` column. + mag_system : str + The magnitude system for which to return the zero point. + kwargs : dict + Appended to the ``query`` dictionary sent to SVO. + + Examples + -------- + >>> from astroquery.svo_fps import SvoFps # doctest: +REMOTE_DATA + >>> SvoFps.get_zeropoint(filter_id='2MASS/2MASS.J', mag_system='AB') # doctest: +REMOTE_DATA + {'MagSys': 'AB', + 'ZeroPoint': , + 'ZeroPointUnit': 'Jy', + 'ZeroPointType': 'Pogson'} + >>> SvoFps.get_filter_metadata(filter_id='2MASS/2MASS.J', PhotCalID='2MASS/2MASS.J/AB') # doctest: +REMOTE_DATA + {'FilterProfileService': 'ivo://svo/fps', + 'filterID': '2MASS/2MASS.J', + ... + 'PhotCalID': '2MASS/2MASS.J/AB', + 'MagSys': 'AB', + 'ZeroPoint': , + 'ZeroPointUnit': 'Jy', + 'ZeroPointType': 'Pogson'} + + """ + metadata = self.get_filter_metadata(filter_id=filter_id, + PhotCalID=f'{filter_id}/{mag_system}', **kwargs) + + zeropoint_keys = ['MagSys', 'ZeroPoint', 'ZeroPointUnit', 'ZeroPointType'] + + zp = {key: metadata[key] for key in zeropoint_keys if key in metadata} + + return zp + def get_transmission_data(self, filter_id, **kwargs): """Get transmission data for the requested Filter ID from SVO diff --git a/astroquery/svo_fps/tests/data/svo_fps_PhotCalID=2MASS.2MASS.H.Vega.xml b/astroquery/svo_fps/tests/data/svo_fps_PhotCalID=2MASS.2MASS.H.Vega.xml new file mode 100644 index 0000000000..cc7dab20af --- /dev/null +++ b/astroquery/svo_fps/tests/data/svo_fps_PhotCalID=2MASS.2MASS.H.Vega.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + Manually specified. See reference + + + + + + + + + + +
+
+
diff --git a/astroquery/svo_fps/tests/test_svo_fps.py b/astroquery/svo_fps/tests/test_svo_fps.py index d8c8c36047..9d8b289793 100644 --- a/astroquery/svo_fps/tests/test_svo_fps.py +++ b/astroquery/svo_fps/tests/test_svo_fps.py @@ -9,12 +9,14 @@ DATA_FILES = {'filter_index': 'svo_fps_WavelengthEff_min=12000_WavelengthEff_max=12100.xml', 'transmission_data': 'svo_fps_ID=2MASS.2MASS.H.xml', - 'filter_list': 'svo_fps_Facility=Keck_Instrument=NIRC2.xml' + 'filter_list': 'svo_fps_Facility=Keck_Instrument=NIRC2.xml', + 'zeropoint': 'svo_fps_PhotCalID=2MASS.2MASS.H.Vega.xml', } TEST_LAMBDA = 12000 TEST_FILTER_ID = '2MASS/2MASS.H' TEST_FACILITY = 'Keck' TEST_INSTRUMENT = 'NIRC2' +TEST_MAG_SYSTEM = 'Vega' def data_path(filename): @@ -35,6 +37,10 @@ def get_mockreturn(method, url, params=None, timeout=10, cache=None, **kwargs): and (params['WavelengthEff_min'] == TEST_LAMBDA and params['WavelengthEff_max'] == TEST_LAMBDA+100)): filename = data_path(DATA_FILES['filter_index']) + elif ('PhotCalID' in params + and params.get('ID') == TEST_FILTER_ID + and params['PhotCalID'] == f'{TEST_FILTER_ID}/{TEST_MAG_SYSTEM}'): + filename = data_path(DATA_FILES['zeropoint']) elif 'ID' in params and params['ID'] == TEST_FILTER_ID: filename = data_path(DATA_FILES['filter_index']) elif 'Facility' in params and (params['Facility'] == TEST_FACILITY @@ -84,6 +90,17 @@ def test_get_filter_list(patch_get): assert 'filterID' in table.colnames +def test_get_zeropoint(patch_get): + zp = SvoFps.get_zeropoint(TEST_FILTER_ID, mag_system=TEST_MAG_SYSTEM) + assert 'ZeroPoint' in zp + assert 'MagSys' in zp + assert zp['MagSys'] == TEST_MAG_SYSTEM + assert 'ZeroPointType' in zp + assert zp['ZeroPointType'] == 'Pogson' + assert 'ZeroPointUnit' in zp + assert zp['ZeroPoint'].unit == u.Jy + + def test_invalid_query(patch_get): msg = r"^parameter bad_param is invalid\. For a description of valid query " with pytest.raises(InvalidQueryError, match=msg): diff --git a/astroquery/svo_fps/tests/test_svo_fps_remote.py b/astroquery/svo_fps/tests/test_svo_fps_remote.py index e195318dc0..cab0bdfc13 100644 --- a/astroquery/svo_fps/tests/test_svo_fps_remote.py +++ b/astroquery/svo_fps/tests/test_svo_fps_remote.py @@ -40,6 +40,23 @@ def test_get_filter_list(self, test_facility, test_instrument): # Check if column for Filter ID (named 'filterID') exists in table assert 'filterID' in table.colnames + @pytest.mark.parametrize('test_filter_id, mag_system, expected_zp_jy', [ + ('2MASS/2MASS.J', 'Vega', 1594.0), + ('2MASS/2MASS.J', 'AB', 3631.0), + ]) + def test_get_zeropoint(self, test_filter_id, mag_system, expected_zp_jy): + zp = SvoFps.get_zeropoint(test_filter_id, mag_system=mag_system) + # Check all expected keys are present + assert 'ZeroPoint' in zp + assert 'MagSys' in zp + assert 'ZeroPointType' in zp + assert 'ZeroPointUnit' in zp + # Check the magnitude system matches what was requested + assert zp['MagSys'] == mag_system + # Check zero point has the right unit and an approximately correct value + assert zp['ZeroPoint'].unit == u.Jy + assert abs(zp['ZeroPoint'].value - expected_zp_jy) < 10.0 + def test_query_parameter_names(self): # Checks if `QUERY_PARAMETERS` is up to date. query = {"FORMAT": "metadata"}