Example #1
0
def read_image(filename):
    """
    Returns desispec.image.Image object from input file
    """
    log = get_logger()
    t0 = time.time()
    with fits.open(filename, uint=True, memmap=False) as fx:
        image = native_endian(fx['IMAGE'].data).astype(np.float64)
        ivar = native_endian(fx['IVAR'].data).astype(np.float64)
        mask = native_endian(fx['MASK'].data).astype(np.uint16)
        camera = fx['IMAGE'].header['CAMERA'].lower()
        meta = fx['IMAGE'].header

        if 'READNOISE' in fx:
            readnoise = native_endian(fx['READNOISE'].data).astype(np.float64)
        else:
            readnoise = fx['IMAGE'].header['RDNOISE']

    duration = time.time() - t0
    log.info(iotime.format('read', filename, duration))

    return Image(image,
                 ivar,
                 mask=mask,
                 readnoise=readnoise,
                 camera=camera,
                 meta=meta)
Example #2
0
def read_fiberflat(filename):
    """Read fiberflat from filename

    Args:
        filename (str): Name of fiberflat file, or (night, expid, camera) tuple

    Returns:
        FiberFlat object with attributes
            fiberflat, ivar, mask, meanspec, wave, header

    Notes:
        fiberflat, ivar, mask are 2D [nspec, nwave]
        meanspec and wave are 1D [nwave]
    """
    #- check if outfile is (night, expid, camera) tuple instead
    if isinstance(filename, (tuple, list)) and len(filename) == 3:
        night, expid, camera = filename
        filename = findfile('fiberflat', night, expid, camera)

    header    = fits.getheader(filename, 0)
    fiberflat = native_endian(fits.getdata(filename, 0))
    ivar      = native_endian(fits.getdata(filename, "IVAR").astype('f8'))
    mask      = native_endian(fits.getdata(filename, "MASK", uint=True))
    meanspec  = native_endian(fits.getdata(filename, "MEANSPEC").astype('f8'))
    wave      = native_endian(fits.getdata(filename, "WAVELENGTH").astype('f8'))

    return FiberFlat(wave, fiberflat, ivar, mask, meanspec, header=header)
Example #3
0
def read_fiberflat(filename):
    """Read fiberflat from filename

    Args:
        filename (str): Name of fiberflat file, or (night, expid, camera) tuple

    Returns:
        FiberFlat object with attributes
            fiberflat, ivar, mask, meanspec, wave, header

    Notes:
        fiberflat, ivar, mask are 2D [nspec, nwave]
        meanspec and wave are 1D [nwave]
    """
    #- check if outfile is (night, expid, camera) tuple instead
    if isinstance(filename, (tuple, list)) and len(filename) == 3:
        night, expid, camera = filename
        filename = findfile('fiberflat', night, expid, camera)

    header = fits.getheader(filename, 0)
    fiberflat = native_endian(fits.getdata(filename, 0)).astype('f8')
    ivar = native_endian(fits.getdata(filename, "IVAR").astype('f8'))
    mask = native_endian(fits.getdata(filename, "MASK", uint=True))
    meanspec = native_endian(fits.getdata(filename, "MEANSPEC").astype('f8'))
    wave = native_endian(fits.getdata(filename, "WAVELENGTH").astype('f8'))

    return FiberFlat(wave, fiberflat, ivar, mask, meanspec, header=header)
Example #4
0
def read_frame(filename, nspec=None):
    """Reads a frame fits file and returns its data.

    Args:
        filename: path to a file, or (night, expid, camera) tuple where
            night = string YEARMMDD
            expid = integer exposure ID
            camera = b0, r1, .. z9

    Returns:
        desispec.Frame object with attributes wave, flux, ivar, etc.
    """
    #- check if filename is (night, expid, camera) tuple instead
    if not isinstance(filename, (str, unicode)):
        night, expid, camera = filename
        filename = findfile('frame', night, expid, camera)

    if not os.path.isfile(filename):
        raise IOError("cannot open" + filename)

    fx = fits.open(filename, uint=True, memmap=False)
    hdr = fx[0].header
    flux = native_endian(fx['FLUX'].data.astype('f8'))
    ivar = native_endian(fx['IVAR'].data.astype('f8'))
    wave = native_endian(fx['WAVELENGTH'].data.astype('f8'))
    if 'MASK' in fx:
        mask = native_endian(fx['MASK'].data)
    else:
        mask = None  #- let the Frame object create the default mask

    resolution_data = native_endian(fx['RESOLUTION'].data.astype('f8'))

    if 'FIBERMAP' in fx:
        fibermap = fx['FIBERMAP'].data
    else:
        fibermap = None

    fx.close()

    if nspec is not None:
        flux = flux[0:nspec]
        ivar = ivar[0:nspec]
        resolution_data = resolution_data[0:nspec]

    # return flux,ivar,wave,resolution_data, hdr
    return Frame(wave,
                 flux,
                 ivar,
                 mask,
                 resolution_data,
                 meta=hdr,
                 fibermap=fibermap)
Example #5
0
def read_frame(filename, nspec=None):
    """Reads a frame fits file and returns its data.

    Args:
        filename: path to a file, or (night, expid, camera) tuple where
            night = string YEARMMDD
            expid = integer exposure ID
            camera = b0, r1, .. z9

    Returns:
        desispec.Frame object with attributes wave, flux, ivar, etc.
    """
    #- check if filename is (night, expid, camera) tuple instead
    if not isinstance(filename, (str, unicode)):
        night, expid, camera = filename
        filename = findfile('frame', night, expid, camera)

    if not os.path.isfile(filename) :
        raise IOError("cannot open"+filename)

    fx = fits.open(filename, uint=True, memmap=False)
    hdr = fx[0].header
    flux = native_endian(fx['FLUX'].data.astype('f8'))
    ivar = native_endian(fx['IVAR'].data.astype('f8'))
    wave = native_endian(fx['WAVELENGTH'].data.astype('f8'))
    if 'MASK' in fx:
        mask = native_endian(fx['MASK'].data)
    else:
        mask = None   #- let the Frame object create the default mask
        
    resolution_data = native_endian(fx['RESOLUTION'].data.astype('f8'))
    
    if 'FIBERMAP' in fx:
        fibermap = fx['FIBERMAP'].data
    else:
        fibermap = None
    
    fx.close()

    if nspec is not None:
        flux = flux[0:nspec]
        ivar = ivar[0:nspec]
        resolution_data = resolution_data[0:nspec]

    # return flux,ivar,wave,resolution_data, hdr
    return Frame(wave, flux, ivar, mask, resolution_data, meta=hdr, fibermap=fibermap)
