This module groups small, self-contained utilities used across the package and the jupyter notebook examples:
table, spectrum and ephemeris loaders, and some numerical and analytical helpers for
seeing-dependent slit-loss estimates.
Notes
Packaged data files live under cometspec/data/. The get_*_path
helpers resolve those locations relative to the installed package.
Wavelengths returned by line-list loaders are in vacuum Angstrom unless
documented otherwise.
Build wavelength-dependent seeing bounds from the minimum and maximum seeing values (at zenith) and the minimum and maximum zenith angles. See Persson (2022) [1].
Parameters:
eps_min_arcsec_500 (float) – Minimum seeing at 500nm and zenith, in arcsec. It can be at any other wavelength, but lambda0_nm and alpha must be set accordingly.
eps_max_arcsec_500 (float) – Maximum seeing at 500nm and zenith, in arcsec.
k (float, optional, default0.6) – Airmass scaling exponent.
Returns:
tuple[callable, callable] – A pair (fwhm_min,fwhm_max) of callables that evaluate the minimum and maximum FWHM in arcsec as a function of wavelength given the max and min seeing and zenith angles. Each callable takes x:floatorndarrayoffloat and returns f(x):floatorndarrayoffloatofthesameshape.
Raises:
ValueError – If a zenith angle is greater than or equal to 90 degrees.
Estimate the aperture-enclosed flux fraction and slit loss as a function of wavelength.
Computes, over a wavelength grid, the fraction of a Gaussian PSF that falls
within the given aperture for both the best-case (sharpest PSF) and worst-case
(broadest PSF) observing conditions, defined by the seeing and zenith-angle ranges.
Note
The _min / _max suffix in the output keys refers to the input
seeing/zenith extremes ( _min / _maxFWHM), not to the numerical ordering of the output values.
Because a sharper PSF concentrates more flux, frac_min (best seeing) is
numerically larger than frac_max (worst seeing), and loss_min is
numerically smaller than loss_max.
Parameters:
lambda_min_nm (float) – Minimum wavelength of the evaluation grid, in nm.
lambda_max_nm (float) – Maximum wavelength of the evaluation grid, in nm.
eps_min_arcsec_500 (float) – Best (minimum) seeing FWHM at 500 nm and zenith, in arcsec.
eps_max_arcsec_500 (float) – Worst (maximum) seeing FWHM at 500 nm and zenith, in arcsec.
zmin_deg (float) – Minimum (best) zenith angle during observations, in degrees (zenith angle = 90° - elevation angle).
zmax_deg (float) – Maximum (worst) zenith angle during observations, in degrees (zenith angle = 90° - elevation angle).
fwhm_min_arcsec (numpy.ndarray of float) – PSF FWHM at best seeing (eps_min, zmin)
as a function of wavelength, in arcsec. Numerically the smallest FWHM values.
fwhm_max_arcsec (numpy.ndarray of float) – PSF FWHM at worst seeing (eps_max, zmax)
as a function of wavelength, in arcsec. Numerically the largest FWHM values.
frac_min (numpy.ndarray of float) – Enclosed flux fraction at best seeing conditions.
Numerically the largest fraction (sharpest PSF → most flux within aperture).
frac_max (numpy.ndarray of float) – Enclosed flux fraction at worst seeing conditions.
Numerically the smallest fraction (broadest PSF → least flux within aperture).
loss_min (numpy.ndarray of float) – Slit loss at best seeing, i.e. 1-frac_min.
Numerically the smallest loss.
loss_max (numpy.ndarray of float) – Slit loss at worst seeing, i.e. 1-frac_max.
Numerically the largest loss.
Raises:
ValueError – If n_points is smaller than 2 or aperture['type']
is not 'circular' or 'rectangular'.
Add slit-loss uncertainty to the log10 error of a log10 quantity.
Evaluates the aperture-enclosed flux fraction over a narrow wavelength window
centred on lambda_nm for both the best- and worst-case seeing/zenith
conditions (see throughput_vs_lambda()). From those two flux fractions it derives a symmetric systematic
uncertainty in log10 space via a geometric-mean scaling, then adds it in
quadrature to the input statistical error.
Where \(\sigma_\mathrm{stat}\) is the input statistical error q_err, and \(\bar{f}_\mathrm{min}\) and \(\bar{f}_\mathrm{max}\) are the mean flux fractions over the wavelength window for the best and worst seeing/zenith conditions, respectively.
Important
q_errmust be the error of a log10 quantity
proportional to the aperture-collected flux (e.g., log10(F),
log10(N) for a column density inferred from line flux, or any
derived quantity Q such that Q∝F). The slit loss multiplies
the true flux by a fraction f∈(0,1], so on a log scale it acts
as an additive shift Δlog10(Q)=log10(f). The systematic-error
derivation in this function assumes exactly that additive structure;
feeding it a linear-space value or a quantity not proportional to flux
will produce an incorrect uncertainty.
Note
The wavelength window used for the flux-fraction estimate is
[lambda_nm-0.01,lambda_nm+0.01] nm, sampled with n_points
points, and the result flux fraction is averaged over that window.
Parameters:
q_err (float) – One-sigma statistical uncertainty in log10 space from a quantity proportional to the aperture-collected flux (e.g., the error of log10(column density)).
lambda_nm (float) – Central wavelength at which to evaluate the slit-loss
systematic, in nm.
aperture (dict) – Aperture definition. Must contain the key 'type' with
value 'circular' or 'rectangular'. For circular apertures, also
requires 'radius_arcsec' (float). For rectangular apertures, requires
'width_arcsec' and 'length_arcsec' (both float).
eps_min_arcsec_500 (float, optional, default0.7) – Best (minimum) seeing FWHM at 500 nm and zenith,
in arcsec. Defaults to 0.7.
eps_max_arcsec_500 (float, optional, default1.2) – Worst (maximum) seeing FWHM at 500 nm and zenith,
in arcsec. Defaults to 1.2.
zmin_deg (float, optional, default45.0) – Minimum (best) zenith angle during observations, in degrees.
Defaults to 45.0.
zmax_deg (float, optional, default45.0) – Maximum (worst) zenith angle during observations, in degrees.
Defaults to 45.0.
n_points (int, optional, default2000) – Number of wavelength points used to sample the narrow window
around lambda_nm. Must be >= 2. Defaults to 2000.
Returns:
float – Total one-sigma uncertainty on q_log10 in dex, equal to the
quadrature sum of the input statistical error q_err and the symmetric
slit-loss systematic sigma_sys:
Raises:
ValueError – If n_points is smaller than 2 or aperture['type']
is not 'circular' or 'rectangular'.
The units_row expect strings that can be parsed by astropy.units.Unit. If a unit string cannot be parsed, a warning is issued and the column is left unitless. If the units row contains empty strings or placeholders like "-" or "None", those columns are also left unitless.
Parameters:
file_path (os.PathLike or str) – Path to the table file.
header_row (int, optional, default0) – Zero-based row index containing the column names.
units_row (int, optional, default1) – Zero-based row index containing the units row, or None to skip unit parsing.
data_start (int, optional, default2) – Zero-based row index where table data begin.
delimiter (str, optional, default",") – Delimiter used in the CSV file.
night (str) – Night substring to match in the filename.
fibre (str) – Fibre substring to match in the filename. Technically the function checks if both night and fibre are substrings of the filename, so they can be any distinctive part of the filename as long as they uniquely identify the file. If multiple files match, the first one when sorted by name is returned.
suffix (str, optional, default".csv") – Filename suffix to accept. Defaults to ".csv".
Returns:
pathlib.Path or None – The first matching path, or None if no file matches.
Load a stacked spectrum for a given night and fibre.
Note
The units_row expect strings that can be parsed by astropy.units.Unit. If a unit string cannot be parsed, a warning is issued and the column is left unitless. If the units row contains empty strings or placeholders like “-” or “None”, those columns are also left unitless.
Technically the function checks if both night and fibre are substrings of the filename, so they can be any distinctive part of the filename as long as they uniquely identify the file. If multiple files match, the first one when sorted by name is returned.
Parameters:
dir_path (os.PathLike or str) – Directory containing the spectrum files.
night (str) – Night substring used to locate the file.
fibre (str) – Fibre substring used to locate the file.
header_row (int, optional, default0) – Zero-based row index containing the column names.
units_row (int, optional, default1) – Zero-based row index containing the units row.
data_start (int, optional, default2) – Zero-based row index where table data begin.
Read a csv file into a nested dictionary where the key of the outer dictionary is determined by key_column and the inner dictionary contains the row values with the column names as key.
Load the packaged Hall & Anderson [3] UV solar irradiance file.
The on-disk file has wavelength in Angstrom and irradiance in
\(\mathrm{photons\,s^{-1}\,cm^{-2}\,\AA^{-1}}\). The output is converted to the same units
as open_kurucz_irradiance() and truncated at wave_max_AA so the two
spectra concatenate without overlap. See Hall & Anderson.
Parameters:
wave_max_AA (float, optional, default2990.0) – Upper wavelength cutoff in Angstrom (inclusive). Default
2990.0 matches the Kurucz file’s lower bound.
Returns:
pandas.DataFrame – A DataFrame with columns WAVE in units of \(\AA\) and FLUX
in units of \(\mathrm{erg\,s^{-1}\,cm^{-2}\,\AA^{-1}}\).
Raises:
FileNotFoundError – If the packaged Hall & Anderson file cannot be found.
Load the packaged Meftah et al. (2023) solar irradiance file.
We used the disk integrated MPS-ATLAS-Kurucz spectrum which has units of
\(\mathrm{nm}\) and \(\mathrm{W.m^(-2).nm^(-1)}\), but it is converted to the same units
as open_kurucz_irradiance(). See Meftah et al. (2023).
Returns:
pandas.DataFrame – A DataFrame with columns WAVE in units of \(\AA\) and FLUX in units of \(\mathrm{erg\,s^{-1}\,cm^{-2}\,\AA^{-1}}\).
Raises:
FileNotFoundError – If the packaged Meftah et al. (2023) file cannot be found.
Bromley et. al. (2024) [5]. file, stored as a compressed .npz archive with two
float32 arrays: wavelength (nm) and flux
(\(\mathrm{W\,m^{-2}\,nm^{-1}}\)). The output is converted to the same
units as open_kurucz_irradiance().We used the 0-14000_vac.tar.gz file.
Returns:
pandas.DataFrame – A DataFrame with columns WAVE in units of \(\AA\) and FLUX
in units of \(\mathrm{erg\,s^{-1}\,cm^{-2}\,\AA^{-1}}\).
Parses CN molecular line lists distributed in the fixed-width “machine-readable
table” format used by ApJS, as produced by Brooke et al. (2014) [6] and
Sneden et al. (2014) [7]. Three isotopologues are supported, each available
from the journal’s online supplementary materials:
12C14N
(Brooke et al. 2014) — \(^{12}\mathrm{C}^{14}\mathrm{N}\)
13C14N
(Sneden et al. 2014) — \(^{13}\mathrm{C}^{14}\mathrm{N}\)
12C15N
(Sneden et al. 2014) — \(^{12}\mathrm{C}^{15}\mathrm{N}\)
Parameters:
path_or_text (str or os.PathLike) – Path to the line-list file, or the file contents as a string.
Returns:
pandas.DataFrame – Parsed line list. Each row corresponds to one rovibronic transition.
The columns reproduce the fields of the source machine-readable tables,
plus two derived wavelength columns appended at the end:
Electronic state and vibrational quantum numbers
eS' (str) – Upper electronic state label (A, B, or X).
eS'' (str) – Lower electronic state label (A, B, or X).
v' (int) – Upper vibrational quantum number \(v'\).
v'' (int) – Lower vibrational quantum number \(v''\).
Rotational quantum numbers and fine-structure / parity labels
J'' (float) – Lower total angular momentum \(J''\).
F' (int) – Upper-state spin/parity component: in \(A^{2}\Pi\), 1 for \(\Omega = 1/2\), 2 for \(\Omega = 3/2\); in \(B^{2}\Sigma^{+}\) and \(X^{2}\Sigma^{+}\), 1 for \(e\), 2 for \(f\) parity.
F'' (int) – Lower-state spin/parity component, same encoding as F'.
p' (str) – Upper-state parity / e-f label (e or f).
p'' (str) – Lower-state parity / e-f label (e or f).
N' (float) – Upper \(N\) quantum number as defined in Brooke et al. (2014) [6]. Stored as text in the source file (allowing blank entries) and coerced to numeric; NaN where blank.