Source code for pyreduce.instruments.MCDONALD
"""
Handles instrument specific info for the HARPS spectrograph
Mostly reading data from the header
"""
import logging
import os.path
import re
from astropy.time import Time
from ..common import Instrument, getter
logger = logging.getLogger(__name__)
[docs]
class MCDONALD(Instrument):
def __init__(self):
super().__init__()
# The date is a combination of the two values
kw = f"{{{self.info['date']}}}T{{{self.info['universal_time']}}}"
self.filters["night"].keyword = kw
def _convert_time_deg(self, v):
v = [float(s) for s in v.split(":")]
v = v[0] + v[1] / 60 + v[2] / 3600
return v
[docs]
def add_header_info(self, header, channel, **kwargs):
"""read data from header and add it as REDUCE keyword back to the header"""
# "Normal" stuff is handled by the general version, specific changes to values happen here
# alternatively you can implement all of it here, whatever works
header = super().add_header_info(header, channel, **kwargs)
info = self.info # Use cached info dict
get = getter(header, info, channel)
header["e_orient"] = get("orientation", 0)
# As per IDL rotate if orient is 4 or larger and transpose is undefined
# the image is transposed
header["e_transpose"] = get("transpose", (header["e_orient"] % 8 >= 4))
trimsec = get("trimsec")
if trimsec is not None:
pattern = r"\[(\d*?):(\d*?),(\d*?):(\d*?)\]"
res = re.match(pattern, trimsec)
prescan_x = int(res[1]) + 1
overscan_x = int(res[2])
prescan_y = int(res[3])
overscan_y = int(res[4])
else:
prescan_x = 2
overscan_x = 2048
prescan_y = 2
overscan_y = 2047
header["e_xlo"] = prescan_x
header["e_xhi"] = overscan_x
header["e_ylo"] = prescan_y
header["e_yhi"] = overscan_y
amp = get("amplifier")
gain = info["gain"].format(amplifier=amp)
readnoise = info["readnoise"].format(amplifier=amp)
header["e_gain"] = get(gain, 1)
header["e_readn"] = get(readnoise, 0)
header["e_exptim"] = get("exposure_time", 0)
header["e_sky"] = get("sky", 0)
header["e_drk"] = get("dark", 0)
header["e_backg"] = header["e_gain"] * (header["e_drk"] + header["e_sky"])
header["e_imtype"] = get("observation_type")
header["e_ctg"] = get("observation_type")
obs_date = get("date")
ut = get("universal_time")
if obs_date is not None and ut is not None:
obs_date = f"{obs_date}T{ut}"
dark_time = get("dark_time")
ra = get("ra")
dec = get("dec")
if ra is not None:
ra = self._convert_time_deg(ra)
if dec is not None:
dec = self._convert_time_deg(dec)
if dark_time is not None:
tmid = dark_time / 2
else:
tmid = 0
if obs_date is not None:
jd = Time(obs_date).mjd + tmid + 0.5
else:
jd = 0
header["e_ra"] = ra
header["e_dec"] = dec
header["e_jd"] = jd
header["e_obslon"] = self._convert_time_deg(info["longitude"])
header["e_obslat"] = self._convert_time_deg(info["latitude"])
header["e_obsalt"] = info["altitude"]
return header
[docs]
def get_wavecal_filename(self, header, channel, **kwargs):
"""Get the filename of the wavelength calibration config file"""
cwd = os.path.dirname(__file__)
fname = os.path.join(cwd, "wavecal.npz")
return fname
[docs]
def get_mask_filename(self, channel, **kwargs):
cwd = os.path.dirname(__file__)
fname = os.path.join(cwd, "mask.fits.gz")
return fname