• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jveitchmichaelis / rascal / 18630926536

19 Oct 2025 01:12PM UTC coverage: 91.723%. First build
18630926536

Pull #95

github

web-flow
Merge 1ab293551 into c6da64f2f
Pull Request #95: switch to uv

156 of 173 new or added lines in 14 files covered. (90.17%)

1884 of 2054 relevant lines covered (91.72%)

3.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.41
/src/rascal/atlas.py
1
import numpy as np
4✔
2
from .util import load_calibration_lines
4✔
3
from .util import vacuum_to_air_wavelength
4✔
4

5

6
class AtlasLine:
4✔
7
    def __init__(self, wavelength, element=None, intensity=None, source=None):
4✔
8
        self.wavelength = wavelength
4✔
9
        self.element = element
4✔
10
        self.intensity = intensity
4✔
11
        self.source = source
4✔
12

13

14
class Atlas:
4✔
15
    def __init__(
4✔
16
        self,
17
        elements=None,
18
        min_atlas_wavelength=3000.0,
19
        max_atlas_wavelength=5000.0,
20
        range_tolerance=500,
21
        min_intensity=10.0,
22
        min_distance=10.0,
23
        vacuum=False,
24
        pressure=101325.0,
25
        temperature=273.15,
26
        relative_humidity=0.0,
27
        linelist="nist",
28
    ):
29
        """
30
        Creates an atlas of arc lines.
31

32
        Arc lines are taken from a general list of NIST lines and can be
33
        filtered using the minimum relative intensity (note this may not be
34
        accurate due to instrumental effects such as detector response,
35
        dichroics, etc) and minimum line separation.
36

37
        Lines are filtered first by relative intensity, then by separation.
38
        This is to improve robustness in the case where there is a strong
39
        line very close to a weak line (which is within the separation limit).
40

41
        The vacuum to air wavelength conversion is deafult to False because
42
        observatories usually provide the line lists in the respective air
43
        wavelength, as the corrections from temperature and humidity are
44
        small. See https://emtoolbox.nist.gov/Wavelength/Documentation.asp
45

46
        Parameters
47
        ----------
48
        elements: string or list of strings
49
            Chemical symbol, case insensitive
50
        min_atlas_wavelength: float (default: None)
51
            Minimum wavelength of the arc lines.
52
        max_atlas_wavelength: float (default: None)
53
            Maximum wavelength of the arc lines.
54
        range_tolerance: float (default 500.)
55
            Range tolerance to add to min/max wavelengths
56
        min_intensity: float (default: None)
57
            Minimum intensity of the arc lines. Refer to NIST for the
58
            intensity.
59
        min_distance: float (default: None)
60
            Minimum separation between neighbouring arc lines.
61
        vacuum: boolean
62
            Set to True if the light path from the arc lamb to the detector
63
            plane is entirely in vacuum.
64
        pressure: float
65
            Pressure when the observation took place, in Pascal.
66
            If it is not known, we suggest you to assume 10% decrement per
67
            1000 meter altitude.
68
        temperature: float
69
            Temperature when the observation took place, in Kelvin.
70
        relative_humidity: float
71
            In percentage.
72

73
        """
74

75
        self.atlas_lines = []
4✔
76
        self.min_atlas_wavelength = min_atlas_wavelength
4✔
77
        self.max_atlas_wavelength = max_atlas_wavelength
4✔
78
        self.min_intensity = min_intensity
4✔
79
        self.min_distance = min_distance
4✔
80
        self.range_tolerance = range_tolerance
4✔
81

82
        if elements is not None:
4✔
83
            self.add(
×
84
                elements=elements,
85
                min_atlas_wavelength=min_atlas_wavelength,
86
                max_atlas_wavelength=max_atlas_wavelength,
87
                min_intensity=min_intensity,
88
                min_distance=min_distance,
89
                vacuum=vacuum,
90
                pressure=pressure,
91
                temperature=temperature,
92
                relative_humidity=relative_humidity,
93
                linelist=linelist,
94
            )
95