Example #6
0
def read_image(filename):
    """
    Returns desispec.image.Image object from input file
    """
    fx = fits.open(filename, uint=True, memmap=False)
    image = native_endian(fx['IMAGE'].data).astype(np.float64)
    ivar = native_endian(fx['IVAR'].data).astype(np.float64)
    mask = native_endian(fx['MASK'].data).astype(np.uint16)
    camera = fx['IMAGE'].header['CAMERA'].lower()
    meta = fx['IMAGE'].header

    if 'READNOISE' in fx:
        readnoise = native_endian(fx['READNOISE'].data).astype(np.float64)
    else:
        readnoise = fx['IMAGE'].header['RDNOISE']

    return Image(image, ivar, mask=mask, readnoise=readnoise,
                 camera=camera, meta=meta)
Example #7
0
def read_zbest(filename):
    """Returns a desispec.zfind.ZfindBase object with contents from filename.
    """
    from desispec.io.util import native_endian
    fx = fits.open(filename, memmap=False)
    zbest = fx['ZBEST'].data
    if 'WAVELENGTH' in fx:
        wave = native_endian(fx['WAVELENGTH'].data.astype('f8'))
        flux = native_endian(fx['FLUX'].data.astype('f8'))
        ivar = native_endian(fx['IVAR'].data.astype('f8'))
        model = fx['MODEL'].data

        zf = ZfindBase(wave, flux, ivar, results=zbest)
        zf.model = model
    else:
        zf = ZfindBase(None, None, None, results=zbest)

    fx.close()
    return zf
Example #8
0
def read_zbest(filename):
    """Returns a desispec.zfind.ZfindBase object with contents from filename.
    """
    from desispec.io.util import native_endian
    fx = fits.open(filename, memmap=False)
    zbest = fx['ZBEST'].data
    if 'WAVELENGTH' in fx:
        wave = native_endian(fx['WAVELENGTH'].data.astype('f8'))
        flux = native_endian(fx['FLUX'].data.astype('f8'))
        ivar = native_endian(fx['IVAR'].data.astype('f8'))
        model = fx['MODEL'].data

        zf = ZfindBase(wave, flux, ivar, results=zbest)
        zf.model = model
    else:
        zf = ZfindBase(None, None, None, results=zbest)

    fx.close()
    return zf
Example #9
0
def read_sky(filename):
    """Read sky model and return SkyModel object with attributes
    wave, flux, ivar, mask, header.
    
    skymodel.wave is 1D common wavelength grid, the others are 2D[nspec, nwave]
    """
    #- check if filename is (night, expid, camera) tuple instead
    if not isinstance(filename, (str, unicode)):
        night, expid, camera = filename
        filename = findfile('sky', night, expid, camera)

    hdr = fits.getheader(filename, 0)
    wave = native_endian(fits.getdata(filename, "WAVELENGTH"))
    skyflux = native_endian(fits.getdata(filename, "SKY"))
    ivar = native_endian(fits.getdata(filename, "IVAR"))
    mask = native_endian(fits.getdata(filename, "MASK", uint=True))

    skymodel = SkyModel(wave, skyflux, ivar, mask, header=hdr)

    return skymodel
Example #10
0
def read_sky(filename) :
    """Read sky model and return SkyModel object with attributes
    wave, flux, ivar, mask, header.
    
    skymodel.wave is 1D common wavelength grid, the others are 2D[nspec, nwave]
    """
    #- check if filename is (night, expid, camera) tuple instead
    if not isinstance(filename, (str, unicode)):
        night, expid, camera = filename
        filename = findfile('sky', night, expid, camera)

    hdr = fits.getheader(filename, 0)
    wave = native_endian(fits.getdata(filename, "WAVELENGTH"))
    skyflux = native_endian(fits.getdata(filename, "SKY"))
    ivar = native_endian(fits.getdata(filename, "IVAR"))
    mask = native_endian(fits.getdata(filename, "MASK", uint=True))

    skymodel = SkyModel(wave, skyflux, ivar, mask, header=hdr)

    return skymodel
Example #11
0
def read_sky(filename) :
    """Read sky model and return SkyModel object with attributes
    wave, flux, ivar, mask, header.
    
    skymodel.wave is 1D common wavelength grid, the others are 2D[nspec, nwave]
    """
    #- check if filename is (night, expid, camera) tuple instead
    if not isinstance(filename, (str, unicode)):
        night, expid, camera = filename
        filename = findfile('sky', night, expid, camera)

    fx = fits.open(filename, memmap=False, uint=True)

    hdr = fx[0].header
    wave = native_endian(fx["WAVELENGTH"].data.astype('f8'))
    skyflux = native_endian(fx["SKY"].data.astype('f8'))
    ivar = native_endian(fx["IVAR"].data.astype('f8'))
    mask = native_endian(fx["MASK"].data)
    fx.close()

    skymodel = SkyModel(wave, skyflux, ivar, mask, header=hdr)

    return skymodel
