Source code for specter.psf.monospot

"""
specter.psf.monospot
====================

MonoSpotPSF - ...
"""

from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np
from astropy.io import fits
from specter.psf import PSF
from specter.util import LinearInterp2D, rebin_image, sincshift

[docs]class MonoSpotPSF(PSF): def __init__(self, filename, spot=None, scale=1.0): """ Initialize MonoSpotPSF from input file with optional override of which spot[y,x] to use. If overriding spot, scale gives ratio of spot pixel-size to CCD pixel-size. Must be >1 and evenly divisible by spot dimensions. See specter.psf.PSF for futher details """ #- Use PSF class to Load Generic PSF values (x, y, wavelength, ...) PSF.__init__(self, filename) if spot is None: self._spot = fits.getdata(filename, 'SPOT') self._scale = fits.getheader(filename, 'SPOT')['SCALE'] else: self._spot = spot.copy() self._scale = scale
[docs] def _xypix(self, ispec, wavelength, ispec_cache=None, iwave_cache=None): """ Return xslice, yslice, pix for PSF at spectrum ispec, wavelength """ assert 0 <= ispec < self.nspec xc, yc = self.xy(ispec, wavelength) scale = self._scale #- shorthand #- Calculate offset into CCD pixel xoffset = int(xc * scale) % scale yoffset = int(yc * scale) % scale #- Place high res spot into grid aligned with CCD pixels ny, nx = self._spot.shape A = np.zeros(shape=(ny+scale, nx+scale)) A[yoffset:yoffset+ny, xoffset:xoffset+nx] = self._spot ccdpix = rebin_image(A, scale) #- Fractional high-res pixel offset #- This can be slow; is it really necessary? dxx = ((xc * scale) % scale - xoffset) / scale dyy = ((yc * scale) % scale - yoffset) / scale ccdpix = sincshift(ccdpix, dxx, dyy) #- sinc shift can cause negative ringing, so clip and re-normalize ccdpix = ccdpix.clip(0) ccdpix /= np.sum(ccdpix) #- Find where the [0,0] pixel goes on the CCD xccd = int(xc - ccdpix.shape[1]//2 + 1) yccd = int(yc - ccdpix.shape[0]//2 + 1) xx = slice(xccd, xccd+ccdpix.shape[1]) yy = slice(yccd, yccd+ccdpix.shape[0]) return xx, yy, ccdpix
#- Incomplete code for creating without a file # def __init__(self, x, y, w, spot, scale=1): # """ # Create new MonoSpotPSF # # Inputs: # x[nspec, *] : 2D array of x-centroids on CCD # y[nspec, *] : 2D array of y-centroids on CCD # w[nspec, *] : 2D array of wavelengths on CCD # # spot[ny,nx] : 2D spot image to use everywhere on CCD # scale : ratio of spot pixel scale to CCD pixel scale. # Must be evenly divisible by ny,nx. # # Notes: # The second dimension of x,y,w is arbitrary, but the resolution # should be fine enough that liner interpolation is valid. # e.g. numpy.interp(yt, y[i], w[i]) should give the wavelength of # spectrum i at CCD row = yt. # # If spot.shape == (120,120) and scale=10, then 10 pixels of spot # correspond to 1 CCD pixel and the spot covers an area of (12x12) # CCD pixels. # """ # # assert x.shape == y.shape == w.shape # assert spot.shape[0] % scale == 0 # assert spot.shape[1] % scale == 0 # # self._nspec = x.shape[0] # self._x = x.copy() # self._y = y.copy() # self._w = w.copy() # self._spot = spot.copy() # self._scale = scale