astropy / astroquery
1
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2 1
from __future__ import print_function
3

4 1
import re
5

6 1
import astropy.units as u
7 1
import astropy.io.ascii as asciitable
8 1
from six import PY2
9

10 1
from ..query import BaseQuery
11 1
from ..utils import async_to_sync, prepend_docstr_nosections
12 1
from . import conf
13 1
from ..exceptions import TableParseError
14

15 1
if not PY2:
16 1
    import html  # html is available in Py3 stdlib, but not in Py2
17

18 1
__all__ = ['Nist', 'NistClass']
19

20

21 1
def _strip_blanks(table):
22
    """
23
    Remove blank lines from table (included for "human readability" but
24
    useless to us...
25
    returns a single string joined by \n newlines
26

27
    Parameters
28
    ----------
29
    table : str
30
       table to strip as a string
31

32
    Returns
33
    -------
34
    single string joined by newlines.
35
    """
36 1
    numbersletters = re.compile("[0-9A-Za-z]")
37 1
    if isinstance(table, str):
38 1
        table = table.split('\n')
39 1
    table = [line for line in table if numbersletters.search(line)]
40 1
    return "\n".join(table)
41

42

43 1
@async_to_sync
44 1
class NistClass(BaseQuery):
45 1
    URL = conf.server
46 1
    TIMEOUT = conf.timeout
47 1
    unit_code = {'Angstrom': 0,
48
                 'nm': 1,
49
                 'um': 2}
50 1
    energy_level_code = {'cm-1': 0, 'invcm': 0, 'cm': 0,
51
                         'ev': 1, 'eV': 1, 'EV': 1, 'electronvolt': 1,
52
                         'R': 2, 'Rydberg': 2, 'rydberg': 2}
53 1
    order_out_code = {'wavelength': 0,
54
                      'multiplet': 1}
55 1
    wavelength_unit_code = {'vacuum': 3,
56
                            'vac+air': 4}
57

58 1
    def _args_to_payload(self, *args, **kwargs):
59
        """
60
        Serves the same purpose as `~NistClass.query` but returns
61
        the raw HTTP response rather than a `~astropy.table.Table` object.
62

63
        Parameters
64
        ----------
65
        minwav : `astropy.units.Quantity` object
66
            The lower wavelength for the spectrum in appropriate units.
67
        maxwav : `astropy.units.Quantity` object
68
            The upper wavelength for the spectrum in appropriate units.
69
        linename : str, optional
70
            The spectrum to fetch. Defaults to "H I"
71
        energy_level_unit : str, optional
72
            The energy level units must be one of the following:
73
            'R', 'Rydberg', 'rydberg', 'cm', 'cm-1', 'EV', 'eV',
74
            'electronvolt', 'ev', 'invcm' Defaults to 'eV'.
75
        output_order : str, optional
76
            Decide ordering of output. Must be one of following:
77
            ['wavelength', 'multiplet']. Defaults to 'wavelength'.
78
        wavelength_type : str, optional
79
            Must be one of 'vacuum' or 'vac+air'. Defaults to 'vacuum'.
80
        get_query_payload : bool, optional
81
            If true then returns the dictionary of query parameters, posted to
82
            remote server. Defaults to `False`.
83

84
        Returns
85
        -------
86
        request_payload : dict
87
            The dictionary of parameters sent with the HTTP request
88

89
        """
90 1
        request_payload = {}
91 1
        request_payload["spectra"] = kwargs['linename']
92 1
        (min_wav, max_wav, wav_unit) = _parse_wavelength(args[0], args[1])
93 1
        request_payload["low_wl"] = min_wav
94 1
        request_payload["upp_wl"] = max_wav
95 1
        request_payload["unit"] = wav_unit
96 1
        request_payload["submit"] = "Retrieve Data"
97 1
        request_payload["format"] = 1  # ascii
98 1
        request_payload["line_out"] = 0  # All lines
99 1
        request_payload["en_unit"] = Nist.energy_level_code[
100
            kwargs["energy_level_unit"]]
101 1
        request_payload["output"] = 0  # entirely rather than pagewise
102 1
        request_payload["bibrefs"] = 1
103 1
        request_payload["show_obs_wl"] = 1
104 1
        request_payload["show_calc_wl"] = 1
105 1
        request_payload["order_out"] = Nist.order_out_code[
106
            kwargs['output_order']]
107 1
        request_payload["max_low_enrg"] = ""