Example #12
0
def read_cosmics(filename, expid=1, shape=None, jitter=True):
    """
    Reads a dark image with cosmics from the input filename.

    The input might have multiple dark images; use the `expid%n` image where
    `n` is the number of images in the input cosmics file.

    Args:
        filename : FITS filename with EXTNAME=IMAGE-*, IVAR-*, MASK-* HDUs
        expid : integer, use `expid % n` image where `n` is number of images

    Optional:
        shape : (ny, nx) tuple for output image shape
        jitter : If True (default), apply random flips and rolls so you
            don't get the exact same cosmics every time

    Returns:
        `desisim.image.Image` object with attributes pix, ivar, mask
    """
    fx = fits.open(filename)
    imagekeys = list()
    for i in range(len(fx)):
        if fx[i].name.startswith('IMAGE-'):
            imagekeys.append(fx[i].name.split('-', 1)[1])

    assert len(imagekeys) > 0, 'No IMAGE-* extensions found in '+filename
    i = expid % len(imagekeys)
    pix  = native_endian(fx['IMAGE-'+imagekeys[i]].data.astype(np.float64))
    ivar = native_endian(fx['IVAR-'+imagekeys[i]].data.astype(np.float64))
    mask = native_endian(fx['MASK-'+imagekeys[i]].data)
    meta = fx['IMAGE-'+imagekeys[i]].header
    meta['CRIMAGE'] = (imagekeys[i], 'input cosmic ray image')

    if shape is not None:
        if len(shape) != 2: raise ValueError('Invalid shape {}'.format(shape))
        newpix = np.empty(shape, dtype=np.float64)
        ny = min(shape[0], pix.shape[0])
        nx = min(shape[1], pix.shape[1])
        newpix[0:ny, 0:nx] = pix[0:ny, 0:nx]

        pix = _resize(pix, shape)
        ivar = _resize(ivar, shape)
        mask = _resize(mask, shape)

    if jitter:
        #- Randomly flip left-right and/or up-down
        if np.random.uniform(0, 1) > 0.5:
            pix = np.fliplr(pix)
            ivar = np.fliplr(ivar)
            mask = np.fliplr(mask)
            meta['CRFLIPLR'] = (True, 'Input cosmics image flipped Left/Right')
        else:
            meta['CRFLIPLR'] = (False, 'Input cosmics image NOT flipped Left/Right')

        if np.random.uniform(0, 1) > 0.5:
            pix = np.flipud(pix)
            ivar = np.flipud(ivar)
            mask = np.flipud(mask)
            meta['CRFLIPUD'] = (True, 'Input cosmics image flipped Up/Down')
        else:
            meta['CRFLIPUD'] = (True, 'Input cosmics image NOT flipped Up/Down')

        #- Randomly roll image a bit
        nx, ny = np.random.randint(-200, 200, size=2)
        pix = np.roll(np.roll(pix, ny, axis=0), nx, axis=1)
        ivar = np.roll(np.roll(ivar, ny, axis=0), nx, axis=1)
        mask = np.roll(np.roll(mask, ny, axis=0), nx, axis=1)
        meta['CRSHIFTX'] = (nx, 'Input cosmics image shift in x')
        meta['CRSHIFTY'] = (nx, 'Input cosmics image shift in y')
    else:
        meta['CRFLIPLR'] = (False, 'Input cosmics image NOT flipped Left/Right')
        meta['CRFLIPUD'] = (True, 'Input cosmics image NOT flipped Up/Down')
        meta['CRSHIFTX'] = (0, 'Input cosmics image shift in x')
        meta['CRSHIFTY'] = (0, 'Input cosmics image shift in y')

    #- RDNOISEn -> average RDNOISE
    if 'RDNOISE' not in meta:
        x = meta['RDNOISE0']+meta['RDNOISE1']+meta['RDNOISE2']+meta['RDNOISE3']
        meta['RDNOISE'] = x / 4.0

    return Image(pix, ivar, mask, meta=meta)
Example #13
0
def read_cosmics(filename, expid=1, shape=None, jitter=True):
    """
    Reads a dark image with cosmics from the input filename.

    The input might have multiple dark images; use the `expid%n` image where
    `n` is the number of images in the input cosmics file.

    Args:
        filename : FITS filename with EXTNAME=IMAGE-*, IVAR-*, MASK-* HDUs
        expid : integer, use `expid % n` image where `n` is number of images

    Optional:
        shape : (ny, nx) tuple for output image shape
        jitter : If True (default), apply random flips and rolls so you
            don't get the exact same cosmics every time

    Returns:
        `desisim.image.Image` object with attributes pix, ivar, mask
    """
    fx = fits.open(filename)
    imagekeys = list()
    for i in range(len(fx)):
        if fx[i].name.startswith('IMAGE-'):
            imagekeys.append(fx[i].name.split('-', 1)[1])

    assert len(imagekeys) > 0, 'No IMAGE-* extensions found in ' + filename
    i = expid % len(imagekeys)
    pix = native_endian(fx['IMAGE-' + imagekeys[i]].data.astype(np.float64))
    ivar = native_endian(fx['IVAR-' + imagekeys[i]].data.astype(np.float64))
    mask = native_endian(fx['MASK-' + imagekeys[i]].data)
    meta = fx['IMAGE-' + imagekeys[i]].header
    meta['CRIMAGE'] = (imagekeys[i], 'input cosmic ray image')

    if shape is not None:
        if len(shape) != 2: raise ValueError('Invalid shape {}'.format(shape))
        newpix = np.empty(shape, dtype=np.float64)
        ny = min(shape[0], pix.shape[0])
        nx = min(shape[1], pix.shape[1])
        newpix[0:ny, 0:nx] = pix[0:ny, 0:nx]

        pix = _resize(pix, shape)
        ivar = _resize(ivar, shape)
        mask = _resize(mask, shape)

    if jitter:
        #- Randomly flip left-right and/or up-down
        if np.random.uniform(0, 1) > 0.5:
            pix = np.fliplr(pix)
            ivar = np.fliplr(ivar)
            mask = np.fliplr(mask)
            meta['CRFLIPLR'] = (True, 'Input cosmics image flipped Left/Right')
        else:
            meta['CRFLIPLR'] = (False,
                                'Input cosmics image NOT flipped Left/Right')

        if np.random.uniform(0, 1) > 0.5:
            pix = np.flipud(pix)
            ivar = np.flipud(ivar)
            mask = np.flipud(mask)
            meta['CRFLIPUD'] = (True, 'Input cosmics image flipped Up/Down')
        else:
            meta['CRFLIPUD'] = (True,
                                'Input cosmics image NOT flipped Up/Down')

        #- Randomly roll image a bit
        nx, ny = np.random.randint(-200, 200, size=2)
        pix = np.roll(np.roll(pix, ny, axis=0), nx, axis=1)
        ivar = np.roll(np.roll(ivar, ny, axis=0), nx, axis=1)
        mask = np.roll(np.roll(mask, ny, axis=0), nx, axis=1)
        meta['CRSHIFTX'] = (nx, 'Input cosmics image shift in x')
        meta['CRSHIFTY'] = (nx, 'Input cosmics image shift in y')
    else:
        meta['CRFLIPLR'] = (False,
                            'Input cosmics image NOT flipped Left/Right')
        meta['CRFLIPUD'] = (True, 'Input cosmics image NOT flipped Up/Down')
        meta['CRSHIFTX'] = (0, 'Input cosmics image shift in x')
        meta['CRSHIFTY'] = (0, 'Input cosmics image shift in y')

    #- RDNOISEn -> average RDNOISE
    if 'RDNOISE' not in meta:
        x = meta['RDNOISE0'] + meta['RDNOISE1'] + meta['RDNOISE2'] + meta[
            'RDNOISE3']
        meta['RDNOISE'] = x / 4.0

    return Image(pix, ivar, mask, meta=meta)
