def __init__(self, wave, calib, ivar, mask, meancalib=None): """Lightweight wrapper object for flux calibration vectors Args: wave : 1D[nwave] input wavelength (Angstroms) calib: 2D[nspec, nwave] calibration vectors for each spectrum ivar : 2D[nspec, nwave] inverse variance of calib mask : 2D[nspec, nwave] mask of calib (0=good) meancalib : 1D[nwave] mean convolved calibration (optional) All arguments become attributes, plus nspec,nwave = calib.shape The calib vector should be such that [1e-17 erg/s/cm^2/A] = [photons/A] / calib """ assert wave.ndim == 1 assert calib.ndim == 2 assert calib.shape == ivar.shape assert calib.shape == mask.shape assert np.all(ivar >= 0) self.nspec, self.nwave = calib.shape self.wave = wave self.calib = calib self.ivar = ivar self.mask = util.mask32(mask) self.meancalib = meancalib
def __init__(self, wave, flux, ivar, mask, header=None, nrej=0, stat_ivar=None): """Create SkyModel object Args: wave : 1D[nwave] wavelength in Angstroms flux : 2D[nspec, nwave] sky model to subtract ivar : 2D[nspec, nwave] inverse variance of the sky model mask : 2D[nspec, nwave] 0=ok or >0 if problems; 32-bit header : (optional) header from FITS file HDU0 nrej : (optional) Number of rejected pixels in fit All input arguments become attributes """ assert wave.ndim == 1 assert flux.ndim == 2 assert ivar.shape == flux.shape assert mask.shape == flux.shape self.nspec, self.nwave = flux.shape self.wave = wave self.flux = flux self.ivar = ivar self.mask = util.mask32(mask) self.header = header self.nrej = nrej self.stat_ivar = stat_ivar
def __init__(self, wave, calib, ivar, mask, meancalib=None): """Lightweight wrapper object for flux calibration vectors Args: wave : 1D[nwave] input wavelength (Angstroms) calib: 2D[nspec, nwave] calibration vectors for each spectrum ivar : 2D[nspec, nwave] inverse variance of calib mask : 2D[nspec, nwave] mask of calib (0=good) meancalib : 1D[nwave] mean convolved calibration (optional) All arguments become attributes, plus nspec,nwave = calib.shape The calib vector should be such that [1e-17 erg/s/cm^2/A] = [photons/A] / calib """ assert wave.ndim == 1 assert calib.ndim == 2 assert calib.shape == ivar.shape assert calib.shape == mask.shape assert np.all(ivar >= 0) self.nspec, self.nwave = calib.shape self.wave = wave self.calib = calib self.ivar = ivar self.mask = util.mask32(mask) self.meancalib = meancalib self.meta = dict(units='photons/(erg/s/cm^2)')
def test_mask32(self): for dtype in ( int, 'int64', 'uint64', 'i8', 'u8', 'int32', 'uint32', 'i4', 'u4', 'int16', 'uint16', 'i2', 'u2', 'int8', 'uint8', 'i1', 'u1', ): x = np.ones(10, dtype=np.dtype(dtype)) m32 = util.mask32(x) self.assertTrue(np.all(m32 == 1)) x = util.mask32(np.array([-1, 0, 1], dtype='i4')) self.assertEqual(x[0], 2**32 - 1) self.assertEqual(x[1], 0) self.assertEqual(x[2], 1) with self.assertRaises(ValueError): util.mask32(np.arange(2**35, 2**35 + 5)) with self.assertRaises(ValueError): util.mask32(np.arange(-2**35, -2**35 + 5))
def __init__(self, pix, ivar, mask=None, readnoise=0.0, camera='unknown', meta=None): """ Create Image object Args: pix : 2D numpy.ndarray of image pixels Optional: ivar : inverse variance of pix, same shape as pix mask : 0 is good, non-0 is bad; default is (ivar==0) readnoise : CCD readout noise in electrons/pixel (float) camera : e.g. 'b0', 'r1', 'z9' meta : dict-like metadata key/values, e.g. from FITS header """ if pix.ndim != 2: raise ValueError('pix must be 2D, not {}D'.format(pix.ndim)) if pix.shape != ivar.shape: raise ValueError('pix.shape{} != ivar.shape{}'.format( pix.shape, ivar.shape)) if (mask is not None) and (pix.shape != mask.shape): raise ValueError('pix.shape{} != mask.shape{}'.format( pix.shape, mask.shape)) self.pix = pix self.ivar = ivar self.meta = meta if mask is not None: self.mask = util.mask32(mask) else: self.mask = np.zeros(self.ivar.shape, dtype=np.uint32) self.mask[self.ivar == 0] |= ccdmask.BAD #- Optional parameters self.readnoise = readnoise self.camera = camera
def test_mask32(self): for dtype in ( int, 'int64', 'uint64', 'i8', 'u8', 'int32', 'uint32', 'i4', 'u4', 'int16', 'uint16', 'i2', 'u2', 'int8', 'uint8', 'i1', 'u1', ): x = np.ones(10, dtype=np.dtype(dtype)) m32 = util.mask32(x) self.assertTrue(np.all(m32 == 1)) x = util.mask32( np.array([-1,0,1], dtype='i4') ) self.assertEqual(x[0], 2**32-1) self.assertEqual(x[1], 0) self.assertEqual(x[2], 1) with self.assertRaises(ValueError): util.mask32(np.arange(2**35, 2**35+5)) with self.assertRaises(ValueError): util.mask32(np.arange(-2**35, -2**35+5))
def __init__(self, wave, flux, ivar, mask=None, resolution_data=None, fibers=None, spectrograph=None, meta=None, fibermap=None, chi2pix=None, scores=None, scores_comments=None, wsigma=None, ndiag=21, suppress_res_warning=False): """ Lightweight wrapper for multiple spectra on a common wavelength grid x.wave, x.flux, x.ivar, x.mask, x.resolution_data, x.header, sp.R Args: wave: 1D[nwave] wavelength in Angstroms flux: 2D[nspec, nwave] flux ivar: 2D[nspec, nwave] inverse variance of flux Optional: mask: 2D[nspec, nwave] integer bitmask of flux. 0=good. resolution_data: 3D[nspec, ndiag, nwave] diagonals of resolution matrix data fibers: ndarray of which fibers these spectra are spectrograph: integer, which spectrograph [0-9] meta: dict-like object (e.g. FITS header) fibermap: fibermap table chi2pix: 2D[nspec, nwave] chi2 of 2D model to pixel-level data for pixels that contributed to each flux bin scores: dictionnary of 1D arrays of size nspec scores_comments: dictionnary of string (explaining the scores) suppress_res_warning: bool to suppress Warning message when the Resolution image is not read Parameters below allow on-the-fly resolution calculation wsigma: 2D[nspec,nwave] sigma widths for each wavelength bin for all fibers Notes: spectrograph input is used only if fibers is None. In this case, it assumes nspec_per_spectrograph = flux.shape[0] and calculates the fibers array for this spectrograph, i.e. fibers = spectrograph * flux.shape[0] + np.arange(flux.shape[0]) Attributes: All input args become object attributes. nspec : number of spectra, flux.shape[0] nwave : number of wavelengths, flux.shape[1] specmin : minimum fiber number R: array of sparse Resolution matrix objects converted from resolution_data fibermap: fibermap table if provided """ assert wave.ndim == 1 assert flux.ndim == 2 assert wave.shape[0] == flux.shape[1] assert ivar.shape == flux.shape assert (mask is None) or mask.shape == flux.shape assert (mask is None) or mask.dtype in \ (int, np.int64, np.int32, np.uint64, np.uint32), "Bad mask type "+str(mask.dtype) self.wave = wave self.flux = flux self.ivar = ivar self.meta = meta self.fibermap = fibermap self.nspec, self.nwave = self.flux.shape self.chi2pix = chi2pix self.scores = scores self.scores_comments = scores_comments self.ndiag = ndiag fibers_per_spectrograph = 500 #- hardcode; could get from desimodel if mask is None: self.mask = np.zeros(flux.shape, dtype=np.uint32) else: self.mask = util.mask32(mask) if resolution_data is not None: if resolution_data.ndim != 3 or \ resolution_data.shape[0] != self.nspec or \ resolution_data.shape[2] != self.nwave: raise ValueError( "Wrong dimensions for resolution_data[nspec, ndiag, nwave]" ) #- Maybe setup non-None identity matrix resolution matrix instead? self.wsigma = wsigma self.resolution_data = resolution_data if resolution_data is not None: self.wsigma = None #ignore width coefficients if resolution data is given explicitly self.ndiag = None self.R = np.array([Resolution(r) for r in resolution_data]) elif wsigma is not None: from desispec.quicklook.qlresolution import QuickResolution assert ndiag is not None r = [] for sigma in wsigma: r.append(QuickResolution(sigma=sigma, ndiag=self.ndiag)) self.R = np.array(r) else: #SK I believe this should be error, but looking at the #tests frame objects are allowed to not to have resolution data # thus I changed value error to a simple warning message. if not suppress_res_warning: log = get_logger() log.warning("Frame object is constructed without resolution data or respective "\ "sigma widths. Resolution will not be available") # raise ValueError("Need either resolution_data or coefficients to generate it") self.spectrograph = spectrograph # Deal with Fibers (these must be set!) if fibers is not None: fibers = np.asarray(fibers) if len(fibers) != self.nspec: raise ValueError("len(fibers) != nspec ({} != {})".format( len(fibers), self.nspec)) if fibermap is not None and np.any(fibers != fibermap['FIBER']): raise ValueError("fibermap doesn't match fibers") if (spectrograph is not None): minfiber = spectrograph * fibers_per_spectrograph maxfiber = (spectrograph + 1) * fibers_per_spectrograph if np.any(fibers < minfiber) or np.any(maxfiber <= fibers): raise ValueError('fibers inconsistent with spectrograph') self.fibers = fibers else: if fibermap is not None: self.fibers = fibermap['FIBER'] elif spectrograph is not None: self.fibers = spectrograph * fibers_per_spectrograph + np.arange( self.nspec, dtype=int) elif (self.meta is not None) and ('FIBERMIN' in self.meta): self.fibers = self.meta['FIBERMIN'] + np.arange(self.nspec, dtype=int) else: raise ValueError("Must set fibers by one of the methods!") if self.meta is not None: self.meta['FIBERMIN'] = np.min(self.fibers)
def __init__(self, wave, flux, ivar, mask=None, resolution_data=None, fibers=None, spectrograph=None, meta=None, fibermap=None, chi2pix=None): """ Lightweight wrapper for multiple spectra on a common wavelength grid x.wave, x.flux, x.ivar, x.mask, x.resolution_data, x.header, sp.R Args: wave: 1D[nwave] wavelength in Angstroms flux: 2D[nspec, nwave] flux ivar: 2D[nspec, nwave] inverse variance of flux Optional: mask: 2D[nspec, nwave] integer bitmask of flux. 0=good. resolution_data: 3D[nspec, ndiag, nwave] diagonals of resolution matrix data fibers: ndarray of which fibers these spectra are spectrograph: integer, which spectrograph [0-9] meta: dict-like object (e.g. FITS header) fibermap: fibermap table chi2pix: 2D[nspec, nwave] chi2 of 2D model to pixel-level data for pixels that contributed to each flux bin Notes: spectrograph input is used only if fibers is None. In this case, it assumes nspec_per_spectrograph = flux.shape[0] and calculates the fibers array for this spectrograph, i.e. fibers = spectrograph * flux.shape[0] + np.arange(flux.shape[0]) Attributes: All input args become object attributes. nspec : number of spectra, flux.shape[0] nwave : number of wavelengths, flux.shape[1] specmin : minimum fiber number R: array of sparse Resolution matrix objects converted from resolution_data fibermap: fibermap table if provided """ assert wave.ndim == 1 assert flux.ndim == 2 assert wave.shape[0] == flux.shape[1] assert ivar.shape == flux.shape assert (mask is None) or mask.shape == flux.shape assert (mask is None) or mask.dtype in \ (int, np.int64, np.int32, np.uint64, np.uint32), "Bad mask type "+str(mask.dtype) self.wave = wave self.flux = flux self.ivar = ivar self.meta = meta self.fibermap = fibermap self.nspec, self.nwave = self.flux.shape self.chi2pix = chi2pix fibers_per_spectrograph = 500 #- hardcode; could get from desimodel if mask is None: self.mask = np.zeros(flux.shape, dtype=np.uint32) else: self.mask = util.mask32(mask) if resolution_data is not None: if resolution_data.ndim != 3 or \ resolution_data.shape[0] != self.nspec or \ resolution_data.shape[2] != self.nwave: raise ValueError( "Wrong dimensions for resolution_data[nspec, ndiag, nwave]" ) #- Maybe setup non-None identity matrix resolution matrix instead? self.resolution_data = resolution_data if resolution_data is not None: self.R = np.array([Resolution(r) for r in resolution_data]) self.spectrograph = spectrograph # Deal with Fibers (these must be set!) if fibers is not None: fibers = np.asarray(fibers) if len(fibers) != self.nspec: raise ValueError("len(fibers) != nspec ({} != {})".format( len(fibers), self.nspec)) if fibermap is not None and np.any(fibers != fibermap['FIBER']): raise ValueError("fibermap doesn't match fibers") if (spectrograph is not None): minfiber = spectrograph * fibers_per_spectrograph maxfiber = (spectrograph + 1) * fibers_per_spectrograph if np.any(fibers < minfiber) or np.any(maxfiber <= fibers): raise ValueError('fibers inconsistent with spectrograph') self.fibers = fibers else: if fibermap is not None: self.fibers = fibermap['FIBER'] elif spectrograph is not None: self.fibers = spectrograph * fibers_per_spectrograph + np.arange( self.nspec, dtype=int) elif (self.meta is not None) and ('FIBERMIN' in self.meta): self.fibers = self.meta['FIBERMIN'] + np.arange(self.nspec, dtype=int) else: raise ValueError("Must set fibers by one of the methods!") if self.meta is not None: self.meta['FIBERMIN'] = np.min(self.fibers)
def __init__(self, wave, fiberflat, ivar, mask=None, meanspec=None, chi2pdf=None, header=None, fibers=None, spectrograph=0): """ Creates a lightweight data wrapper for fiber flats Args: wave: 1D[nwave] wavelength in Angstroms fiberflat: 2D[nspec, nwave] ivar: 2D[nspec, nwave] inverse variance of fiberflat Optional inputs: mask: 2D[nspec, nwave] mask where 0=good; default ivar==0; 32-bit meanspec: (optional) 1D[nwave] mean deconvolved average flat lamp spectrum chi2pdf: (optional) Normalized chi^2 for fit to mean spectrum header: (optional) FITS header from HDU0 fibers: (optional) fiber indices spectrograph: (optional) spectrograph number [0-9] """ if wave.ndim != 1: raise ValueError("wave should be 1D") if fiberflat.ndim != 2: raise ValueError("fiberflat should be 2D[nspec, nwave]") if ivar.ndim != 2: raise ValueError("ivar should be 2D") if fiberflat.shape != ivar.shape: raise ValueError("fiberflat and ivar must have the same shape") if mask is not None and mask.ndim != 2: raise ValueError("mask should be 2D") if meanspec is not None and meanspec.ndim != 1: raise ValueError("meanspec should be 1D") if mask is not None and fiberflat.shape != mask.shape: raise ValueError("fiberflat and mask must have the same shape") if meanspec is not None and wave.shape != meanspec.shape: raise ValueError("wrong size/shape for meanspec {}".format( meanspec.shape)) if wave.shape[0] != fiberflat.shape[1]: raise ValueError( "nwave mismatch between wave.shape[0] and flux.shape[1]") if mask is None: mask = (ivar == 0) if meanspec is None: meanspec = np.ones_like(wave) self.wave = wave self.fiberflat = fiberflat self.ivar = ivar self.mask = util.mask32(mask) self.meanspec = meanspec self.nspec, self.nwave = self.fiberflat.shape self.header = header if chi2pdf is not None: self.chi2pdf = chi2pdf else: try: self.chi2pdf = header['chi2pdf'] except (KeyError, TypeError): self.chi2pdf = None self.spectrograph = spectrograph if fibers is None: self.fibers = self.spectrograph + np.arange(self.nspec, dtype=int) else: if len(fibers) != self.nspec: raise ValueError("len(fibers) != nspec ({} != {})".format( len(fibers), self.nspec)) self.fibers = fibers
def __init__(self, wave, fiberflat, ivar, mask=None, meanspec=None, chi2pdf=None, header=None, fibers=None, spectrograph=0): """ Creates a lightweight data wrapper for fiber flats Args: wave: 1D[nwave] wavelength in Angstroms fiberflat: 2D[nspec, nwave] ivar: 2D[nspec, nwave] inverse variance of fiberflat Optional inputs: mask: 2D[nspec, nwave] mask where 0=good; default ivar==0; 32-bit meanspec: (optional) 1D[nwave] mean deconvolved average flat lamp spectrum chi2pdf: (optional) Normalized chi^2 for fit to mean spectrum header: (optional) FITS header from HDU0 fibers: (optional) fiber indices spectrograph: (optional) spectrograph number [0-9] """ if wave.ndim != 1: raise ValueError("wave should be 1D") if fiberflat.ndim != 2: raise ValueError("fiberflat should be 2D[nspec, nwave]") if ivar.ndim != 2: raise ValueError("ivar should be 2D") if fiberflat.shape != ivar.shape: raise ValueError("fiberflat and ivar must have the same shape") if mask is not None and mask.ndim != 2: raise ValueError("mask should be 2D") if meanspec is not None and meanspec.ndim != 1: raise ValueError("meanspec should be 1D") if mask is not None and fiberflat.shape != mask.shape: raise ValueError("fiberflat and mask must have the same shape") if meanspec is not None and wave.shape != meanspec.shape: raise ValueError("wrong size/shape for meanspec {}".format(meanspec.shape)) if wave.shape[0] != fiberflat.shape[1]: raise ValueError("nwave mismatch between wave.shape[0] and flux.shape[1]") if mask is None: mask = (ivar == 0) if meanspec is None: meanspec = np.ones_like(wave) self.wave = wave self.fiberflat = fiberflat self.ivar = ivar self.mask = util.mask32(mask) self.meanspec = meanspec self.nspec, self.nwave = self.fiberflat.shape self.header = header if chi2pdf is not None: self.chi2pdf = chi2pdf else: try: self.chi2pdf = header['chi2pdf'] except (KeyError, TypeError): self.chi2pdf = None self.spectrograph = spectrograph if fibers is None: self.fibers = self.spectrograph + np.arange(self.nspec, dtype=int) else: if len(fibers) != self.nspec: raise ValueError("len(fibers) != nspec ({} != {})".format(len(fibers), self.nspec)) self.fibers = fibers
def __init__(self, wave, flux, ivar, mask=None, resolution_data=None, fibers=None, spectrograph=None, meta=None, fibermap=None): """ Lightweight wrapper for multiple spectra on a common wavelength grid x.wave, x.flux, x.ivar, x.mask, x.resolution_data, x.header, sp.R Args: wave: 1D[nwave] wavelength in Angstroms flux: 2D[nspec, nwave] flux ivar: 2D[nspec, nwave] inverse variance of flux Optional: mask: 2D[nspec, nwave] integer bitmask of flux. 0=good. resolution_data: 3D[nspec, ndiag, nwave] diagonals of resolution matrix data fibers: ndarray of which fibers these spectra are spectrograph: integer, which spectrograph [0-9] meta: dict-like object (e.g. FITS header) fibermap: fibermap table Notes: spectrograph input is used only if fibers is None. In this case, it assumes nspec_per_spectrograph = flux.shape[0] and calculates the fibers array for this spectrograph, i.e. fibers = spectrograph * flux.shape[0] + np.arange(flux.shape[0]) Attributes: All input args become object attributes. nspec : number of spectra, flux.shape[0] nwave : number of wavelengths, flux.shape[1] specmin : minimum fiber number R: array of sparse Resolution matrix objects converted from resolution_data fibermap: fibermap table if provided """ assert wave.ndim == 1 assert flux.ndim == 2 assert wave.shape[0] == flux.shape[1] assert ivar.shape == flux.shape assert (mask is None) or mask.shape == flux.shape assert (mask is None) or mask.dtype in \ (int, np.int64, np.int32, np.uint64, np.uint32), "Bad mask type "+str(mask.dtype) self.wave = wave self.flux = flux self.ivar = ivar self.meta = meta self.fibermap = fibermap self.nspec, self.nwave = self.flux.shape fibers_per_spectrograph = 500 #- hardcode; could get from desimodel if mask is None: self.mask = np.zeros(flux.shape, dtype=np.uint32) else: self.mask = util.mask32(mask) if resolution_data is not None: if resolution_data.ndim != 3 or \ resolution_data.shape[0] != self.nspec or \ resolution_data.shape[2] != self.nwave: raise ValueError("Wrong dimensions for resolution_data[nspec, ndiag, nwave]") #- Maybe setup non-None identity matrix resolution matrix instead? self.resolution_data = resolution_data if resolution_data is not None: self.R = np.array( [Resolution(r) for r in resolution_data] ) self.spectrograph = spectrograph # Deal with Fibers (these must be set!) if fibers is not None: fibers = np.asarray(fibers) if len(fibers) != self.nspec: raise ValueError("len(fibers) != nspec ({} != {})".format(len(fibers), self.nspec)) if fibermap is not None and np.any(fibers != fibermap['FIBER']): raise ValueError("fibermap doesn't match fibers") if (spectrograph is not None): minfiber = spectrograph*fibers_per_spectrograph maxfiber = (spectrograph+1)*fibers_per_spectrograph if np.any(fibers < minfiber) or np.any(maxfiber <= fibers): raise ValueError('fibers inconsistent with spectrograph') self.fibers = fibers else: if fibermap is not None: self.fibers = fibermap['FIBER'] elif spectrograph is not None: self.fibers = spectrograph*fibers_per_spectrograph + np.arange(self.nspec, dtype=int) elif (self.meta is not None) and ('FIBERMIN' in self.meta.keys()): self.fibers = self.meta['FIBERMIN'] + np.arange(self.nspec, dtype=int) else: raise ValueError("Must set fibers by one of the methods!") if self.meta is not None: self.meta['FIBERMIN'] = np.min(self.fibers)
def __init__(self, wave, flux, ivar, mask=None, resolution_data=None, fibers=None, spectrograph=None, meta=None, fibermap=None, chi2pix=None,scores=None,scores_comments=None, wsigma=None,ndiag=21, suppress_res_warning=False ): """ Lightweight wrapper for multiple spectra on a common wavelength grid x.wave, x.flux, x.ivar, x.mask, x.resolution_data, x.header, sp.R Args: wave: 1D[nwave] wavelength in Angstroms flux: 2D[nspec, nwave] flux ivar: 2D[nspec, nwave] inverse variance of flux Optional: mask: 2D[nspec, nwave] integer bitmask of flux. 0=good. resolution_data: 3D[nspec, ndiag, nwave] diagonals of resolution matrix data fibers: ndarray of which fibers these spectra are spectrograph: integer, which spectrograph [0-9] meta: dict-like object (e.g. FITS header) fibermap: fibermap table chi2pix: 2D[nspec, nwave] chi2 of 2D model to pixel-level data for pixels that contributed to each flux bin scores: dictionnary of 1D arrays of size nspec scores_comments: dictionnary of string (explaining the scores) suppress_res_warning: bool to suppress Warning message when the Resolution image is not read Parameters below allow on-the-fly resolution calculation wsigma: 2D[nspec,nwave] sigma widths for each wavelength bin for all fibers Notes: spectrograph input is used only if fibers is None. In this case, it assumes nspec_per_spectrograph = flux.shape[0] and calculates the fibers array for this spectrograph, i.e. fibers = spectrograph * flux.shape[0] + np.arange(flux.shape[0]) Attributes: All input args become object attributes. nspec : number of spectra, flux.shape[0] nwave : number of wavelengths, flux.shape[1] specmin : minimum fiber number R: array of sparse Resolution matrix objects converted from resolution_data fibermap: fibermap table if provided """ assert wave.ndim == 1 assert flux.ndim == 2 assert wave.shape[0] == flux.shape[1] assert ivar.shape == flux.shape assert (mask is None) or mask.shape == flux.shape assert (mask is None) or mask.dtype in \ (int, np.int64, np.int32, np.uint64, np.uint32), "Bad mask type "+str(mask.dtype) self.wave = wave self.flux = flux self.ivar = ivar self.meta = meta self.fibermap = fibermap self.nspec, self.nwave = self.flux.shape self.chi2pix = chi2pix self.scores = scores self.scores_comments = scores_comments self.ndiag=ndiag fibers_per_spectrograph = 500 #- hardcode; could get from desimodel if mask is None: self.mask = np.zeros(flux.shape, dtype=np.uint32) else: self.mask = util.mask32(mask) if resolution_data is not None: if resolution_data.ndim != 3 or \ resolution_data.shape[0] != self.nspec or \ resolution_data.shape[2] != self.nwave: raise ValueError("Wrong dimensions for resolution_data[nspec, ndiag, nwave]") #- Maybe setup non-None identity matrix resolution matrix instead? self.wsigma=wsigma self.resolution_data = resolution_data if resolution_data is not None: self.wsigma=None #ignore width coefficients if resolution data is given explicitly self.ndiag=None self.R = np.array( [Resolution(r) for r in resolution_data] ) elif wsigma is not None: from desispec.quicklook.qlresolution import QuickResolution assert ndiag is not None r=[] for sigma in wsigma: r.append(QuickResolution(sigma=sigma,ndiag=self.ndiag)) self.R=np.array(r) else: #SK I believe this should be error, but looking at the #tests frame objects are allowed to not to have resolution data # thus I changed value error to a simple warning message. if not suppress_res_warning: log = get_logger() log.warning("Frame object is constructed without resolution data or respective "\ "sigma widths. Resolution will not be available") # raise ValueError("Need either resolution_data or coefficients to generate it") self.spectrograph = spectrograph # Deal with Fibers (these must be set!) if fibers is not None: fibers = np.asarray(fibers) if len(fibers) != self.nspec: raise ValueError("len(fibers) != nspec ({} != {})".format(len(fibers), self.nspec)) if fibermap is not None and np.any(fibers != fibermap['FIBER']): raise ValueError("fibermap doesn't match fibers") if (spectrograph is not None): minfiber = spectrograph*fibers_per_spectrograph maxfiber = (spectrograph+1)*fibers_per_spectrograph if np.any(fibers < minfiber) or np.any(maxfiber <= fibers): raise ValueError('fibers inconsistent with spectrograph') self.fibers = fibers else: if fibermap is not None: self.fibers = fibermap['FIBER'] elif spectrograph is not None: self.fibers = spectrograph*fibers_per_spectrograph + np.arange(self.nspec, dtype=int) elif (self.meta is not None) and ('FIBERMIN' in self.meta): self.fibers = self.meta['FIBERMIN'] + np.arange(self.nspec, dtype=int) else: raise ValueError("Must set fibers by one of the methods!") if self.meta is not None: self.meta['FIBERMIN'] = np.min(self.fibers)
def __init__( self, wave, flux, ivar, mask=None, sigma=None, fibers=None, spectrograph=None, meta=None, fibermap=None, ): """ Lightweight wrapper for multiple spectra Args: wave: 2D[nspec, nwave] wavelength in Angstroms flux: 2D[nspec, nwave] flux ivar: 2D[nspec, nwave] inverse variance of flux Optional: mask: 2D[nspec, nwave] integer bitmask of flux. 0=good. sigma: 2D[nspec, nwave] LSF sigma in pixel units fibers: ndarray of which fibers these spectra are spectrograph: integer, which spectrograph [0-9] meta: dict-like object (e.g. FITS header) fibermap: fibermap table Attributes: All input args become object attributes. nspec : number of spectra, flux.shape[0] nwave : number of wavelengths, flux.shape[1] specmin : minimum fiber number R: array of sparse Resolution matrix objects converted from resolution_data fibermap: fibermap table if provided """ assert wave.ndim == 2 assert flux.ndim == 2 assert wave.shape == flux.shape assert ivar.shape == flux.shape assert (mask is None) or mask.shape == flux.shape assert (mask is None) or mask.dtype in \ (int, np.int64, np.int32, np.uint64, np.uint32), "Bad mask type "+str(mask.dtype) assert (sigma is None) or sigma.shape == flux.shape self.wave = wave self.flux = flux self.ivar = ivar self.meta = meta self.fibermap = fibermap if mask is None: self.mask = np.zeros(flux.shape, dtype=np.uint32) else: self.mask = util.mask32(mask) self.sigma = sigma self.nspec = self.flux.shape[0] self.spectrograph = spectrograph # Deal with Fibers (these must be set!) fibers_per_spectrograph = 500 #- hardcode; could get from desimodel if fibers is not None: fibers = np.asarray(fibers) if len(fibers) != self.flux.shape[0]: raise ValueError( "len(fibers) != flux.shape[0] ({} != {})".format( len(fibers), flux.shape[0])) if fibermap is not None and np.any(fibers != fibermap['FIBER']): raise ValueError("fibermap doesn't match fibers") if (spectrograph is not None): minfiber = spectrograph * fibers_per_spectrograph maxfiber = (spectrograph + 1) * fibers_per_spectrograph if np.any(fibers < minfiber) or np.any(maxfiber <= fibers): raise ValueError('fibers inconsistent with spectrograph') self.fibers = fibers else: if fibermap is not None: self.fibers = np.asarray(fibermap['FIBER']) elif spectrograph is not None: self.fibers = spectrograph * fibers_per_spectrograph + np.arange( self.nspec, dtype=int) elif (self.meta is not None) and ('FIBERMIN' in self.meta): self.fibers = self.meta['FIBERMIN'] + np.arange(self.nspec, dtype=int) else: self.fibers = np.arange(self.flux.shape[0]) if self.meta is not None: self.meta['FIBERMIN'] = np.min(self.fibers)
def __init__(self, wave, flux, ivar, mask=None, sigma=None, fibers=None, spectrograph=None, meta=None, fibermap=None, ): """ Lightweight wrapper for multiple spectra Args: wave: 2D[nspec, nwave] wavelength in Angstroms flux: 2D[nspec, nwave] flux ivar: 2D[nspec, nwave] inverse variance of flux Optional: mask: 2D[nspec, nwave] integer bitmask of flux. 0=good. sigma: 2D[nspec, nwave] LSF sigma in pixel units fibers: ndarray of which fibers these spectra are spectrograph: integer, which spectrograph [0-9] meta: dict-like object (e.g. FITS header) fibermap: fibermap table Attributes: All input args become object attributes. nspec : number of spectra, flux.shape[0] nwave : number of wavelengths, flux.shape[1] specmin : minimum fiber number R: array of sparse Resolution matrix objects converted from resolution_data fibermap: fibermap table if provided """ assert wave.ndim == 2 assert flux.ndim == 2 assert wave.shape == flux.shape assert ivar.shape == flux.shape assert (mask is None) or mask.shape == flux.shape assert (mask is None) or mask.dtype in \ (int, np.int64, np.int32, np.uint64, np.uint32), "Bad mask type "+str(mask.dtype) assert (sigma is None) or sigma.shape == flux.shape self.wave = wave self.flux = flux self.ivar = ivar self.meta = meta self.fibermap = fibermap if mask is None: self.mask = np.zeros(flux.shape, dtype=np.uint32) else: self.mask = util.mask32(mask) self.sigma = sigma self.nspec = self.flux.shape[0] self.spectrograph = spectrograph # Deal with Fibers (these must be set!) fibers_per_spectrograph = 500 #- hardcode; could get from desimodel if fibers is not None: fibers = np.asarray(fibers) if len(fibers) != self.flux.shape[0]: raise ValueError("len(fibers) != flux.shape[0] ({} != {})".format(len(fibers), flux.shape[0])) if fibermap is not None and np.any(fibers != fibermap['FIBER']): raise ValueError("fibermap doesn't match fibers") if (spectrograph is not None): minfiber = spectrograph*fibers_per_spectrograph maxfiber = (spectrograph+1)*fibers_per_spectrograph if np.any(fibers < minfiber) or np.any(maxfiber <= fibers): raise ValueError('fibers inconsistent with spectrograph') self.fibers = fibers else: if fibermap is not None: self.fibers = np.asarray(fibermap['FIBER']) elif spectrograph is not None: self.fibers = spectrograph*fibers_per_spectrograph + np.arange(self.nspec, dtype=int) elif (self.meta is not None) and ('FIBERMIN' in self.meta): self.fibers = self.meta['FIBERMIN'] + np.arange(self.nspec, dtype=int) else: self.fibers = np.arange(self.flux.shape[0]) if self.meta is not None: self.meta['FIBERMIN'] = np.min(self.fibers)