108 1
        request_payload["show_av"] = Nist.wavelength_unit_code[
109
            kwargs['wavelength_type']]
110 1
        request_payload["max_upp_enrg"] = ""
111 1
        request_payload["tsb_value"] = 0
112 1
        request_payload["min_str"] = ""
113 1
        request_payload["A_out"] = 0
114 1
        request_payload["f_out"] = "on"
115 1
        request_payload["intens_out"] = "on"
116 1
        request_payload["max_str"] = ""
117 1
        request_payload["allowed_out"] = 1
118 1
        request_payload["forbid_out"] = 1
119 1
        request_payload["min_accur"] = ""
120 1
        request_payload["min_intens"] = ""
121 1
        request_payload["conf_out"] = "on"
122 1
        request_payload["term_out"] = "on"
123 1
        request_payload["enrg_out"] = "on"
124 1
        request_payload["J_out"] = "on"
125 1
        request_payload["page_size"] = 15
126 1
        request_payload["remove_js"] = "on"
127 1
        request_payload["show_wn"] = 1
128 1
        return request_payload
129

130 1
    @prepend_docstr_nosections("\n" + _args_to_payload.__doc__)
131 1
    def query_async(self, minwav, maxwav, linename="H I",
132
                    energy_level_unit='eV', output_order='wavelength',
133
                    wavelength_type='vacuum', get_query_payload=False):
134
        """
135
        Returns
136
        -------
137
        response : `requests.Response` object
138
            The response of the HTTP request.
139
        """
140 1
        request_payload = self._args_to_payload(
141
            minwav, maxwav, linename=linename,
142
            energy_level_unit=energy_level_unit, output_order=output_order,
143
            wavelength_type=wavelength_type)
144 1
        if get_query_payload:
145 1
            return request_payload
146

147 1
        response = self._request("GET", url=Nist.URL, params=request_payload,
148
                                 timeout=Nist.TIMEOUT)
149 1
        return response
150

151 1
    def _parse_result(self, response, verbose=False):
152
        """
153
        Parses the results from the HTTP response to `astropy.table.Table`.
154

155
        Parameters
156
        ----------
157
        response : `requests.Response`
158
            The HTTP response object
159

160
        Returns
161
        -------
162
        table : `astropy.table.Table`
163
        """
164

165 1
        pre_re = re.compile("<pre>(.*)</pre>", flags=re.DOTALL)
166 1
        links_re = re.compile(r"<a.*?>\s*(\w+)\s*</a>")
167 1
        content = str(response.text)
168

169 1
        try:
170 1
            pre = pre_re.findall(content)[0]
171 0
        except IndexError:
172 0
            raise Exception("Result did not contain a table")
173 1
        try:
174 1
            table = _strip_blanks(pre)
175 1
            table = links_re.sub(r'\1', table)
176 1
            if not PY2:
177 1
                table = html.unescape(table)
178 1
            table = asciitable.read(table, Reader=asciitable.FixedWidth,
179
                                    data_start=3, delimiter='|')
180 1
            return table
181 0
        except Exception as ex:
182 0
            self.response = response
183 0
            self.table_parse_error = ex
184 0
            raise TableParseError("Failed to parse asciitable! The raw "
185
                                  "response can be found in self.response, "
186
                                  "and the error in self.table_parse_error.")
187

188

189 1
Nist = NistClass()
190

191

192 1
def _parse_wavelength(min_wav, max_wav):
193
    """
194
    Helper function to return wavelength and units in form accepted by NIST
195

196
    Parameters
197
    ----------
198
    min_wav : `astropy.units.Quantity` object
199
        The lower wavelength in proper units.
200
    max_wav : `astropy.units.Quantity` object
201
        The upper wavelength in proper units.
202

203
    Returns
204
    -------
205
    tuple : (number, number, number)
206
        The value of lower, upper wavelength and their unit.
207
    """
208 1
    max_wav = max_wav.to(min_wav.unit)
209 1
    wav_unit = min_wav.unit.to_string()
210 1
    if wav_unit not in Nist.unit_code:
211 0
        max_wav = max_wav.to(u.angstrom).value
212 0
        min_wav = min_wav.to(u.angstrom).value
213 0
        wav_unit = Nist.unit_code['Angstrom']
214
    else:
215 1
        max_wav = max_wav.value
216 1
        min_wav = min_wav.value
217 1
        wav_unit = Nist.unit_code[wav_unit]
218 1
    return (min_wav, max_wav, wav_unit)

Read our documentation on viewing source code .

Loading