Example #14
0
def read_spectra(infile, single=False, coadd=None):
    """Read Spectra object from FITS file.

    This reads data written by the write_spectra function.  A new Spectra
    object is instantiated and returned.

    Args:
        infile (str): path to read
        single (bool): if True, keep spectra as single precision in memory.
        coadd (array-like): if set, coadd all spectra from the provided targetids.

    Returns (Spectra):
        The object containing the data read from disk.

    """

    ftype = np.float64
    if single:
        ftype = np.float32

    infile = os.path.abspath(infile)
    if not os.path.isfile(infile):
        raise FileNotFoundError("{} is not a file!".format(infile))

    # initialize data objects
    bands = []
    fmap = None
    wave = None
    flux = None
    ivar = None
    mask = None
    res = None
    extra = None
    scores = None

    with fits.open(infile, mode="readonly") as hdulist:
        nhdu = len(hdulist)

        # load the metadata.
        meta = hdulist[0].header

        # For efficiency, go through the HDUs in disk-order.  Use the
        # extension name to determine where to put the data.  We don't
        # explicitly copy the data, since that will be done when constructing
        # the Spectra object.

        for h in range(1, nhdu):
            name = hdulist[h].header["EXTNAME"]
            if name == "FIBERMAP":
                fmap = encode_table(Table(hdulist[h].data, copy=True).as_array())
            elif name == "SCORES":
                scores = encode_table(Table(hdulist[h].data, copy=True).as_array())
            else:
                # Find the band based on the name
                mat = re.match(r"(.*)_(.*)", name)
                if mat is None:
                    raise RuntimeError("FITS extension name {} does not contain the band".format(name))
                band = mat.group(1).lower()
                type = mat.group(2)
                if band not in bands:
                    bands.append(band)
                if type == "WAVELENGTH":
                    if wave is None:
                        wave = {}
                    wave[band] = native_endian(hdulist[h].data.astype(ftype))
                elif type == "FLUX":
                    if flux is None:
                        flux = {}
                    flux[band] = native_endian(hdulist[h].data.astype(ftype))
                elif type == "IVAR":
                    if ivar is None:
                        ivar = {}
                    ivar[band] = native_endian(hdulist[h].data.astype(ftype))
                elif type == "MASK":
                    if mask is None:
                        mask = {}
                    mask[band] = native_endian(hdulist[h].data.astype(np.uint32))
                elif type == "RESOLUTION":
                    if res is None:
                        res = {}
                    res[band] = native_endian(hdulist[h].data.astype(ftype))
                else:
                    # this must be an "extra" HDU
                    if extra is None:
                        extra = {}
                    if band not in extra:
                        extra[band] = {}
                    extra[band][type] = native_endian(hdulist[h].data.astype(ftype))

    if coadd is not None:
        uniq, indices = np.unique(coadd, return_index=True)
        targetids = uniq[indices.argsort()]
        ntargets = len(targetids)
        cwave = dict()
        cflux = dict()
        civar = dict()
        crdat = dict()
        cmask = dict()
        for channel in bands:
            cwave[channel] = wave[channel].copy()
            nwave = len(cwave[channel])
            cflux[channel] = np.zeros((ntargets, nwave))
            civar[channel] = np.zeros((ntargets, nwave))
            ndiag = res[channel].shape[1]
            crdat[channel] = np.zeros((ntargets, ndiag, nwave))
            cmask[channel] = np.zeros((ntargets, nwave), dtype=mask[channel].dtype)
        #- Loop over targets, coadding all spectra for each target
        fibermap = Table(dtype=fmap.dtype)
        for i, targetid in enumerate(targetids):
            ii = np.where(fmap['TARGETID'] == targetid)[0]
            fibermap.add_row(fmap[ii[0]])
            for channel in bands:
                if len(ii) > 1:
                    outwave, outflux, outivar, outrdat = _coadd(
                        wave[channel],
                        flux[channel][ii],
                        ivar[channel][ii],
                        res[channel][ii]
                        )
                    outmask = mask[channel][ii[0]]
                    for j in range(1, len(ii)):
                        outmask |= mask[channel][ii[j]]
                else:
                    outwave, outflux, outivar, outrdat = (
                        wave[channel],
                        flux[channel][ii[0]],
                        ivar[channel][ii[0]],
                        res[channel][ii[0]]
                        )
                    outmask = mask[channel][ii[0]]

                cflux[channel][i] = outflux
                civar[channel][i] = outivar
                crdat[channel][i] = outrdat
                cmask[channel][i] = outmask

        return Spectra(bands, cwave, cflux, civar, mask=cmask, resolution_data=crdat,
                       fibermap=fibermap, meta=meta, extra=extra, single=single,
                       scores=scores)

    # Construct the Spectra object from the data.  If there are any
    # inconsistencies in the sizes of the arrays read from the file,
    # they will be caught by the constructor.

    return Spectra(bands, wave, flux, ivar, mask=mask, resolution_data=res,
                   fibermap=fmap, meta=meta, extra=extra, single=single,
                   scores=scores)