96
    def add(
4✔
97
        self,
98
        elements=None,
99
        min_atlas_wavelength=None,
100
        max_atlas_wavelength=None,
101
        min_intensity=10.0,
102
        min_distance=10.0,
103
        vacuum=False,
104
        pressure=101325.0,
105
        temperature=273.15,
106
        relative_humidity=0.0,
107
        linelist="nist",
108
        brightest_n_lines=1000,
109
    ):
110
        """
111
        Adds arc lines to the atlas
112

113
        Arc lines are taken from a general list of NIST lines and can be
114
        filtered using the minimum relative intensity (note this may not be
115
        accurate due to instrumental effects such as detector response,
116
        dichroics, etc) and minimum line separation.
117

118
        Lines are filtered first by relative intensity, then by separation.
119
        This is to improve robustness in the case where there is a strong
120
        line very close to a weak line (which is within the separation limit).
121

122
        The vacuum to air wavelength conversion is deafult to False because
123
        observatories usually provide the line lists in the respective air
124
        wavelength, as the corrections from temperature and humidity are
125
        small. See https://emtoolbox.nist.gov/Wavelength/Documentation.asp
126

127
        Parameters
128
        ----------
129
        elements: string or list of strings
130
            Chemical symbol, case insensitive
131
        min_atlas_wavelength: float (default: None)
132
            Minimum wavelength of the arc lines.
133
        max_atlas_wavelength: float (default: None)
134
            Maximum wavelength of the arc lines.
135
        min_intensity: float (default: None)
136
            Minimum intensity of the arc lines. Refer to NIST for the
137
            intensity.
138
        min_distance: float (default: None)
139
            Minimum separation between neighbouring arc lines.
140
        vacuum: boolean
141
            Set to True if the light path from the arc lamb to the detector
142
            plane is entirely in vacuum.
143
        pressure: float
144
            Pressure when the observation took place, in Pascal.
145
            If it is not known, we suggest you to assume 10% decrement per
146
            1000 meter altitude.
147
        temperature: float
148
            Temperature when the observation took place, in Kelvin.
149
        relative_humidity: float
150
            In percentage.
151

152
        """
153

154
        if min_atlas_wavelength is None:
4✔
155
            min_atlas_wavelength = self.min_atlas_wavelength - self.range_tolerance
4✔
156

157
        if max_atlas_wavelength is None:
4✔
158
            max_atlas_wavelength = self.max_atlas_wavelength + self.range_tolerance
4✔
159

160
        if not np.isfinite(min_atlas_wavelength):
4✔
NEW
161
            raise ValueError("min_atlas_wavelength has to be finite or None. {} is given.".format(min_atlas_wavelength))
×
162

163
        if not np.isfinite(max_atlas_wavelength):
4✔
NEW
164
            raise ValueError("max_atlas_wavelength has to be finite or None. {} is given.".format(max_atlas_wavelength))
×
165

166
        if isinstance(elements, str):
4✔
167
            elements = [elements]
4✔
168

169
        if elements is not None:
4✔
170
            for element in elements:
4✔
171
                (
4✔
172
                    atlas_elements_tmp,
173
                    atlas_tmp,
174
                    atlas_intensities_tmp,
175
                ) = load_calibration_lines(
176
                    elements=element,
177
                    min_atlas_wavelength=min_atlas_wavelength,
178
                    max_atlas_wavelength=max_atlas_wavelength,
179
                    min_intensity=min_intensity,
180
                    min_distance=min_distance,
181
                    vacuum=vacuum,
182
                    pressure=pressure,
183
                    temperature=temperature,
184
                    relative_humidity=relative_humidity,
185
                    linelist=linelist,
186
                    brightest_n_lines=brightest_n_lines,
187
                )
188

189
                for element, line, intensity in list(zip(atlas_elements_tmp, atlas_tmp, atlas_intensities_tmp)):
4✔
190
                    self.atlas_lines.append(AtlasLine(line, element, intensity, "NIST"))
4✔
191

192
    def add_user_atlas(
4✔
193
        self,
194
        elements,
195
        wavelengths,
196
        intensities=None,
197
        vacuum=False,
198
        pressure=101325.0,
199
        temperature=273.15,
200
        relative_humidity=0.0,
201
    ):
