Source code for pypeit.scripts.binospec_ifu_extract

"""Interactive 1D fiber spectrum extractor for the MMT Binospec IFU.

Loads a single PypeIt ``spec1d`` file (covering both detector sides),
displays the IFU as a hexagonal flux map, and writes the user's combined
fiber selection as a :class:`~pypeit.onespec.OneSpec` FITS file.

.. include:: ../include/links.rst
"""
from __future__ import annotations

import argparse

from pypeit import PypeItError
from pypeit.scripts import scriptbase


[docs] class BinospecIFUExtract(scriptbase.ScriptBase): """Interactive fiber-spectrum extractor for the MMT Binospec IFU."""
[docs] @classmethod def get_parser(cls, width: int | None = None) -> argparse.ArgumentParser: parser = super().get_parser( description='Interactive 1D fiber spectrum extractor for the ' 'MMT Binospec IFU.', width=width, default_log_file=True) parser.add_argument('spec1d_file', type=str, help='PypeIt spec1d FITS file (covering both ' 'detector sides)') parser.add_argument('-o', '--output', type=str, default=None, help='Output OneSpec FITS filename ' '(default: spec1d_<base>.fits → ' 'extract1d_<base>.fits)') parser.add_argument('--boxcar', default=False, action='store_true', help='Use boxcar (BOX) extraction columns ' 'instead of optimal (OPT)') return parser
[docs] @classmethod def main(cls, args: argparse.Namespace) -> None: from pathlib import Path import numpy as np from pypeit import log from pypeit.core import datacube from pypeit.gui.binospec_ifu_extract import BinospecIFUExtractGUI from pypeit.specobjs import SpecObjs from pypeit.spectrographs.util import load_spectrograph cls.init_log(args) if not Path(args.spec1d_file).name.startswith('spec1d_'): raise PypeItError( f"Only spec1d files are supported; got " f"{Path(args.spec1d_file).name}") log.info(f"Loading {args.spec1d_file}") sobjs = SpecObjs.from_fitsfile(args.spec1d_file) if sobjs.nobj == 0: raise PypeItError(f"No objects in {args.spec1d_file}") # SpecObjs already carries the primary header it was read from, so # reuse it rather than opening the file a second time. raw_hdr = sobjs.header.copy() spectrograph = load_spectrograph(raw_hdr['PYP_SPEC']) if spectrograph.name != 'mmt_binospec_ifu': raise PypeItError( f"This script requires an mmt_binospec_ifu spec1d; " f"got PYP_SPEC={spectrograph.name!r}") targetx, targety = spectrograph.load_sky_layout() prefix = 'BOX' if args.boxcar else 'OPT' log.info(f" Using {prefix} extraction") fibers = datacube.load_fibers(sobjs, spectrograph, targetx, targety, prefix=prefix) log.info(f" Loaded {len(fibers)} science fibers") # Project each fiber's instrument-frame x,y to sky. x = np.array([f['x'] for f in fibers]) y = np.array([f['y'] for f in fibers]) ra, dec = datacube.project_to_sky(x, y, raw_hdr, spectrograph) for f, r, d in zip(fibers, ra, dec): f['ra'] = float(r) f['dec'] = float(d) # Output filename if args.output is not None: outfile = args.output else: base = Path(args.spec1d_file).stem if 'spec1d_' in base: base = base.replace('spec1d_', 'extract1d_') outfile = base + '.fits' gui = BinospecIFUExtractGUI(fibers, raw_hdr, spectrograph.name, outfile) gui.show()