Example #15
0
def read_qframe(filename, nspec=None, skip_resolution=False):
    """Reads a frame fits file and returns its data.

    Args:
        filename: path to a file
        skip_resolution: bool, option
            Speed up read time (>5x) by avoiding the Resolution matrix

    Returns:
        desispec.Frame object with attributes wave, flux, ivar, etc.
    """
    log = get_logger()

    if not os.path.isfile(filename) :
        raise IOError("cannot open"+filename)

    fx = fits.open(filename, uint=True, memmap=False)
    hdr = fx[0].header
    flux = native_endian(fx['FLUX'].data.astype('f8'))
    ivar = native_endian(fx['IVAR'].data.astype('f8'))
    wave = native_endian(fx['WAVELENGTH'].data.astype('f8'))

    if wave.shape != flux.shape :
        log.error("{} is not a valid QFrame file because wave.shape != flux.shape".format(filename))
        return None


    if 'MASK' in fx:
        mask = native_endian(fx['MASK'].data)
    else:
        mask = None   #- let the Frame object create the default mask

    if 'SIGMA' in fx:
        sigma = native_endian(fx['SIGMA'].data.astype('f8'))
    else:
        sigma = None


    if 'FIBERMAP' in fx:
        fibermap = fx['FIBERMAP'].data
        fibers   = fibermap['FIBER']
    else:
        fibermap = None
        fibers = None

    fx.close()

    if nspec is not None:
        flux = flux[0:nspec]
        ivar = ivar[0:nspec]
        if mask is not None:
            mask = mask[0:nspec]
        if fibermap is not None:
            fibermap = fibermap[:][0:nspec]
        if fibers is not None:
            fibers = fibers[:][0:nspec]

    # return flux,ivar,wave,resolution_data, hdr
    qframe = QFrame(wave, flux, ivar, mask=mask, sigma=sigma, meta=hdr, fibermap=fibermap, fibers=fibers)

    # Return
    return qframe
