"""Wavelength configuration model.
Maps to uvspec keywords: wavelength, spline, filter_function_file,
wavelength_grid_file, wavelength_index, slit_function_file, spline_file,
fluorescence, fluorescence_file, thermal_bands_file, thermal_bandwidth.
Reference: libRadtran src_py/spectral_options.py
"""
from __future__ import annotations
from pydantic import Field, model_validator
from pyradtran.models.base import UvspecOption
[docs]
class WavelengthConfig(UvspecOption):
"""Spectral range configuration.
Attributes:
wavelength_min: Shortest wavelength (nm or cm-1), or single wavelength
when wavelength_max is not set.
wavelength_max: Longest wavelength (nm or cm-1). Optional; when None,
wavelength_min is treated as a single wavelength value.
unit: Wavelength unit -- "nm" (default) or "cm-1" for wavenumbers.
spline: Spline smoothing arguments string (3 floats).
filter_function_file: Path to filter function file.
wavelength_grid_file: Path to wavelength grid file (alternative to wavelength_min).
wavelength_index: Tuple of (start_index, end_index) for wavelength subset.
slit_function_file: Path to slit function file.
spline_file: Path to spline file.
fluorescence: Enable fluorescence calculation.
fluorescence_file: Path to fluorescence data file.
thermal_bands_file: Path to thermal bands file.
thermal_bandwidth: Tuple of (width, unit) for thermal bandwidth.
"""
wavelength_min: float | None = Field(default=None, ge=0.0, le=1e6)
wavelength_max: float | None = Field(default=None, ge=0.0, le=1e6)
unit: str = Field(default="nm", pattern=r"^(nm|cm-1)$")
spline: str | None = None
filter_function_file: str | None = None
wavelength_grid_file: str | None = None
wavelength_index: tuple[int, int] | None = None
slit_function_file: str | None = None
spline_file: str | None = None
fluorescence: bool = False
fluorescence_file: str | None = None
thermal_bands_file: str | None = None
thermal_bandwidth: tuple[float, str] | None = None
[docs]
@model_validator(mode="after")
def validate_wavelength_set(self) -> WavelengthConfig:
if self.wavelength_min is None and self.wavelength_grid_file is None:
raise ValueError(
"At least one of wavelength_min or wavelength_grid_file must be set"
)
return self
[docs]
def to_uvspec_lines(self) -> list[str]:
lines: list[str] = []
if self.wavelength_grid_file is not None:
lines.append(f"wavelength_grid_file {self.wavelength_grid_file}")
if self.wavelength_min is not None:
if self.wavelength_max is not None:
# Range mode: min and max
if self.unit == "cm-1":
lines.append(f"wavelength {self.wavelength_min} {self.wavelength_max} cm-1")
else:
lines.append(f"wavelength {self.wavelength_min} {self.wavelength_max}")
else:
# Single wavelength mode
if self.unit == "cm-1":
lines.append(f"wavelength {self.wavelength_min} cm-1")
else:
lines.append(f"wavelength {self.wavelength_min}")
if self.wavelength_index is not None:
i0, i1 = self.wavelength_index
lines.append(f"wavelength_index {i0} {i1}")
if self.spline is not None:
lines.append(f"spline {self.spline}")
if self.spline_file is not None:
lines.append(f"spline_file {self.spline_file}")
if self.slit_function_file is not None:
lines.append(f"slit_function_file {self.slit_function_file}")
if self.filter_function_file is not None:
lines.append(f"filter_function_file {self.filter_function_file}")
if self.fluorescence:
lines.append("fluorescence")
if self.fluorescence_file is not None:
lines.append(f"fluorescence_file {self.fluorescence_file}")
if self.thermal_bands_file is not None:
lines.append(f"thermal_bands_file {self.thermal_bands_file}")
if self.thermal_bandwidth is not None:
width, unit = self.thermal_bandwidth
lines.append(f"thermal_bandwidth {width} {unit}")
return lines
[docs]
def to_uvspec_items(self) -> list[tuple[int, str]]:
phase = 3
return [(phase, line) for line in self.to_uvspec_lines()]