PyReduce supports many instruments out of the box. Custom instruments can be added by creating YAML configuration files.
- HARPS - High Accuracy Radial velocity Planet Searcher
- HARPS-N - HARPS-North at TNG
- HARPSPOL - HARPS Polarimeter (dual-beam mode)
- UVES - UV-Visual Echelle Spectrograph
- XSHOOTER - Wide-band spectrograph (UVB/VIS/NIR)
- CRIRES+ - Cryogenic IR Echelle Spectrograph
- JWST NIRISS - Near Infrared Imager and Slitless Spectrograph
- JWST MIRI - Mid-Infrared Instrument
- Keck NIRSPEC - Near-IR spectrograph
- Lick APF - Automated Planet Finder
- McDonald - McDonald Observatory spectrograph
- NEID - NN-EXPLORE Exoplanet Investigations with Doppler spectroscopy
- METIS - Mid-infrared ELT Imager and Spectrograph (LSS and IFU modes)
- MICADO - Multi-AO Imaging Camera for Deep Observations
- MOSAIC - Multi-Object Spectrograph for Astrophysics, Intergalactic-medium studies and Cosmology
- ANDES_UBV - ArmazoNes high Dispersion Echelle Spectrograph (U/B/V channels)
- ANDES_RIZ - ArmazoNes high Dispersion Echelle Spectrograph (R/IZ channels)
- ANDES_YJH - ArmazoNes high Dispersion Echelle Spectrograph (Y/J/H channels)
- NTE - New Technology Echelle spectrograph
Create a YAML file defining your instrument:
# myinstrument.yaml
instrument: MyInstrument
telescope: MyTelescope
channels: [default]
# Detector
naxis: [2048, 2048]
orientation: 0
extension: 0
gain: 1.0
readnoise: 5.0
# Header keywords
date: DATE-OBS
target: OBJECT
exposure_time: EXPTIME
# File classification
kw_bias: IMAGETYP
id_bias: bias
kw_flat: IMAGETYP
id_flat: flat
kw_spec: IMAGETYP
id_spec: objectLoad it directly:
from pyreduce.instruments import load_instrument
inst = load_instrument("/path/to/myinstrument.yaml")For instruments needing custom logic, create a Python class:
from pyreduce.instruments.common import Instrument
class MyInstrument(Instrument):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Custom initialization
def add_header_info(self, header):
# Compute derived header values
header["MJD_MID"] = header["MJD_OBS"] + header["EXPTIME"] / 86400 / 2
return header
def get_wavecal_filename(self, header, channel, **kwargs):
# Return path to wavelength calibration file
return f"wavecal_{channel}.npz"Place both files in pyreduce/instruments/{NAME}/ directory (YAML as config.yaml, Python as __init__.py).
| Field | Description |
|---|---|
instrument |
Instrument name |
telescope |
Telescope name |
channels |
List of instrument channels/modes |
naxis |
Detector dimensions [x, y] |
| Field | Description |
|---|---|
extension |
FITS extension (0 or name) |
orientation |
Rotation/flip code (0-7) |
gain |
Detector gain (value or header keyword) |
readnoise |
Read noise (value or header keyword) |
dark |
Dark current (value or header keyword) |
prescan_x |
Prescan region in x |
overscan_x |
Overscan region in x |
These map instrument-specific header keywords to internal names:
| Field | Description |
|---|---|
date |
Observation date |
target |
Target name |
exposure_time |
Exposure time |
ra, dec |
Coordinates |
jd |
Julian date |
instrument_mode |
Instrument mode |
| Field | Description |
|---|---|
kw_bias, id_bias |
Bias file keyword and pattern |
kw_flat, id_flat |
Flat file keyword and pattern |
kw_wave, id_wave |
Wavelength calibration keyword and pattern |
kw_spec, id_spec |
Science file keyword and pattern |
See pyreduce/instruments/models.py for the complete schema.
The orientation field controls how the raw image is rotated/flipped before processing.
Values 0-7 correspond to different transformations:
| Value | Transformation |
|---|---|
| 0 | No change |
| 1 | Rotate 90 CCW |
| 2 | Rotate 180 |
| 3 | Rotate 90 CW |
| 4 | Flip horizontal |
| 5 | Flip horizontal + rotate 90 CCW |
| 6 | Flip vertical |
| 7 | Flip horizontal + rotate 90 CW |
The goal is to orient the image so that:
- Dispersion direction is horizontal (wavelength increases left to right)
- Cross-dispersion is vertical (orders are stacked vertically)
Each instrument has its own settings file at pyreduce/instruments/{INSTRUMENT}/settings.json.
This inherits from and overrides pyreduce/instruments/defaults/settings.json.
Per-channel overrides can be placed in settings_{channel}.json (e.g., settings_r.json),
which inherit from the instrument's base settings.
See Configuration for details.
Some instruments have multiple fibers per spectral order (e.g., IFU bundles, calibration fibers alongside science fibers). PyReduce supports these via the fibers configuration in config.yaml:
- Fiber groups - Named collections of fibers (e.g., "science", "cal", "sky")
- Bundle patterns - Repeating groups of fibers (e.g., 7 fibers per IFU target)
- Per-order grouping - For echelle instruments with multi-fiber orders
The fibers.use section specifies which traces each reduction step should use:
fibers:
groups:
A: { range: [1, 36], merge: average }
cal: { range: [37, 40], merge: average }
use:
science: [A]
wavecal: [cal]
norm_flat: allSee Fiber Bundle Tracing for the full configuration reference.