Example #16
0
def read_cosmics(filename, expid=1, shape=None, jitter=True):
    """
    Reads a dark image with cosmics from the input filename.

    The input might have multiple dark images; use the `expid%n` image where
    `n` is the number of images in the input cosmics file.

    Args:
        filename : FITS filename with EXTNAME=IMAGE-*, IVAR-*, MASK-* HDUs
        expid : integer, use `expid % n` image where `n` is number of images
        shape : (ny, nx, optional) tuple for output image shape
        jitter (bool, optional): If True (default), apply random flips and rolls so you
            don't get the exact same cosmics every time

    Returns:
        `desisim.image.Image` object with attributes pix, ivar, mask
    """
    fx = fits.open(filename)
    imagekeys = list()
    for i in range(len(fx)):
        if fx[i].name.startswith('IMAGE-'):
            imagekeys.append(fx[i].name.split('-', 1)[1])

    assert len(imagekeys) > 0, 'No IMAGE-* extensions found in ' + filename
    i = expid % len(imagekeys)
    pix = native_endian(fx['IMAGE-' + imagekeys[i]].data.astype(np.float64))
    ivar = native_endian(fx['IVAR-' + imagekeys[i]].data.astype(np.float64))
    mask = native_endian(fx['MASK-' + imagekeys[i]].data)
    meta = fx['IMAGE-' + imagekeys[i]].header
    meta['CRIMAGE'] = (imagekeys[i], 'input cosmic ray image')

    #- De-trend each amplifier
    nx = pix.shape[1] // 2
    ny = pix.shape[0] // 2
    kernel_size = min(201, ny // 3, nx // 3)

    pix[0:ny, 0:nx] -= spline_medfilt2d(pix[0:ny, 0:nx], kernel_size)
    pix[0:ny, nx:2 * nx] -= spline_medfilt2d(pix[0:ny, nx:2 * nx], kernel_size)
    pix[ny:2 * ny, 0:nx] -= spline_medfilt2d(pix[ny:2 * ny, 0:nx], kernel_size)
    pix[ny:2 * ny, nx:2 * nx] -= spline_medfilt2d(pix[ny:2 * ny, nx:2 * nx],
                                                  kernel_size)

    if shape is not None:
        if len(shape) != 2: raise ValueError('Invalid shape {}'.format(shape))
        pix = _resize(pix, shape)
        ivar = _resize(ivar, shape)
        mask = _resize(mask, shape)

    if jitter:
        #- Randomly flip left-right and/or up-down
        if np.random.uniform(0, 1) > 0.5:
            pix = np.fliplr(pix)
            ivar = np.fliplr(ivar)
            mask = np.fliplr(mask)
            meta['CRFLIPLR'] = (True, 'Input cosmics image flipped Left/Right')
        else:
            meta['CRFLIPLR'] = (False,
                                'Input cosmics image NOT flipped Left/Right')

        if np.random.uniform(0, 1) > 0.5:
            pix = np.flipud(pix)
            ivar = np.flipud(ivar)
            mask = np.flipud(mask)
            meta['CRFLIPUD'] = (True, 'Input cosmics image flipped Up/Down')
        else:
            meta['CRFLIPUD'] = (False,
                                'Input cosmics image NOT flipped Up/Down')

        #- Randomly roll image a bit
        nx, ny = np.random.randint(-100, 100, size=2)
        pix = np.roll(np.roll(pix, ny, axis=0), nx, axis=1)
        ivar = np.roll(np.roll(ivar, ny, axis=0), nx, axis=1)
        mask = np.roll(np.roll(mask, ny, axis=0), nx, axis=1)
        meta['CRSHIFTX'] = (nx, 'Input cosmics image shift in x')
        meta['CRSHIFTY'] = (nx, 'Input cosmics image shift in y')
    else:
        meta['CRFLIPLR'] = (False,
                            'Input cosmics image NOT flipped Left/Right')
        meta['CRFLIPUD'] = (False, 'Input cosmics image NOT flipped Up/Down')
        meta['CRSHIFTX'] = (0, 'Input cosmics image shift in x')
        meta['CRSHIFTY'] = (0, 'Input cosmics image shift in y')

    del meta['RDNOISE0']
    #- Amp 1 lower left
    nx = pix.shape[1] // 2
    ny = pix.shape[0] // 2
    iixy = np.s_[0:ny, 0:nx]
    cx = pix[iixy][mask[iixy] == 0]
    mean, median, std = sigma_clipped_stats(cx, sigma=3, iters=5)
    meta['RDNOISE1'] = std

    #- Amp 2 lower right
    iixy = np.s_[0:ny, nx:2 * nx]
    cx = pix[iixy][mask[iixy] == 0]
    mean, median, std = sigma_clipped_stats(cx, sigma=3, iters=5)
    meta['RDNOISE2'] = std

    #- Amp 3 upper left
    iixy = np.s_[ny:2 * ny, 0:nx]
    mean, median, std = sigma_clipped_stats(pix[iixy], sigma=3, iters=5)
    meta['RDNOISE3'] = std

    #- Amp 4 upper right
    iixy = np.s_[ny:2 * ny, nx:2 * nx]
    mean, median, std = sigma_clipped_stats(pix[iixy], sigma=3, iters=5)
    meta['RDNOISE4'] = std
    fx.close()

    return Image(pix, ivar, mask, meta=meta)
Example #17
0
def read_simspec(filename,
                 cameras=None,
                 comm=None,
                 readflux=True,
                 readphot=True):
    """
    Read a simspec file and return a SimSpec object

    Args:
        filename: input simspec file name

    Options:
        cameras: camera name or list of names, e.g. b0, r1, z9
        comm: MPI communicator
        readflux: if True (default), include flux
        readphot: if True (default), include per-camera photons
    """
    if comm is not None:
        rank, size = comm.rank, comm.size
    else:
        rank, size = 0, 1

    if cameras is None:
        #- Build the potential cameras list based upon the fibermap
        if rank == 0:
            fibermap = fits.getdata(filename, 'FIBERMAP')
            cameras = fibers2cameras(fibermap['FIBER'])

        if comm is not None:
            cameras = comm.bcast(cameras, root=0)

    elif isinstance(cameras, str):
        cameras = [
            cameras,
        ]

    #- Read and broadcast data that are common across cameras
    header = flavor = truth = fibermap = obsconditions = None
    wave = flux = skyflux = None
    if rank == 0:
        with fits.open(filename, memmap=False) as fx:
            header = fx[0].header.copy()
            flavor = header['FLAVOR']

            if 'WAVE' in fx and readflux:
                wave = native_endian(fx['WAVE'].data.copy())

            if 'FLUX' in fx and readflux:
                flux = native_endian(fx['FLUX'].data.astype('f8'))

            if 'SKYFLUX' in fx and readflux:
                skyflux = native_endian(fx['SKYFLUX'].data.astype('f8'))

            if 'TRUTH' in fx:
                truth = Table(fx['TRUTH'].data)

            if 'FIBERMAP' in fx:
                fibermap = Table(fx['FIBERMAP'].data)

            if 'OBSCONDITIONS' in fx:
                obsconditions = Table(fx['OBSCONDITIONS'].data)[0]

    if comm is not None:
        header = comm.bcast(header, root=0)
        flavor = comm.bcast(flavor, root=0)
        truth = comm.bcast(truth, root=0)
        fibermap = comm.bcast(fibermap, root=0)
        obsconditions = comm.bcast(obsconditions, root=0)

        wave = comm.bcast(wave, root=0)
        flux = comm.bcast(flux, root=0)
        skyflux = comm.bcast(skyflux, root=0)

    #- Trim arrays to match camera
    #- Note: we do this after the MPI broadcast because rank 0 doesn't know
    #- which ranks need which cameras.  Although inefficient, in practice
    #- this doesn't matter (yet?) because the place we use parallelism is
    #- pixsim which uses readflux=False and thus doesn't broadcast flux anyway
    ii = np.zeros(len(fibermap), dtype=bool)
    for camera in cameras:
        spectrograph = int(camera[1])  #- e.g. b0
        fibers = np.arange(500, dtype=int) + spectrograph * 500
        ii |= np.in1d(fibermap['FIBER'], fibers)

    assert np.any(ii), "input simspec doesn't cover cameras {}".format(cameras)

    full_fibermap = fibermap
    fibermap = fibermap[ii]
    if flux is not None:
        flux = flux[ii]
    if skyflux is not None:
        skyflux = skyflux[ii]
    if truth is not None:
        truth = truth[ii]

    simspec = SimSpec(flavor, wave, flux, skyflux, fibermap, truth,
                      obsconditions, header)

    #- Now read individual camera photons
    #- NOTE: this is somewhat inefficient since the same PHOT_B/R/Z HDUs
    #- are read multiple times by different nodes for different cameras,
    #- though at least only one reader per camera (node) not per rank.
    #- If this is slow, this would be an area for optimization.
    if readphot:
        for camera in cameras:
            channel = camera[0].upper()
            spectrograph = int(camera[1])
            fiber = full_fibermap['FIBER']
            ii = (spectrograph * 500 <= fiber) & (fiber <
                                                  (spectrograph + 1) * 500)
            assert np.any(ii), 'Camera {} is not in fibers {}-{}'.format(
                camera, np.min(fiber), np.max(fiber))

            #- Split MPI communicator by camera
            #- read and broadcast each camera
            if comm is not None:
                tmp = 'b0 r0 z0 b1 r1 z1 b2 r2 z2 b3 r3 z3 b4 r4 z4 b5 r5 z5 b6 r6 z6 b7 r7 z7 b8 r8 z8 b9 r9 z9'.split(
                )
                camcomm = comm.Split(color=tmp.index(camera))
                camrank = camcomm.rank
            else:
                camcomm = None
                camrank = 0

            wave = phot = skyphot = None
            if camrank == 0:
                with fits.open(filename, memmap=False) as fx:
                    wave = native_endian(fx['WAVE_' + channel].data.copy())
                    phot = native_endian(fx['PHOT_' +
                                            channel].data[ii].astype('f8'))
                    if 'SKYPHOT_' + channel in fx:
                        skyphot = native_endian(
                            fx['SKYPHOT_' + channel].data[ii].astype('f8'))
                    else:
                        skyphot = None

            if camcomm is not None:
                wave = camcomm.bcast(wave, root=0)
                phot = camcomm.bcast(phot, root=0)
                skyphot = camcomm.bcast(skyphot, root=0)

            simspec.add_camera(camera, wave, phot, skyphot)

    return simspec
Example #18
0
def read_qframe(filename, nspec=None, skip_resolution=False):
    """Reads a frame fits file and returns its data.

    Args:
        filename: path to a file
        skip_resolution: bool, option
            Speed up read time (>5x) by avoiding the Resolution matrix

    Returns:
        desispec.Frame object with attributes wave, flux, ivar, etc.
    """
    log = get_logger()

    if not os.path.isfile(filename):
        raise IOError("cannot open" + filename)

    fx = fits.open(filename, uint=True, memmap=False)
    hdr = fx[0].header
    flux = native_endian(fx['FLUX'].data.astype('f8'))
    ivar = native_endian(fx['IVAR'].data.astype('f8'))
    wave = native_endian(fx['WAVELENGTH'].data.astype('f8'))

    if wave.shape != flux.shape:
        log.error(
            "{} is not a valid QFrame file because wave.shape != flux.shape".
            format(filename))
        return None

    if 'MASK' in fx:
        mask = native_endian(fx['MASK'].data)
    else:
        mask = None  #- let the Frame object create the default mask

    if 'SIGMA' in fx:
        sigma = native_endian(fx['SIGMA'].data.astype('f8'))
    else:
        sigma = None

    if 'FIBERMAP' in fx:
        fibermap = fx['FIBERMAP'].data
        fibers = fibermap['FIBER']
    else:
        fibermap = None
        fibers = None

    fx.close()

    if nspec is not None:
        flux = flux[0:nspec]
        ivar = ivar[0:nspec]
        if mask is not None:
            mask = mask[0:nspec]
        if fibermap is not None:
            fibermap = fibermap[:][0:nspec]
        if fibers is not None:
            fibers = fibers[:][0:nspec]

    # return flux,ivar,wave,resolution_data, hdr
    qframe = QFrame(wave,
                    flux,
                    ivar,
                    mask=mask,
                    sigma=sigma,
                    meta=hdr,
                    fibermap=fibermap,
                    fibers=fibers)

    # Return
    return qframe
Example #19
0
def read_simspec_mpi(filename, comm, channel, spectrographs=None):
    """
    Read simspec data from filename and return SimSpec object.
    """
    import astropy.table
    from mpi4py import MPI  #need to reimport this so MPI.DOUBLE can be used

    # rank 0 opens file and gets the metadata and wavelength
    # grids, which will be kept on all processes.

    hdr = None
    flavor = None
    fibermap = None
    obs = None
    wave = dict()
    totalspec = None

    if comm.rank == 0:
        fx = fits.open(filename, memmap=True)
        hdr = fx[0].header.copy()
        flavor = hdr['FLAVOR']
        if 'WAVE' in fx:
            wave['brz'] = native_endian(fx['WAVE'].data.copy())
        #for channel in ('b', 'r', 'z'):
        hname = 'WAVE_' + channel.upper()
        wave[channel] = native_endian(fx[hname].data.copy())
        if 'FIBERMAP' in fx:
            fibermap = astropy.table.Table(fx['FIBERMAP'].data.copy())
            totalspec = len(fibermap)
        else:
            # Get the number of spectra from one of the photon HDUs
            totalspec = fx['PHOT_B'].header['NAXIS2']
        if 'OBSCONDITIONS' in fx:
            obs = astropy.table.Table(fx['OBSCONDITIONS'].data.copy())[0]
        fx.close()
        # Memmap file handle should close here when fx goes out of scope...

    hdr = comm.bcast(hdr, root=0)
    flavor = comm.bcast(flavor, root=0)
    obs = comm.bcast(obs, root=0)
    totalspec = comm.bcast(totalspec, root=0)
    wave = comm.bcast(wave, root=0)
    fibermap = comm.bcast(fibermap, root=0)

    # Based on the spectrographs for this process, compute the range of
    # spectra we need to store.  The number of spectra per spectrograph (500)
    # is hard-coded several places in desisim.  This should be put in desimodel
    # somewhere...

    fibers = None
    if fibermap is not None:
        fibers = np.array(fibermap['FIBER'], dtype=np.int32)
    else:
        fibers = np.arange(totalspec, dtype=np.int32)

    #this comes in as an input, spectrographs=group_spectra[i]
    #just simulate and write one spectrograph at a time
    if spectrographs is None:
        spectrographs = np.arange(10, dtype=np.int32)

    specslice = np.in1d(fibers // 500, spectrographs)

    if fibermap is not None:
        fibermap = fibermap[specslice]

    # Now read one HDU at a time, broadcast, and every process grabs its slice.

    # Note: this is global scope within the function, so memmap file handle
    # will not close until the function returns (which is fine).
    # only want to open file for rank 0 to cut down on I/O
    if comm.rank == 0:
        hdus = None
        hdus = fits.open(filename, memmap=True)

    #in these next blocks, we fix the endian-ness of the data for each type
    #we also extract the data for later broadcast if comm.rank == 0
    #and we store the shape of the data to allocate numpy arrays if comm_rank !=0
    #it looks a little silly but it's better than trying to convert from a python
    #dictionary back to a numpy array later

    #preallocate shape_dict
    shape_dict = dict()

    #have to check in a different way than read_simspec since we don't
    #have fx availble on all ranks

    #we will sort according to flavor in the mpi version
    #flavor = flat has phot and flux
    #flavor = arc has phot
    #flavor = science has phot, flux, skyphot, and skyflux

    #all flavors have photons
    hname = 'PHOT_' + channel.upper()
    if comm.rank == 0:
        phot_hdata = np.empty(1, dtype=np.float64)
        phot_hdata = native_endian(hdus[hname].data.copy().astype('f8'))
        shape_dict[hname] = hdus[hname].shape
    del hname

    #flavors=science and flat have flux
    hname = 'FLUX'
    if comm.rank == 0:
        flux_hdata = np.empty(1, dtype=np.float64)
        if (flavor == 'science') or (flavor == 'flat'):
            flux_hdata = native_endian(hdus[hname].data.copy().astype('f8'))
            shape_dict[hname] = hdus[hname].shape
    del hname

    #only flavor=science has skyphot
    hname = 'SKYPHOT_' + channel.upper()
    if comm.rank == 0:
        sky_hdata = np.empty(1, dtype=np.float64)
        if flavor == 'science':
            sky_hdata = native_endian(hdus[hname].data.copy().astype('f8'))
            shape_dict[hname] = hdus[hname].shape
    del hname

    #only flavor=science has skyflux
    hname = 'SKYFLUX'
    if comm.rank == 0:
        skyflux_hdata = np.empty(1, dtype=np.float64)
        if flavor == 'science':
            skyflux_hdata = native_endian(hdus[hname].data.copy().astype('f8'))
            shape_dict[hname] = hdus[hname].shape
    del hname

    #now put shape tuples into a dict so we can broadcast them
    #one broadcast is more efficienct than many broadcasts
    #this allows the ranks to know what size to preallocate
    shape_dict = comm.bcast(shape_dict, root=0)
    #add a barrier so we can make sure these data have been broadcast
    #to all ranks before we start the next process
    comm.Barrier()

    #we will sort according to flavor in the mpi version
    #flavor = flat has phot and flux
    #flavor = arc has phot
    #flavor = science has phot, flux, skyphot, and skyflux

    # Read photons
    # all flavors have photons
    phot = dict()
    if comm.rank == 0:
        #hdata=phot_hdata
        phot[channel] = phot_hdata[specslice]
    phot = comm.bcast(phot, root=0)

    # Read flux
    #flavors science and flat have flux
    flux = dict()
    if (flavor == 'science') or (flavor == 'flat'):
        if comm.rank == 0:
            flux[channel] = flux_hdata[specslice]
        flux = comm.bcast(flux, root=0)

    # Read sky photons
    #only flavor=science has skyphot
    skyphot = dict()
    if flavor == 'science':
        if comm.rank == 0:
            skyphot[channel] = sky_hdata[specslice]
        skyphot = comm.bcast(skyphot, root=0)
    else:
        skyphot[channel] = np.zeros_like(phot[channel])
    assert phot[channel].shape == skyphot[channel].shape

    # Read skyflux
    #only flavor science has skyflux
    skyflux = np.empty(1, dtype=np.float64)
    if flavor == 'science':
        if comm.rank == 0:
            skyflux = skyflux_hdata[specslice]
        elif comm.rank != 0:
            skyflux = np.empty(shape_dict['SKYFLUX'],
                               dtype=np.float64)[specslice]
        comm.Bcast([skyflux, MPI.DOUBLE], root=0)

    # metadata / truth
    metadata = None
    hname = 'TRUTH'
    found = False
    if comm.rank == 0:
        if hname in hdus:
            found = True
    found = comm.bcast(found, root=0)
    if not found:
        hname = 'METADATA'
        if comm.rank == 0:
            if hname in hdus:
                found = True
        found = comm.bcast(found, root=0)
    if found:
        hdata = None
        if comm.rank == 0:
            hdata = astropy.table.Table(hdus[hname].data.copy())
        hdata = comm.bcast(
            hdata, root=0
        )  #leaving this call alone because hdata is not a numpy array
        metadata = hdata[specslice].copy()
        del hdata

        if comm.rank == 0:
            hdus.close()

    return SimSpec(flavor,
                   wave,
                   phot,
                   flux=flux,
                   skyflux=skyflux,
                   skyphot=skyphot,
                   metadata=metadata,
                   fibermap=fibermap,
                   obs=obs,
                   header=hdr)
Example #20
0
def read_simspec(filename, nspec=None, firstspec=0):
    """Read simspec data from filename and return SimSpec object.
    """
    import astropy.table
    with fits.open(filename, memmap=False) as fx:
        hdr = fx[0].header
        flavor = hdr['FLAVOR']

        #- All flavors have photons
        wave = dict()
        phot = dict()
        skyphot = dict()
        for channel in ('b', 'r', 'z'):
            wave[channel] = native_endian(fx['WAVE_' + channel.upper()].data)
            phot[channel] = native_endian(
                fx['PHOT_' + channel.upper()].data.astype('f8'))

            skyext = 'SKYPHOT_' + channel.upper()
            if skyext in fx:
                skyphot[channel] = native_endian(fx[skyext].data.astype('f8'))
            else:
                skyphot[channel] = np.zeros_like(phot[channel])

            assert phot[channel].shape == skyphot[channel].shape

        #- Check for flux, skyflux, and metadata
        flux = None
        skyflux = None
        if 'WAVE' in fx:
            wave['brz'] = native_endian(fx['WAVE'].data)
        if 'FLUX' in fx:
            flux = native_endian(fx['FLUX'].data.astype('f8'))
        if 'SKYFLUX' in fx:
            skyflux = native_endian(fx['SKYFLUX'].data.astype('f8'))

        if 'TRUTH' in fx:
            metadata = astropy.table.Table(fx['TRUTH'].data)
        #- For backwards compatibility
        elif 'METADATA' in fx:
            metadata = astropy.table.Table(fx['METADATA'].data)
        else:
            metadata = None

        if 'FIBERMAP' in fx:
            fibermap = astropy.table.Table(fx['FIBERMAP'].data)
        else:
            fibermap = None

        if 'OBSCONDITIONS' in fx:
            obs = astropy.table.Table(fx['OBSCONDITIONS'].data)[0]
        else:
            obs = None

    #- Trim down if requested
    if nspec is None:
        nspec = phot['b'].shape[0]

    if firstspec > 0 or firstspec + nspec < phot['b'].shape[0]:
        for channel in ('b', 'r', 'z'):
            phot[channel] = phot[channel][firstspec:firstspec + nspec]
            skyphot[channel] = skyphot[channel][firstspec:firstspec + nspec]
        if flux is not None:
            flux = flux[firstspec:firstspec + nspec]
        if skyflux is not None:
            skyflux = skyflux[firstspec:firstspec + nspec]
        if metadata is not None:
            metadata = metadata[firstspec:firstspec + nspec]

    return SimSpec(flavor,
                   wave,
                   phot,
                   flux=flux,
                   skyflux=skyflux,
                   skyphot=skyphot,
                   metadata=metadata,
                   fibermap=fibermap,
                   obs=obs,
                   header=hdr)