202
        """
203
        Add a single or list of arc lines. Each arc line should have an
204
        element label associated with it. It is recommended that you use
205
        a standard periodic table abbreviation (e.g. 'Hg'), but it makes
206
        no difference to the fitting process.
207

208
        The vacuum to air wavelength conversion is deafult to False because
209
        observatories usually provide the line lists in the respective air
210
        wavelength, as the corrections from temperature and humidity are
211
        small. See https://emtoolbox.nist.gov/Wavelength/Documentation.asp
212

213
        Parameters
214
        ----------
215
        elements: list/str
216
            Elements (required). Preferably a standard (i.e. periodic table)
217
            name for convenience with built-in atlases
218
        wavelengths: list/float
219
            Wavelengths to add (Angstrom)
220
        intensities: list/float
221
            Relative line intensities (NIST value)
222
        vacuum: boolean
223
            Set to true to convert the input wavelength to air-wavelengths
224
            based on the given pressure, temperature and humidity.
225
        pressure: float
226
            Pressure when the observation took place, in Pascal.
227
            If it is not known, assume 10% decrement per 1000 meter altitude
228
        temperature: float
229
            Temperature when the observation took place, in Kelvin.
230
        relative_humidity: float
231
            In percentage.
232

233
        """
234

235
        if not isinstance(elements, list):
4✔
236
            elements = list(elements)
×
237

238
        if not isinstance(wavelengths, list):
4✔
239
            wavelengths = list(wavelengths)
4✔
240

241
        if intensities is None:
4✔
242
            intensities = [0] * len(wavelengths)
4✔
243

244
        else:
245
            if not isinstance(intensities, list):
×
246
                intensities = list(intensities)
×
247

248
        assert len(elements) == len(wavelengths), ValueError("Input elements and wavelengths have different length.")
4✔
249
        assert len(elements) == len(intensities), ValueError("Input elements and intensities have different length.")
4✔
250

251
        if vacuum:
4✔
NEW
252
            wavelengths = vacuum_to_air_wavelength(wavelengths, temperature, pressure, relative_humidity)
×
253

254
        self.min_atlas_wavelength = min(wavelengths)
4✔
255
        self.max_atlas_wavelength = max(wavelengths)
4✔
256

257
        for element, line, intensity in list(zip(elements, wavelengths, intensities)):
4✔
258
            self.atlas_lines.append(AtlasLine(line, element, intensity))
4✔
259

260
    def get_lines(self):
4✔
261
        """
262
        Returns a list of line wavelengths in the atlas
263

264
        Returns
265
            wavelength_list: list
266

267
        """
268
        return [line.wavelength for line in self.atlas_lines]
4✔
269

270
    def get_elements(self):
4✔
271
        """
272
        Returns a list of per-line elements in the atlas
273

274
        Returns
275
            element_list: list
276

277
        """
278

279
        return [line.element for line in self.atlas_lines]
4✔
280

281
    def get_intensities(self):
4✔
282
        """
283
        Returns a list of per-line intensities in the atlas
284

285
        Returns
286
            intensity_list: list
287

288
        """
289

290
        return [line.intensity for line in self.atlas_lines]
×
291

292
    def remove_atlas_lines_range(self, wavelength, tolerance=10):
4✔
293
        """
294
        Remove arc lines within a certain wavelength range.
295

296
        Parameters
297
        ----------
298
        wavelength: float
299
            Wavelength to remove (Angstrom)
300
        tolerance: float
301
            Tolerance around this wavelength where atlas lines will be removed
302

303
        """
304

305
        for atlas_line in self.atlas_lines:
4✔
306
            if abs(atlas_line.wavelength - wavelength) < tolerance:
4✔
307
                self.atlas_lines.remove(atlas_line)
4✔
308

309
    def list(self):
4✔
310
        """
311
        List all the lines loaded to the Calibrator.
312

313
        """
314

315
        for line in self.atlas_lines:
4✔
316
            print("Element " + str(line.element) + " at " + str(line.wavelength) + " with intensity " + str(line.intensity))
4✔
317

318
    def clear(self):
4✔
319
        """
320
        Remove all the lines loaded to the Calibrator.
321

322
        """
323

324
        self.atlas_lines.clear()
4✔
325

326
    def __len__(self):
4✔
327
        return len(self.atlas_lines)
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc