def write_fiberflat(outfile, fiberflat, header=None): """Write fiberflat object to outfile Args: outfile: filepath string or (night, expid, camera) tuple fiberflat: FiberFlat object header: (optional) dict or fits.Header object to use as HDU 0 header Returns: filepath of file that was written """ outfile = makepath(outfile, 'fiberflat') if header is None: hdr = fitsheader(fiberflat.header) else: hdr = fitsheader(header) if fiberflat.chi2pdf is not None: hdr['chi2pdf'] = float(fiberflat.chi2pdf) add_dependencies(hdr) ff = fiberflat #- shorthand hdus = fits.HDUList() hdus.append(fits.PrimaryHDU(ff.fiberflat.astype('f4'), header=hdr)) hdus.append(fits.ImageHDU(ff.ivar.astype('f4'), name='IVAR')) hdus.append(fits.CompImageHDU(ff.mask, name='MASK')) hdus.append(fits.ImageHDU(ff.meanspec.astype('f4'), name='MEANSPEC')) hdus.append(fits.ImageHDU(ff.wave.astype('f4'), name='WAVELENGTH')) hdus.writeto(outfile + '.tmp', clobber=True, checksum=True) os.rename(outfile + '.tmp', outfile) return outfile
def write_fiberflat(outfile,fiberflat,header=None): """Write fiberflat object to outfile Args: outfile: filepath string or (night, expid, camera) tuple fiberflat: FiberFlat object header: (optional) dict or fits.Header object to use as HDU 0 header Returns: filepath of file that was written """ outfile = makepath(outfile, 'fiberflat') if header is None: hdr = fitsheader(fiberflat.header) else: hdr = fitsheader(header) if fiberflat.chi2pdf is not None: hdr['chi2pdf'] = float(fiberflat.chi2pdf) add_dependencies(hdr) ff = fiberflat #- shorthand hdus = fits.HDUList() hdus.append(fits.PrimaryHDU(ff.fiberflat.astype('f4'), header=hdr)) hdus.append(fits.ImageHDU(ff.ivar.astype('f4'), name='IVAR')) hdus.append(fits.CompImageHDU(ff.mask, name='MASK')) hdus.append(fits.ImageHDU(ff.meanspec.astype('f4'), name='MEANSPEC')) hdus.append(fits.ImageHDU(ff.wave.astype('f4'), name='WAVELENGTH')) hdus.writeto(outfile+'.tmp', clobber=True, checksum=True) os.rename(outfile+'.tmp', outfile) return outfile
def write_fibermap(outfile, fibermap, header=None, clobber=True, extname='FIBERMAP'): """Write fibermap binary table to outfile. Args: outfile (str): output filename fibermap: astropy Table of fibermap data header: header data to include in same HDU as fibermap clobber (bool, optional): overwrite outfile if it exists extname (str, optional): set the extension name. Returns: write_fibermap (str): full path to filename of fibermap file written. """ outfile = makepath(outfile) #- astropy.io.fits incorrectly generates warning about 2D arrays of strings #- Temporarily turn off warnings to avoid this; desispec.test.test_io will #- catch it if the arrays actually are written incorrectly. if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(fibermap.meta) add_dependencies(hdr) with warnings.catch_warnings(): warnings.simplefilter("ignore") write_bintable(outfile, fibermap, hdr, comments=fibermap_comments, extname=extname, clobber=clobber) return outfile
def write_sky(outfile, skymodel, header=None): """Write sky model. Args: outfile : filename or (night, expid, camera) tuple skymodel : SkyModel object, with the following attributes wave : 1D wavelength in vacuum Angstroms flux : 2D[nspec, nwave] sky flux ivar : 2D inverse variance of sky flux mask : 2D mask for sky flux header : optional fits header data (fits.Header, dict, or list) """ outfile = makepath(outfile, 'sky') #- Convert header to fits.Header if needed if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(skymodel.header) add_dependencies(hdr) hx = fits.HDUList() hdr['EXTNAME'] = ('SKY', 'no dimension') hx.append( fits.PrimaryHDU(skymodel.flux.astype('f4'), header=hdr) ) hx.append( fits.ImageHDU(skymodel.ivar.astype('f4'), name='IVAR') ) hx.append( fits.CompImageHDU(skymodel.mask, name='MASK') ) hx.append( fits.ImageHDU(skymodel.wave.astype('f4'), name='WAVELENGTH') ) hx.writeto(outfile+'.tmp', clobber=True, checksum=True) os.rename(outfile+'.tmp', outfile) return outfile
def write_fibermap(outfile, fibermap, header=None): """Write fibermap binary table to outfile. Args: outfile (str): output filename fibermap: astropy Table of fibermap data header: header data to include in same HDU as fibermap Returns: write_fibermap (str): full path to filename of fibermap file written. """ outfile = makepath(outfile) #- astropy.io.fits incorrectly generates warning about 2D arrays of strings #- Temporarily turn off warnings to avoid this; desispec.test.test_io will #- catch it if the arrays actually are written incorrectly. if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(fibermap.meta) add_dependencies(hdr) with warnings.catch_warnings(): warnings.simplefilter("ignore") write_bintable(outfile, fibermap, hdr, comments=fibermap_comments, extname="FIBERMAP", clobber=True) return outfile
def write_fiberflat(outfile, fiberflat, header=None): """Write fiberflat object to outfile Args: outfile: filepath string or (night, expid, camera) tuple header: (optional) dict or fits.Header object to use as HDU 0 header Returns: filepath of file that was written """ outfile = makepath(outfile, 'fiberflat') if header is None: hdr = fitsheader(fiberflat.header) else: hdr = fitsheader(header) ff = fiberflat #- shorthand hdus = fits.HDUList() hdus.append(fits.PrimaryHDU(ff.fiberflat, header=hdr)) hdus.append(fits.ImageHDU(ff.ivar, name='IVAR')) hdus.append(fits.ImageHDU(ff.mask, name='MASK')) hdus.append(fits.ImageHDU(ff.meanspec, name='MEANSPEC')) hdus.append(fits.ImageHDU(ff.wave, name='WAVELENGTH')) hdus.writeto(outfile, clobber=True) return outfile
def write_frame(outfile, frame, header=None, fibermap=None): """Write a frame fits file and returns path to file written. Args: outfile: full path to output file, or tuple (night, expid, channel) frame: desispec.frame.Frame object with wave, flux, ivar... Optional: header: astropy.io.fits.Header or dict to override frame.header fibermap: table to store as FIBERMAP HDU Returns: full filepath of output file that was written Note: to create a Frame object to pass into write_frame, frame = Frame(wave, flux, ivar, resolution_data) """ outfile = makepath(outfile, 'frame') if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(frame.meta) add_dependencies(hdr) hdus = fits.HDUList() x = fits.PrimaryHDU(frame.flux.astype('f4'), header=hdr) x.header['EXTNAME'] = 'FLUX' hdus.append(x) hdus.append(fits.ImageHDU(frame.ivar.astype('f4'), name='IVAR')) hdus.append(fits.CompImageHDU(frame.mask, name='MASK')) hdus.append(fits.ImageHDU(frame.wave.astype('f4'), name='WAVELENGTH')) hdus.append( fits.ImageHDU(frame.resolution_data.astype('f4'), name='RESOLUTION')) if fibermap is not None: hdus.append(fits.BinTableHDU(np.asarray(fibermap), name='FIBERMAP')) elif frame.fibermap is not None: hdus.append( fits.BinTableHDU(np.asarray(frame.fibermap), name='FIBERMAP')) elif frame.spectrograph is not None: x.header[ 'FIBERMIN'] = 500 * frame.spectrograph # Hard-coded (as in desispec.frame) else: log.error( "You are likely writing a frame without sufficient fiber info") hdus.writeto(outfile + '.tmp', clobber=True, checksum=True) os.rename(outfile + '.tmp', outfile) return outfile
def write_frame(outfile, frame, header=None, fibermap=None): """Write a frame fits file and returns path to file written. Args: outfile: full path to output file, or tuple (night, expid, channel) frame: desispec.frame.Frame object with wave, flux, ivar... Optional: header: astropy.io.fits.Header or dict to override frame.header fibermap: table to store as FIBERMAP HDU Returns: full filepath of output file that was written Note: to create a Frame object to pass into write_frame, frame = Frame(wave, flux, ivar, resolution_data) """ outfile = makepath(outfile, 'frame') if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(frame.meta) add_dependencies(hdr) hdus = fits.HDUList() x = fits.PrimaryHDU(frame.flux.astype('f4'), header=hdr) x.header['EXTNAME'] = 'FLUX' hdus.append(x) hdus.append( fits.ImageHDU(frame.ivar.astype('f4'), name='IVAR') ) hdus.append( fits.CompImageHDU(frame.mask, name='MASK') ) hdus.append( fits.ImageHDU(frame.wave.astype('f4'), name='WAVELENGTH') ) hdus.append( fits.ImageHDU(frame.resolution_data.astype('f4'), name='RESOLUTION' ) ) if fibermap is not None: hdus.append( fits.BinTableHDU(np.asarray(fibermap), name='FIBERMAP' ) ) elif frame.fibermap is not None: hdus.append( fits.BinTableHDU(np.asarray(frame.fibermap), name='FIBERMAP' ) ) elif frame.spectrograph is not None: x.header['FIBERMIN'] = 500*frame.spectrograph # Hard-coded (as in desispec.frame) else: log.error("You are likely writing a frame without sufficient fiber info") if frame.chi2pix is not None: hdus.append( fits.ImageHDU(frame.chi2pix.astype('f4'), name='CHI2PIX' ) ) hdus.writeto(outfile+'.tmp', clobber=True, checksum=True) os.rename(outfile+'.tmp', outfile) return outfile
def write_templates(outfile, flux, wave, meta, objtype=None, comments=None, units=None): """Write out simulated galaxy templates. (Incomplete documentation...) Args: outfile (str): Output file name. Returns: Raises """ from astropy.io import fits from desispec.io.util import fitsheader, write_bintable, makepath # Create the path to OUTFILE if necessary. outfile = makepath(outfile) header = dict( OBJTYPE = (objtype, 'Object type'), CUNIT = ('Angstrom', 'units of wavelength array'), CRPIX1 = (1, 'reference pixel number'), CRVAL1 = (wave[0], 'Starting wavelength [Angstrom]'), CDELT1 = (wave[1]-wave[0], 'Wavelength step [Angstrom]'), LOGLAM = (0, 'linear wavelength steps, not log10'), AIRORVAC = ('vac', 'wavelengths in vacuum (vac) or air'), BUNIT = ('erg/s/cm2/A', 'spectrum flux units') ) hdr = fitsheader(header) fits.writeto(outfile,flux.astype(np.float32),header=hdr,clobber=True) write_bintable(outfile, meta, header=hdr, comments=comments, units=units, extname='METADATA')
def write_templates(outfile, flux, wave, meta, objtype=None, comments=None, units=None): """Write out simulated galaxy templates. (Incomplete documentation...) Args: outfile (str): Output file name. """ from astropy.io import fits from desispec.io.util import fitsheader, write_bintable, makepath # Create the path to OUTFILE if necessary. outfile = makepath(outfile) header = dict(OBJTYPE=(objtype, 'Object type'), CUNIT=('Angstrom', 'units of wavelength array'), CRPIX1=(1, 'reference pixel number'), CRVAL1=(wave[0], 'Starting wavelength [Angstrom]'), CDELT1=(wave[1] - wave[0], 'Wavelength step [Angstrom]'), LOGLAM=(0, 'linear wavelength steps, not log10'), AIRORVAC=('vac', 'wavelengths in vacuum (vac) or air'), BUNIT=('1e-17 erg/(s cm2 Angstrom)', 'spectrum flux units')) hdr = fitsheader(header) fits.writeto(outfile, flux.astype(np.float32), header=hdr, clobber=True) write_bintable(outfile, meta, header=hdr, comments=comments, units=units, extname='METADATA')
def write_fibermap(outfile, fibermap, header=None): """Write fibermap binary table to outfile. Args: outfile (str): output filename fibermap: ndarray with named columns of fibermap data header: header data to include in same HDU as fibermap Returns: write_fibermap (str): full path to filename of fibermap file written. """ outfile = makepath(outfile) #- astropy.io.fits incorrectly generates warning about 2D arrays of strings #- Temporarily turn off warnings to avoid this; desispec.test.test_io will #- catch it if the arrays actually are written incorrectly. hdr = fitsheader(header) add_dependencies(hdr) with warnings.catch_warnings(): warnings.simplefilter("ignore") write_bintable(outfile, fibermap, hdr, comments=fibermap_comments, extname="FIBERMAP", clobber=True) return outfile
def write_image(outfile, image, meta=None): """Writes image object to outfile Args: outfile : output file string image : desispec.image.Image object (or any object with 2D array attributes image, ivar, mask) Optional: meta : dict-like object with metadata key/values (e.g. FITS header) """ if meta is not None: hdr = fitsheader(meta) else: hdr = fitsheader(image.meta) add_dependencies(hdr) outdir = os.path.dirname(os.path.abspath(outfile)) if not os.path.isdir(outdir): os.makedirs(outdir) hx = fits.HDUList() hdu = fits.ImageHDU(image.pix.astype(np.float32), name='IMAGE', header=hdr) if 'CAMERA' not in hdu.header: hdu.header.append( ('CAMERA', image.camera.lower(), 'Spectrograph Camera')) if 'RDNOISE' not in hdu.header and np.isscalar(image.readnoise): hdu.header.append( ('RDNOISE', image.readnoise, 'Read noise [RMS electrons/pixel]')) hx.append(hdu) hx.append(fits.ImageHDU(image.ivar.astype(np.float32), name='IVAR')) hx.append(fits.CompImageHDU(image.mask.astype(np.int16), name='MASK')) if not np.isscalar(image.readnoise): hx.append( fits.ImageHDU(image.readnoise.astype(np.float32), name='READNOISE')) hx.writeto(outfile + '.tmp', overwrite=True, checksum=True) os.rename(outfile + '.tmp', outfile) return outfile
def write_fibermap(outfile, fibermap, header=None, clobber=True, extname='FIBERMAP'): """Write fibermap binary table to outfile. Args: outfile (str): output filename fibermap: astropy Table of fibermap data header: header data to include in same HDU as fibermap clobber (bool, optional): overwrite outfile if it exists extname (str, optional): set the extension name. Returns: write_fibermap (str): full path to filename of fibermap file written. """ log = get_logger() outfile = makepath(outfile) #- astropy.io.fits incorrectly generates warning about 2D arrays of strings #- Temporarily turn off warnings to avoid this; desispec.test.test_io will #- catch it if the arrays actually are written incorrectly. if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(fibermap.meta) add_dependencies(hdr) with warnings.catch_warnings(): warnings.simplefilter("ignore") t0 = time.time() write_bintable(outfile, fibermap, hdr, comments=fibermap_comments, extname=extname, clobber=clobber) duration = time.time() - t0 log.info(iotime.format('write', outfile, duration)) return outfile
def write_image(outfile, image, meta=None): """Writes image object to outfile Args: outfile : output file string image : desispec.image.Image object (or any object with 2D array attributes image, ivar, mask) Optional: meta : dict-like object with metadata key/values (e.g. FITS header) """ if meta is not None: hdr = fitsheader(meta) else: hdr = fitsheader(image.meta) add_dependencies(hdr) outdir = os.path.dirname(os.path.abspath(outfile)) if not os.path.isdir(outdir): os.makedirs(outdir) hx = fits.HDUList() hdu = fits.ImageHDU(image.pix.astype(np.float32), name='IMAGE', header=hdr) if 'CAMERA' not in hdu.header: hdu.header.append( ('CAMERA', image.camera.lower(), 'Spectrograph Camera') ) if 'RDNOISE' not in hdu.header and np.isscalar(image.readnoise): hdu.header.append( ('RDNOISE', image.readnoise, 'Read noise [RMS electrons/pixel]')) hx.append(hdu) hx.append(fits.ImageHDU(image.ivar.astype(np.float32), name='IVAR')) hx.append(fits.CompImageHDU(image.mask.astype(np.int16), name='MASK')) if not np.isscalar(image.readnoise): hx.append(fits.ImageHDU(image.readnoise.astype(np.float32), name='READNOISE')) hx.writeto(outfile+'.tmp', overwrite=True, checksum=True) os.rename(outfile+'.tmp', outfile) return outfile
def write_frame(outfile, frame, header=None): """Write a frame fits file and returns path to file written. Args: outfile: full path to output file, or tuple (night, expid, channel) frame: desispec.frame.Frame object with wave, flux, ivar... header: optional astropy.io.fits.Header or dict to override frame.header Returns: full filepath of output file that was written Note: to create a Frame object to pass into write_frame, frame = Frame(wave, flux, ivar, resolution_data) """ outfile = makepath(outfile, 'frame') if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(frame.header) if 'SPECMIN' not in hdr: hdr['SPECMIN'] = 0 if 'SPECMAX' not in hdr: hdr['SPECMAX'] = hdr['SPECMIN'] + frame.nspec hdus = fits.HDUList() x = fits.PrimaryHDU(frame.flux, header=hdr) x.header['EXTNAME'] = 'FLUX' hdus.append(x) hdus.append( fits.ImageHDU(frame.ivar, name='IVAR') ) hdus.append( fits.ImageHDU(frame.mask, name='MASK') ) hdus.append( fits.ImageHDU(frame.wave, name='WAVELENGTH') ) hdus.append( fits.ImageHDU(frame.resolution_data, name='RESOLUTION' ) ) hdus.writeto(outfile, clobber=True) return outfile
def write_sky(outfile, skymodel, header=None): """Write sky model. Args: outfile : filename or (night, expid, camera) tuple skymodel : SkyModel object, with the following attributes wave : 1D wavelength in vacuum Angstroms flux : 2D[nspec, nwave] sky flux ivar : 2D inverse variance of sky flux mask : 2D mask for sky flux header : optional fits header data (fits.Header, dict, or list) """ outfile = makepath(outfile, 'sky') #- Convert header to fits.Header if needed if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(skymodel.header) hdr['EXTNAME'] = ('SKY', 'no dimension') fits.writeto(outfile, skymodel.flux, header=hdr, clobber=True) hdr['EXTNAME'] = ('IVAR', 'no dimension') hdu = fits.ImageHDU(skymodel.ivar, header=hdr) fits.append(outfile, hdu.data, header=hdu.header) hdr['EXTNAME'] = ('MASK', 'no dimension') hdu = fits.ImageHDU(skymodel.mask, header=hdr) fits.append(outfile, hdu.data, header=hdu.header) hdr['EXTNAME'] = ('WAVELENGTH', '[Angstroms]') hdu = fits.ImageHDU(skymodel.wave, header=hdr) fits.append(outfile, hdu.data, header=hdu.header) return outfile
def write_sky(outfile, skymodel, header=None): """Write sky model. Args: outfile : filename or (night, expid, camera) tuple skymodel : SkyModel object, with the following attributes wave : 1D wavelength in vacuum Angstroms flux : 2D[nspec, nwave] sky flux ivar : 2D inverse variance of sky flux mask : 2D mask for sky flux header : optional fits header data (fits.Header, dict, or list) """ outfile = makepath(outfile, 'sky') #- Convert header to fits.Header if needed if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(skymodel.header) hdr['EXTNAME'] = ('SKY', 'no dimension') fits.writeto(outfile, skymodel.flux,header=hdr, clobber=True) hdr['EXTNAME'] = ('IVAR', 'no dimension') hdu = fits.ImageHDU(skymodel.ivar, header=hdr) fits.append(outfile, hdu.data, header=hdu.header) hdr['EXTNAME'] = ('MASK', 'no dimension') hdu = fits.ImageHDU(skymodel.mask, header=hdr) fits.append(outfile, hdu.data, header=hdu.header) hdr['EXTNAME'] = ('WAVELENGTH', '[Angstroms]') hdu = fits.ImageHDU(skymodel.wave, header=hdr) fits.append(outfile, hdu.data, header=hdu.header) return outfile
def write_image(outfile, image, meta=None): """Writes image object to outfile Args: outfile : output file string image : desispec.image.Image object (or any object with 2D array attributes image, ivar, mask) Optional: meta : dict-like object with metadata key/values (e.g. FITS header) """ log = get_logger() if meta is not None: hdr = fitsheader(meta) else: hdr = fitsheader(image.meta) add_dependencies(hdr) #- Work around fitsio>1.0 writing blank keywords, e.g. on 20191212 for key in hdr.keys(): if type(hdr[key]) == fits.card.Undefined: log.warning('Setting blank keyword {} to None'.format(key)) hdr[key] = None outdir = os.path.dirname(os.path.abspath(outfile)) if not os.path.isdir(outdir): os.makedirs(outdir) hx = fits.HDUList() hdu = fits.ImageHDU(image.pix.astype(np.float32), name='IMAGE', header=hdr) if 'CAMERA' not in hdu.header: hdu.header.append( ('CAMERA', image.camera.lower(), 'Spectrograph Camera')) if 'RDNOISE' not in hdu.header and np.isscalar(image.readnoise): hdu.header.append( ('RDNOISE', image.readnoise, 'Read noise [RMS electrons/pixel]')) hx.append(hdu) hx.append(fits.ImageHDU(image.ivar.astype(np.float32), name='IVAR')) hx.append(fits.CompImageHDU(image.mask.astype(np.int16), name='MASK')) if not np.isscalar(image.readnoise): hx.append( fits.ImageHDU(image.readnoise.astype(np.float32), name='READNOISE')) if hasattr(image, 'fibermap'): if isinstance(image.fibermap, Table): fmhdu = fits.convenience.table_to_hdu(image.fibermap) fmhdu.name = 'FIBERMAP' else: fmhdu = fits.BinTableHDU(image.fibermap, name='FIBERMAP') hx.append(fmhdu) hx.writeto(outfile + '.tmp', overwrite=True, checksum=True) os.rename(outfile + '.tmp', outfile) return outfile
def write_frame(outfile, frame, header=None, fibermap=None, units=None): """Write a frame fits file and returns path to file written. Args: outfile: full path to output file, or tuple (night, expid, channel) frame: desispec.frame.Frame object with wave, flux, ivar... Optional: header: astropy.io.fits.Header or dict to override frame.header fibermap: table to store as FIBERMAP HDU Returns: full filepath of output file that was written Note: to create a Frame object to pass into write_frame, frame = Frame(wave, flux, ivar, resolution_data) """ outfile = makepath(outfile, 'frame') if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(frame.meta) add_dependencies(hdr) hdus = fits.HDUList() x = fits.PrimaryHDU(frame.flux.astype('f4'), header=hdr) x.header['EXTNAME'] = 'FLUX' if units is not None: units = str(units) if 'BUNIT' in hdr and hdr['BUNIT'] != units: log.warn('BUNIT {bunit} != units {units}; using {units}'.format( bunit=hdr['BUNIT'], units=units)) x.header['BUNIT'] = units hdus.append(x) hdus.append(fits.ImageHDU(frame.ivar.astype('f4'), name='IVAR')) hdus.append(fits.CompImageHDU(frame.mask, name='MASK')) hdus.append(fits.ImageHDU(frame.wave.astype('f4'), name='WAVELENGTH')) hdus[-1].header['BUNIT'] = 'Angstrom' hdus.append( fits.ImageHDU(frame.resolution_data.astype('f4'), name='RESOLUTION')) if fibermap is not None: fibermap = desiutil.io.encode_table(fibermap) #- unicode -> bytes fibermap.meta['EXTNAME'] = 'FIBERMAP' hdus.append(fits.convenience.table_to_hdu(fibermap)) elif frame.fibermap is not None: fibermap = desiutil.io.encode_table( frame.fibermap) #- unicode -> bytes fibermap.meta['EXTNAME'] = 'FIBERMAP' hdus.append(fits.convenience.table_to_hdu(fibermap)) elif frame.spectrograph is not None: x.header[ 'FIBERMIN'] = 500 * frame.spectrograph # Hard-coded (as in desispec.frame) else: log.error( "You are likely writing a frame without sufficient fiber info") if frame.chi2pix is not None: hdus.append(fits.ImageHDU(frame.chi2pix.astype('f4'), name='CHI2PIX')) hdus.writeto(outfile + '.tmp', clobber=True, checksum=True) os.rename(outfile + '.tmp', outfile) return outfile
def write_spectra(outfile, spec, units=None): """ Write Spectra object to FITS file. This places the metadata into the header of the (empty) primary HDU. The first extension contains the fibermap, and then HDUs are created for the different data arrays for each band. Floating point data is converted to 32 bits before writing. Args: outfile (str): path to write spec (Spectra): the object containing the data units (str): optional string to use for the BUNIT key of the flux HDUs for each band. Returns: The absolute path to the file that was written. """ outfile = os.path.abspath(outfile) # Create the parent directory, if necessary. dir, base = os.path.split(outfile) if not os.path.exists(dir): os.makedirs(dir) # Create HDUs from the data all_hdus = fits.HDUList() # metadata goes in empty primary HDU hdr = fitsheader(spec.meta) if _desiutil_imported: add_dependencies(hdr) all_hdus.append(fits.PrimaryHDU(header=hdr)) # Next is the fibermap fmap = spec.fibermap.copy() fmap.meta["EXTNAME"] = "FIBERMAP" hdu = fits.convenience.table_to_hdu(fmap) # Add comments for fibermap columns. for i, colname in enumerate(fmap.dtype.names): if colname in fibermap_comments: key = "TTYPE{}".format(i+1) name = hdu.header[key] assert name == colname comment = fibermap_comments[name] hdu.header[key] = (name, comment) else: pass #print('Unknown comment for {}'.format(colname)) all_hdus.append(hdu) # Now append the data for all bands for band in spec.bands: hdu = fits.ImageHDU(name="{}_WAVELENGTH".format(band.upper())) hdu.header["BUNIT"] = "Angstrom" hdu.data = spec.wave[band].astype("f8") all_hdus.append(hdu) hdu = fits.ImageHDU(name="{}_FLUX".format(band.upper())) if units is None: hdu.header["BUNIT"] = "10**-17 erg/(s cm2 Angstrom)" else: hdu.header["BUNIT"] = units hdu.data = spec.flux[band].astype("f4") all_hdus.append(hdu) hdu = fits.ImageHDU(name="{}_IVAR".format(band.upper())) if units is None: hdu.header["BUNIT"] = '10**+34 (s2 cm4 Angstrom2) / erg2' else: hdu.header["BUNIT"] = ((u.Unit(units, format='fits'))**-2).to_string('fits') hdu.data = spec.ivar[band].astype("f4") all_hdus.append(hdu) if spec.mask is not None: # hdu = fits.CompImageHDU(name="{}_MASK".format(band.upper())) hdu = fits.ImageHDU(name="{}_MASK".format(band.upper())) hdu.data = spec.mask[band].astype(np.uint32) all_hdus.append(hdu) if spec.resolution_data is not None: hdu = fits.ImageHDU(name="{}_RESOLUTION".format(band.upper())) hdu.data = spec.resolution_data[band].astype("f4") all_hdus.append(hdu) if spec.extra is not None: for ex in spec.extra[band].items(): hdu = fits.ImageHDU(name="{}_{}".format(band.upper(), ex[0])) hdu.data = ex[1].astype("f4") all_hdus.append(hdu) if spec.scores is not None : scores_tbl = encode_table(spec.scores) #- unicode -> bytes scores_tbl.meta['EXTNAME'] = 'SCORES' all_hdus.append( fits.convenience.table_to_hdu(scores_tbl) ) if spec.scores_comments is not None : # add comments in header hdu=all_hdus['SCORES'] for i in range(1,999): key = 'TTYPE'+str(i) if key in hdu.header: value = hdu.header[key] if value in spec.scores_comments.keys() : hdu.header[key] = (value, spec.scores_comments[value]) all_hdus.writeto("{}.tmp".format(outfile), overwrite=True, checksum=True) os.rename("{}.tmp".format(outfile), outfile) return outfile
def write_qframe(outfile, qframe, header=None, fibermap=None, units=None): """Write a frame fits file and returns path to file written. Args: outfile: full path to output file, or tuple (night, expid, channel) qframe: desispec.qproc.QFrame object with wave, flux, ivar... Optional: header: astropy.io.fits.Header or dict to override frame.header fibermap: table to store as FIBERMAP HDU Returns: full filepath of output file that was written Note: to create a QFrame object to pass into write_qframe, qframe = QFrame(wave, flux, ivar) """ log = get_logger() outfile = makepath(outfile, 'qframe') if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(qframe.meta) add_dependencies(hdr) hdus = fits.HDUList() x = fits.PrimaryHDU(qframe.flux.astype('f4'), header=hdr) x.header['EXTNAME'] = 'FLUX' if units is not None: units = str(units) if 'BUNIT' in hdr and hdr['BUNIT'] != units: log.warning('BUNIT {bunit} != units {units}; using {units}'.format( bunit=hdr['BUNIT'], units=units)) x.header['BUNIT'] = units hdus.append(x) hdus.append(fits.ImageHDU(qframe.ivar.astype('f4'), name='IVAR')) if qframe.mask is None: qframe.mask = np.zeros(qframe.flux.shape, dtype=np.uint32) # hdus.append( fits.CompImageHDU(qframe.mask, name='MASK') ) hdus.append(fits.ImageHDU(qframe.mask, name='MASK')) if qframe.sigma is None: qframe.sigma = np.zeros(qframe.flux.shape, dtype=np.float) hdus.append(fits.ImageHDU(qframe.sigma.astype('f4'), name='YSIGMA')) hdus.append(fits.ImageHDU(qframe.wave.astype('f8'), name='WAVELENGTH')) hdus[-1].header['BUNIT'] = 'Angstrom' if fibermap is not None: fibermap = encode_table(fibermap) #- unicode -> bytes fibermap.meta['EXTNAME'] = 'FIBERMAP' hdus.append(fits.convenience.table_to_hdu(fibermap)) elif qframe.fibermap is not None: fibermap = encode_table(qframe.fibermap) #- unicode -> bytes fibermap.meta['EXTNAME'] = 'FIBERMAP' hdus.append(fits.convenience.table_to_hdu(fibermap)) elif qframe.spectrograph is not None: x.header[ 'FIBERMIN'] = 500 * qframe.spectrograph # Hard-coded (as in desispec.qproc.qframe) else: log.error( "You are likely writing a qframe without sufficient fiber info") raise ValueError('no fibermap') hdus.writeto(outfile + '.tmp', overwrite=True, checksum=True) os.rename(outfile + '.tmp', outfile) return outfile
def write_qframe(outfile, qframe, header=None, fibermap=None, units=None): """Write a frame fits file and returns path to file written. Args: outfile: full path to output file, or tuple (night, expid, channel) qframe: desispec.qproc.QFrame object with wave, flux, ivar... Optional: header: astropy.io.fits.Header or dict to override frame.header fibermap: table to store as FIBERMAP HDU Returns: full filepath of output file that was written Note: to create a QFrame object to pass into write_qframe, qframe = QFrame(wave, flux, ivar) """ log = get_logger() outfile = makepath(outfile, 'qframe') if header is not None: hdr = fitsheader(header) else: hdr = fitsheader(qframe.meta) add_dependencies(hdr) hdus = fits.HDUList() x = fits.PrimaryHDU(qframe.flux.astype('f4'), header=hdr) x.header['EXTNAME'] = 'FLUX' if units is not None: units = str(units) if 'BUNIT' in hdr and hdr['BUNIT'] != units: log.warning('BUNIT {bunit} != units {units}; using {units}'.format( bunit=hdr['BUNIT'], units=units)) x.header['BUNIT'] = units hdus.append(x) hdus.append( fits.ImageHDU(qframe.ivar.astype('f4'), name='IVAR') ) if qframe.mask is None : qframe.mask=np.zeros(qframe.flux.shape,dtype=np.uint32) # hdus.append( fits.CompImageHDU(qframe.mask, name='MASK') ) hdus.append( fits.ImageHDU(qframe.mask, name='MASK') ) if qframe.sigma is None : qframe.sigma=np.zeros(qframe.flux.shape,dtype=np.float) hdus.append( fits.ImageHDU(qframe.sigma.astype('f4'), name='YSIGMA') ) hdus.append( fits.ImageHDU(qframe.wave.astype('f8'), name='WAVELENGTH') ) hdus[-1].header['BUNIT'] = 'Angstrom' if fibermap is not None: fibermap = encode_table(fibermap) #- unicode -> bytes fibermap.meta['EXTNAME'] = 'FIBERMAP' hdus.append( fits.convenience.table_to_hdu(fibermap) ) elif qframe.fibermap is not None: fibermap = encode_table(qframe.fibermap) #- unicode -> bytes fibermap.meta['EXTNAME'] = 'FIBERMAP' hdus.append( fits.convenience.table_to_hdu(fibermap) ) elif qframe.spectrograph is not None: x.header['FIBERMIN'] = 500*qframe.spectrograph # Hard-coded (as in desispec.qproc.qframe) else: log.error("You are likely writing a qframe without sufficient fiber info") hdus.writeto(outfile+'.tmp', clobber=True, checksum=True) os.rename(outfile+'.tmp', outfile) return outfile
def write_coadd_spectra(outfile, coadd_spectra, metadata, simspecfile, fibermap=None, units=None): """ Write the output of the full brz coadded spectra to a fits file. Include the truth and metadata from fiberfile and simspecfile """ # Make parent directory if necessary dir, base = os.path.split(outfile) if not os.path.exists(dir): os.makedirs(dir) # Create HDUs from the data all_hdus = fits.HDUList() sshdu = fits.open(simspecfile) metadict = { 'NIGHT': sshdu[0].header['NIGHT'], 'EXPID': sshdu[0].header['EXPID'], 'TILEID': sshdu[0].header['TILEID'], 'HAS_SN': False } # Add other useful metadata metadict['MAG'] = metadata['MAG'] metadict['REDSHIFT'] = metadata['REDSHIFT'] metadict['OBJTYPE'] = metadata['OBJTYPE'] # metadata goes in empty primary HD hdr = fitsheader(metadict) all_hdus.append(fits.PrimaryHDU(header=hdr)) # Wavelength data hdu = fits.ImageHDU(name='WAVE') hdu.header["BUNIT"] = "Angstrom" hdu.data = coadd_spectra.wave.astype("f8") all_hdus.append(hdu) # Flux data hdu = fits.ImageHDU(name='FLUX') if units is None: hdu.header["BUNIT"] = "1e-17 erg/(s cm2 Angstrom)" else: hdu.header["BUNIT"] = units hdu.data = coadd_spectra.flux.astype("f4") all_hdus.append(hdu) # Variance data hdu = fits.ImageHDU(name="IVAR") hdu.data = coadd_spectra.ivar.astype("f4") all_hdus.append(hdu) # Mask if coadd_spectra.mask is not None: hdu = fits.CompImageHDU(name="MASK") hdu.data = coadd_spectra.mask.astype(np.uint32) all_hdus.append(hdu) # Resolution data if False: #coadd_spectra.resolution is not None: hdu = fits.ImageHDU(name="RESOLUTION") hdu.data = coadd_spectra.resolution.astype("f4") all_hdus.append(hdu) try: all_hdus.writeto("{}.tmp".format(outfile), overwrite=True, checksum=True) except TypeError: all_hdus.writeto("{}.tmp".format(outfile), clobber=True, checksum=True) os.rename("{}.tmp".format(outfile), outfile) return outfile