예제 #1
0
 def photflam(self):
     ps.setref(**self.REFS)
     sp = ps.FlatSpectrum(0, fluxunits='stmag')
     sp.convert('angstroms')
     bp = self.bandpass
     obs = ps.Observation(sp, bp, binset=sp.wave)
     return obs.effstim('flam') / obs.countrate()
예제 #2
0
 def setUp(self):
     self.sp = S.FlatSpectrum(10, fluxunits='flam')
     self.wave = S.Waveset(1000, 11000, 1000)
     self.ref = S.ArraySpectrum(wave=self.wave,
                                flux=self.sp.flux[0] *
                                N.ones(self.wave.shape),
                                fluxunits=self.sp.fluxunits)
예제 #3
0
def test_observation_binset():
    bp = S.ObsBandpass('acs,hrc,f555w')

    spec = S.FlatSpectrum(1)

    obs = S.Observation(spec, bp)

    assert (bp.binset == obs.binwave).all()
예제 #4
0
    def test_values(self):
        ref = np.array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])

        f = S.FlatSpectrum(1, 'angstrom', 'photlam')

        test = f.sample(self.wave[:10])

        self.assertEqualNumpy(test, ref)
예제 #5
0
def get_pb_zpt(pb, reference='AB', model_mag=None):
    """
	Determines a passband zeropoint for synthetic photometry, given a reference
	standard and its model magnitude in the passband

	Parameters
	----------
	pb : :py:class:`pysynphot.ArrayBandpass` or :py:class:`pysynphot.obsbandpass.ObsModeBandpass`
		The passband data.
		Must have ``dtype=[('wave', '<f8'), ('throughput', '<f8')]``
	reference : str, optional
		The name of the reference spectrophotometric standard to use to determine the passband zeropoint.
		'AB' or 'Vega' (default: 'AB')
	model_mag : float, optional
		The magnitude of the reference spectrophotometric standard in the passband.
		default = None

	Returns
	-------
	pbzp : float
		passband AB zeropoint

	Raises
	------
	RuntimeError
		If the passband and reference standard do not overlap
	ValueError
		If the reference model_mag is invalid

	See Also
	--------
	:py:func:`source_synphot.passband.synflux`
	:py:func:`source_synphot.passband.synphot`
	"""

    # setup the photometric system by defining the standard and corresponding magnitude system
    if reference.lower() not in ('vega', 'ab'):
        message = 'Do not understand mag system reference standard {}. Must be AB or Vega'.format(
            reference)
        raise RuntimeError(message)
    if reference.lower() == 'ab':
        refspec = S.FlatSpectrum(3631, fluxunits='jy')
        mag_type = 'abmag'
    else:
        refspec = S.Vega
        mag_type = 'vegamag'

    refspec.convert('flam')

    if model_mag is None:
        ob = S.Observation(refspec, pb)
        model_mag = ob.effstim(mag_type)

    synphot_mag = synphot(refspec, pb, zp=0.)
    #print(synphot_mag)
    #print(model_mag)
    outzp = model_mag - synphot_mag
    return outzp
예제 #6
0
    def test_conversion1(self):
        f = S.FlatSpectrum(1, 'angstrom', 'photlam')

        angflux = f.sample(self.wave)

        f.convert('nm')

        nmflux = f.sample(self.wave / 10.)

        self.assertEqualNumpy(nmflux, angflux)
예제 #7
0
    def test_conversion2(self):
        f = S.FlatSpectrum(1, 'angstrom', 'photlam')

        self.assertEqualNumpy(
            f.sample(self.wave)[:10], f.sample(self.wave[:10]))

        f.convert('nm')

        self.assertEqualNumpy(
            f.sample(self.wave)[:10], f.sample(self.wave[:10]))
예제 #8
0
 def setUp(self):
     self.bb = S.BlackBody(5000)
     self.em = S.GaussianSource(3300, 1, 1)
     self.flat = S.FlatSpectrum(10)
     self.pl = S.PowerLaw(5000, -2)
     self.tspec = S.ArraySpectrum(self.bb.wave,
                                  self.bb.flux,
                                  fluxunits=self.bb.fluxunits)
     self.pl.writefits('ac_pl.fits')
     self.fspec = S.FileSpectrum('ac_pl.fits')
예제 #9
0
def rudy_ic5117():
    """
    Make a simple spectrum from the line table from Rudy et al.
    """
    from astropy.table import Table as table
    import pysynphot as S
    t = table.read('rudy_table1.dat.txt', format='ascii.cds')
    
    spec = S.FlatSpectrum(6e-11*1.e-4, fluxunits='photlam')
    #spec.convert('photlam')
    for line in t:
        if line['f_Ratio'] == 'Atmosphere':
            continue
        #
        #spec += S.GaussianSource(line['Ratio']*4.95e-12, line['Wave']*1., line['Wave']*30./3.e5, fluxunits='photlam')
        if line['Wave'] == 10830:
            f = 1.35
        else:
            f = 1.
        #
        spec += S.GaussianSource(line['Ratio']*4.95e-12*f, line['Wave']*1., line['Wave']*800./3.e5, fluxunits='photlam')
    
    ok = (spec.wave > 7000) & (spec.wave < 1.7e4)
    np.savetxt('rudy_spec.dat', np.array([spec.wave[ok], spec.flux[ok]]).T, fmt='%.5e')
예제 #10
0
import numpy as np
import pysynphot as S
import pdb
from astropy.table import Table
import os
import matplotlib.pyplot as plt

pynrc.setup_logging('WARN', verbose=False)

innerGrid = np.arange(0, 1.6, 0.1)
#innerGrid = np.arange(1.5,1.6,0.1)
outerGrid = np.arange(1.6, 3.2, 0.2)

rGrid = np.hstack([innerGrid, outerGrid])

spFlat = S.FlatSpectrum(5, fluxunits='flam')

bpK = S.ObsBandpass('johnson,k')

for oneFilt, oneMask in zip(['F444W', 'F200W'], ['MASK430R', 'MASK210R']):

    satArr, sensArr = [], []
    for onePt in rGrid:
        #       print('Working on r={}'.format(onePt))
        nrc = pynrc.NIRCam(filter=oneFilt,
                           pupil='CIRCLYOT',
                           mask=oneMask,
                           wind_mode='WINDOW',
                           xpix=320,
                           ypix=320,
                           offset_r=onePt,
예제 #11
0
def get_pbmodel(pbnames, model, pbfile=None, mag_type=None, mag_zero=0.):
    """
    Converts passband names ``pbnames`` into passband models based on the
    mapping of name to ``pysynphot`` ``obsmode`` strings in ``pbfile``.

    Parameters
    ----------
    pbnames : array-like
        List of passband names to get throughput models for Each name is
        resolved by first looking in ``pbfile`` (if provided) If an entry is
        found, that entry is treated as an ``obsmode`` for pysynphot. If the
        entry cannot be treated as an ``obsmode,`` we attempt to treat as an
        ASCII file. If neither is possible, an error is raised.
    model : :py:class:`WDmodel.WDmodel.WDmodel` instance
        The DA White Dwarf SED model generator
        All the passbands are interpolated onto the wavelengths of the SED
        model.
    pbfile : str, optional
        Filename containing mapping between ``pbnames`` and ``pysynphot``
        ``obsmode`` string, as well as the standard that has 0 magnitude in the
        system (either ''Vega'' or ''AB''). The ``obsmode`` may also be the
        fullpath to a file that is readable by ``pysynphot``
    mag_type : str, optional
        One of ''vegamag'' or ''abmag''
        Used to specify the standard that has mag_zero magnitude in the passband.
        If ``magsys`` is specified in ``pbfile,`` that overrides this option.
        Must be the same for all passbands listed in ``pbname`` that do not
        have ``magsys`` specified in ``pbfile``
        If ``pbnames`` require multiple ``mag_type``, concatentate the output.
    mag_zero : float, optional
        Magnitude of the standard in the passband
        If ``magzero`` is specified in ``pbfile,`` that overrides this option.
        Must be the same for all passbands listed in ``pbname`` that do not
        have ``magzero`` specified in ``pbfile``
        If ``pbnames`` require multiple ``mag_zero``, concatentate the output.

    Returns
    -------
    out : dict
        Output passband model dictionary. Has passband name ``pb`` from ``pbnames`` as key.

    Raises
    ------
    RuntimeError
        If a bandpass cannot be loaded

    Notes
    -----
        Each item of ``out`` is a tuple with
            * ``pb`` : (:py:class:`numpy.recarray`)
              The passband transmission with zero throughput entries trimmed.
              Has ``dtype=[('wave', '<f8'), ('throughput', '<f8')]``
            * ``transmission`` : (array-like)
              The non-zero passband transmission interpolated onto overlapping model wavelengths
            * ``ind`` : (array-like)
              Indices of model wavelength that overlap with this passband
            * ``zp`` : (float)
              mag_type zeropoint of this passband
            * ``avgwave`` : (float)
              Passband average/reference wavelength

        ``pbfile`` must be readable by :py:func:`WDmodel.io.read_pbmap` and
        must return a :py:class:`numpy.recarray`
        with``dtype=[('pb', 'str'),('obsmode', 'str')]``

        If there is no entry in ``pbfile`` for a passband, then we attempt to
        use the passband name ``pb`` as ``obsmode`` string as is.

        Trims the bandpass to entries with non-zero transmission and determines
        the ``VEGAMAG/ABMAG`` zeropoint for the passband - i.e. ``zp`` that
        gives ``mag_Vega/AB=mag_zero`` in all passbands.

    See Also
    --------
    :py:func:`WDmodel.io.read_pbmap`
    :py:func:`WDmodel.passband.chop_syn_spec_pb`
    """

    # figure out the mapping from passband to observation mode
    if pbfile is None:
        pbfile = 'WDmodel_pb_obsmode_map.txt'
        pbfile = io.get_pkgfile(pbfile)
    pbdata  = io.read_pbmap(pbfile)
    pbmap   = dict(list(zip(pbdata.pb, pbdata.obsmode)))
    sysmap  = dict(list(zip(pbdata.pb, pbdata.magsys)))
    zeromap = dict(list(zip(pbdata.pb, pbdata.magzero)))

    # setup the photometric system by defining the standard and corresponding magnitude system
    if mag_type not in ('vegamag', 'abmag', None):
        message = 'Magnitude system must be one of abmag or vegamag'
        raise RuntimeError(message)

    try:
        mag_zero = float(mag_zero)
    except ValueError as e:
        message = 'Zero magnitude must be a floating point number'
        raise RuntimeError(message)

    # define the standards
    vega = S.Vega
    vega.convert('flam')
    ab   = S.FlatSpectrum(0., waveunits='angstrom', fluxunits='abmag')
    ab.convert('flam')

    # defile the magnitude sysem
    if mag_type == 'vegamag':
        mag_type= 'vegamag'
    else:
        mag_type = 'abmag'

    out = OrderedDict()

    for pb in pbnames:

        standard = None

        # load each passband
        obsmode = pbmap.get(pb, pb)
        magsys  = sysmap.get(pb, mag_type)
        synphot_mag = zeromap.get(pb, mag_zero)

        if magsys == 'vegamag':
            standard = vega
        elif magsys == 'abmag':
            standard = ab
        else:
            message = 'Unknown standard system {} for passband {}'.format(magsys, pb)
            raise RuntimeError(message)

        loadedpb = False
        # treat the passband as a obsmode string
        try:
            bp = S.ObsBandpass(obsmode)
            loadedpb = True
        except ValueError:
            message = 'Could not load pb {} as an obsmode string {}'.format(pb, obsmode)
            warnings.warn(message, RuntimeWarning)
            loadedpb = False

        # if that fails, try to load the passband interpreting obsmode as a file
        if not loadedpb:
            try:
                bandpassfile = io.get_filepath(obsmode)
                bp = S.FileBandpass(bandpassfile)
                loadedpb = True
            except Exception as e:
                message = 'Could not load passband {} from obsmode or file {}'.format(pb, obsmode)
                warnings.warn(message, RuntimeWarning)
                loadedpb = False

        if not loadedpb:
            message = 'Could not load passband {}. Giving up.'.format(pb)
            raise RuntimeError(message)

        avgwave = bp.avgwave()
        if standard.wave.min() > model._wave.min():
            message = 'Standard does not extend past the blue edge of the model'
            warnings.warn(message, RuntimeWarning)

        if standard.wave.max() < model._wave.max():
            message = 'Standard does not extend past the red edge of the model'
            warnings.warn(message, RuntimeWarning)

        # interpolate the standard onto the model wavelengths
        sinterp = interp1d(standard.wave, standard.flux, fill_value='extrapolate')
        standard_flux = sinterp(model._wave)
        standard = np.rec.fromarrays([model._wave, standard_flux], names='wave,flux')

        # cut the passband to non-zero values and interpolate onto overlapping standard wavelengths
        outpb, outzp = chop_syn_spec_pb(standard, synphot_mag, bp, model)

        # interpolate the passband onto the standard's  wavelengths
        transmission, ind = interp_passband(model._wave, outpb, model)

        # save everything we need for this passband
        out[pb] = (outpb, transmission, ind, outzp, avgwave)
    return out
예제 #12
0
 def setUp(self):
     self.comp1 = S.FileSpectrum(
         os.path.join(os.environ['PYSYN_CDBS'], 'calspec',
                      'alpha_lyr_stis_003.fits'))
     self.comp2 = S.FlatSpectrum(10)
     self.sp = self.comp1 + self.comp2
예제 #13
0
def snr_osiris_imager(tint, mag, filter, phot_sys='vegamag'):

    ##########
    # Detector Characteristics:
    ##########
    # http://www.teledyne-si.com/imaging/H4RG%20Brochure%20-%20rev3%20v2-2%20-%20OSR.pdf
    # http://proceedings.spiedigitallibrary.org/proceeding.aspx?articleid=1363315
    # Claire, personal communication (via Tuan)

    # Read noise (e- per read)
    read_noise = 5.0

    # Dark current (e- per second)
    dark_current = 0.05

    ##########
    # Throughput
    ##########
    # OSIRIS throughput
    # Keck is 77.9 m^2 (equivalent to 9.96 m circular aperture).
    # Assumed something between inscribed and circumscribed pupil cold stop.
    # Thanks to Tuan, Claire Max, and Fitz for this info.
    # Some from the OSIRIS manual.
    tp_window = 0.97
    tp_stop = 0.95
    tp_detector = 0.70
    tp_mirrors = 0.99**7

    osiris_throughput = tp_window * tp_stop * tp_mirrors * tp_detector
    ngao_throughput = 0.61
    tel_throughput = 0.80
    atm_throughput = 0.90

    # Total system throughput (spectrograph + AO system + telescope)
    throughput = osiris_throughput * ngao_throughput * tel_throughput * atm_throughput

    ##########
    # Background
    ##########
    # Used Tuan's calculations:
    # Temperatures:   Tel = 275  AO = 273
    # Emissivities:   Tel = 0.09 AO = 0.02
    # Units: mag / arcsec^2
    bkg_mag = {
        'z': 18.778,
        'y': 17.230,
        'J': 16.510,
        # 'J': 18.96,
        'H': 13.706,
        'K': 13.855,
        'Hcont': 13.607,
        'Kcont': 13.948
    }

    # Filter above the atmosphere (no telescope/instrument)
    #bandpass = synthetic.FilterNIRC2(filter)
    filterStr = filter
    if filter == 'z':
        filterStr = 'SDSS,z'
    if filter == 'y':
        filterStr = 'Stromgren,y'
    bandpass = pysynphot.ObsBandpass(filterStr)

    #star = pysynphot.Vega
    star = pysynphot.BlackBody(6000)
    star = star.renorm(mag, phot_sys, bandpass)

    # Observe the star through a filter
    star_in_filt = pysynphot.observation.Observation(star,
                                                     bandpass,
                                                     binset=bandpass.wave)

    # Integrate over the filter
    star_flux = star_in_filt.integrate(
        fluxunits='photlam')  # photons / s / cm^2
    print 'star_flux 1 = ', star_flux, ' photons s^-1 cm^-2'

    # Convert to observed flux on Keck primary mirror
    keck_area = 77.9 * 100.0**2  # cm^2
    star_flux *= keck_area  # photons / s
    print 'star_flux 2 = ', star_flux, ' photons s^-1'

    # Apply througput of atmosphere, telescope, AO, instrument.
    # This throughput already includes a quantum efficienciy correction.
    star_flux *= throughput  # e- / s
    print 'star_flux 3 = ', star_flux, ' e- s^-1'

    # Do the same for the background
    bkg = pysynphot.FlatSpectrum(1, waveunits='angstrom', fluxunits='flam')
    bkg = bkg.renorm(bkg_mag[filter], phot_sys, bandpass)
    bkg_in_filt = pysynphot.observation.Observation(bkg,
                                                    bandpass,
                                                    binset=bandpass.wave)
    bkg_flux_dens = bkg_in_filt.integrate(
        fluxunits='photlam')  # photons / s / cm^2 / arcsec^2
    bkg_flux_dens *= keck_area * throughput  # e- / s / arcsec^2

    # Aperture information
    # technically there should be an aperture correction on the star as well.
    # In the NIRC2 calculator, they just multiply by the Strehl.
    pix_scale = 0.01  # arcsec
    aper_radius = 0.1  # arcsec
    aper_area = math.pi * aper_radius**2  # arcsec^2
    npix = aper_area / pix_scale**2
    print 'npix = ', npix

    # Calculate signal-to-noise in the specified integration time.
    signal = star_flux * tint
    noise_variance = star_flux * tint
    noise_variance += bkg_flux_dens * tint * aper_area
    noise_variance += (read_noise**2) * npix
    noise_variance += dark_current * tint * npix
    noise = math.sqrt(noise_variance)

    snr = signal / noise

    print 'signal = ', signal
    print 'noise = ', noise
    print 'snr = ', snr

    return star_in_filt
예제 #14
0
 def setUp(self):
     self.bright = S.FlatSpectrum(18.0, fluxunits='abmag')
     self.faint = S.FlatSpectrum(21.0, fluxunits='abmag')
     self.delta = 3
예제 #15
0
파일: model.py 프로젝트: gbrammer/wfc3
    'F105W': 10551.046906405772,
    'F110W': 11534.45855553774,
    'F125W': 12486.059785775655,
    'F140W': 13922.907350356367,
    'F160W': 15369.175708965562,
    'F435W': 4328.256914042873,
    'F606W': 5921.658489236346,
    'F775W': 7693.297933335407,
    'F814W': 8058.784799323767,
    'VISTAH': 1.6433e+04
}

if False:
    import pysynphot as S
    n = 1.e-20
    spec = S.FlatSpectrum(n, fluxunits='flam')
    photflam = {}
    photplam = {}
    for filter in ['F098M', 'F105W', 'F110W', 'F125W', 'F140W', 'F160W']:
        bp = S.ObsBandpass('wfc3,ir,%s' % (filter.lower()))
        photplam[filter] = bp.pivot()
        obs = S.Observation(spec, bp)
        photflam[filter] = n / obs.countrate()

    #
    for filter in ['F435W', 'F606W', 'F775W', 'F814W']:
        bp = S.ObsBandpass('acs,wfc1,%s' % (filter.lower()))
        photplam[filter] = bp.pivot()
        obs = S.Observation(spec, bp)
        photflam[filter] = n / obs.countrate()
예제 #16
0
 def setUp(self):
     sp = S.FlatSpectrum(1, fluxunits='counts')
     bp = S.Box(5000, 100)
     binset = S.Waveset(1000, 10000, 1)
     self.obs = S.Observation(sp, bp, binset=binset)
     self.obs.convert('counts')
예제 #17
0
def read_source(sourcespec):
    """
    Read a spectrum

    Parameters
    ----------
    sourcespec : str
        Source spectrum specification string. Acceptable options are:
         * BB<Temperature>
         * PL<Reference Wave Angstrom>_<PL Index>
         * Flat<AB magnitude>
         * ckmod<Temperature>_<logZ>_<logg>

    Returns
    -------
    source : :py:class:`pysynphot.spectrum.ArraySourceSpectrum`
        The spectrum data.
        Has ``dtype=[('wave', '<f8'), ('flux', '<f8')]``

    Raises
    ------
    ValueError
        If attempting to use this routine to load a file, or if source spectrum
        specification string is invalid

    Notes
    -----
       The source spectrum specification string parsing is basic. Strings are
       checked to see if they start with an acceptable prefix, and then split.
       The individual constituents are converted to float, and passed to
       pysynphot. There is no checking of the values, only that they can be
       properly typecast into float. Making sure the value is accepted is left
       to the user.

    """
    if os.path.exists(sourcespec):
        message = 'File spectrum parsing is complex and requires pre-processing. Use source_synphot.source routines'
        raise ValueError(message)
    else:
        # assume sourcespec is a string and parse it, trying to interpret as:
        # simple blackbody spectrum
        if sourcespec.startswith('BB'):
            temp = sourcespec.lstrip('BB')
            try:
                temp = float(temp)
            except (TypeError, ValueError) as e:
                message = 'Source temperature {} cannot be interpreted as a float'.format(sourcespec)
                raise ValueError(message)
            bb = S.Blackbody(temp)
            bb.convert('flam')
            spec = {'wave':bb.wave, 'flux':bb.flux}

        # power-law spectrum
        elif sourcespec.startswith('PL'):
            refwave, plindex = sourcespec.lstrip('PL').split('_')
            try:
                refwave = float(refwave)
            except (TypeError, ValueError) as e:
                message = 'Reference wavelength {} cannot be interpreted as a float'.format(sourcespec)
                raise ValueError(message)
            try:
                plindex = float(plindex)
            except (TypeError, ValueError) as e:
                message = 'Power law index {} cannot be interpreted as a float'.format(sourcespec)
                raise ValueError(message)
            pl = S.PowerLaw(refwave, plindex)
            pl.convert('flam')
            spec = {'wave':pl.wave, 'flux':pl.flux}

        # flat spectrum (in f_lam, not f_nu) normalized to some ABmag
        elif sourcespec.startswith('Flat'):
            abmag = sourcespec.replace('Flat','')
            try:
                abmag = float(abmag)
            except (TypeError, ValueError) as e:
                message = 'AB mag {} cannot be interpreted as a float'.format(sourcespec)
                raise ValueError(message)
            flat = S.FlatSpectrum(abmag, fluxunits='abmag')
            flat.convert('flam')
            spec = {'wave':flat.wave, 'flux':flat.flux}

        # a Castelli-Kurucz model
        elif sourcespec.startswith('ckmod'):
            teff, logZ, logg = sourcespec.replace('ckmod','').split('_')
            try:
                teff = float(teff)
            except (TypeError, ValueError) as e:
                message = 'Source temperature {} cannot be interpreted as a float'.format(sourcespec)
                raise ValueError(message)
            try:
                logZ = float(logZ)
            except (TypeError, ValueError) as e:
                message = 'Abundance {} cannot be interpreted as a float'.format(sourcespec)
                raise ValueError(message)
            try:
                logg = float(logg)
            except (TypeError, ValueError) as e:
                message = 'Surface gravity {} cannot be interpreted as a float'.format(sourcespec)
                raise ValueError(message)
            ckmod = S.Icat('ck04models',teff, logZ,logg)
            ckmod.convert('flam')
            spec = {'wave':ckmod.wave, 'flux':ckmod.flux}

        # else give up
        else:
            message = 'Source spectrum {} cannot be parsed as input file or pre-defined type (BB, PL, Flat, ckmod)'.format(sourcespec)
            raise ValueError(message)
    spec = S.ArraySpectrum(spec['wave'], spec['flux'], name=sourcespec)
    return spec
예제 #18
0
파일: voronoi.py 프로젝트: gbrammer/voronoi
def apply_binning(tab_file, seg_file, mask_file, obj_name):
    
    """
    Function to bin images according to the input "seg_file", obtained with Voronoi_Binning
    
    Input for this function is the output from the Voronoi_Binning function.
    
    """
    
    import glob
    import astropy.units.astrophys as u
    import numpy as np
    import astropy.io.fits as pyfits
    from grizli import utils
    import pysynphot as S
    
    files = glob.glob('*{0}*fits.gz'.format(obj_name))
    files.sort()
    res = {}
    master_table = tab_file
    bandpasses = {}
    h = {}
    
    for file in files:
        im = pyfits.open(file)
        filt = utils.get_hst_filter(im[0].header)
        for ext in [0,1]:
            if 'PHOTMODE' in im[ext].header:
                bandpasses[filt.lower()] = S.ObsBandpass(im[ext].header['PHOTMODE'].replace(' ',','))
                break    
        flat_flam = S.FlatSpectrum(1., fluxunits='flam')
        obs = S.Observation(flat_flam, bandpasses[filt.lower()])
        my_photflam = 1/obs.countrate()
        flat_ujy = S.FlatSpectrum(1, fluxunits='ujy')
        obs = S.Observation(flat_ujy, bandpasses[filt.lower()])
        my_photfnu = 1/obs.countrate()
        h['{0}_photfnu'.format(filt.lower())] = my_photfnu
        h['{0}_photflam'.format(filt.lower())] = my_photflam
    
    for file in files:
        im = pyfits.open(file)
        f = utils.get_hst_filter(im[0].header).lower()
        im2mujy =  h['{0}_photfnu'.format(f)]
        im2flam =  h['{0}_photflam'.format(f)]
        print(f,im2mujy,im2flam)
        res[f],data_tab = bin_image(im, tab_file, seg_file, mask_file)
        
        primary_extn = pyfits.PrimaryHDU()
        sci_extn = pyfits.ImageHDU(data=res[f]['image_flux'].astype(np.float32),name='SCI')
        err_extn = pyfits.ImageHDU(data=res[f]['image_err'].astype(np.float32),name='ERR')
        hdul = pyfits.HDUList([primary_extn, sci_extn, err_extn])
        for ext in [0,1]:
            for k in im[ext].header:
                if k not in hdul[ext].header:
                    if k in ['COMMENT','HISTORY','']:
                        continue
                    hdul[ext].header[k] = im[ext].header[k]
        hdul[1].header['IM2FLAM'] = (im2flam, 'Convert images to flambda cgs')
        hdul[1].header['IM2MUJY'] = (im2mujy, 'Convert images to fnu, microJy')
        hdul.writeto('binned_{0}_{1}_image.fits'.format(obj_name,f), output_verify='fix',overwrite=True)
        
        # bin_flux and bin_error of each filter to append to the master table       
        master_table['{0}_flux'.format(f)] = res[f]['bin_flux']*im2mujy
        master_table['{0}_flux'.format(f)].unit = u.Jy*1e-6
        master_table['{0}_err'.format(f)] = res[f]['bin_err']*im2mujy
        master_table['{0}_err'.format(f)].unit = u.Jy*1e-6

    # master_table.remove_columns(['flux','err','area'])
    master_table.write('binned_{0}_master_table.fits'.format(obj_name), overwrite=True)
    
    return master_table
예제 #19
0
def subtract_continuum(line='f673n',
                       cont='f814w',
                       target='galaxy',
                       file_name='galaxy*.fits',
                       line_name='ha',
                       z=0.02,
                       plot=False):
    """
    Function for subtracting the continuum in a line emission image

    INPUTS:
         line: Filter into which the emission line falls.
         cont: Filter within which the emission line and broader continuum are contained.
       target: The name of the target, to be used in the output files.
    file_name: General form of the file names that contain the line and continuum images.
    line_name: State 'ha' or 'pab' to subtract Balmer-alpha or Paschen-beta respectively.
            z: Redshift of the target object.
       
    KEYWORDS:
         PLOT: Set this keyword to produce a plot of the two-dimensional
               continuum subtracted image.   
    OUTPUTS:
         Fits file with the continuum subtracted line emission image.

    """

    import pysynphot as S
    import numpy as np
    import glob
    from grizli import utils
    import astropy.io.fits as pyfits
    import matplotlib.pyplot as plt

    # restframe wavelength of the emission lines to subtract
    wave_pab = 1.2822e4
    wave_ha = 6562.8

    print('Target =', target)
    files = glob.glob(file_name)
    files.sort()
    images = {}
    headers = {}
    bandpasses = {}

    for file in files:
        im = pyfits.open(file)
        filt = utils.get_hst_filter(im[0].header).lower()
        for ext in [0, 1]:
            if 'PHOTMODE' in im[ext].header:
                photflam = im[ext].header['PHOTFLAM']
                headers[filt.lower()] = im[ext].header
                bandpasses[filt.lower()] = S.ObsBandpass(
                    im[ext].header['PHOTMODE'].replace(' ', ','))
                break

        flat_flam = S.FlatSpectrum(1., fluxunits='flam')
        obs = S.Observation(flat_flam, bandpasses[filt.lower()])
        my_photflam = 1 / obs.countrate()
        flat_ujy = S.FlatSpectrum(1, fluxunits='ujy')
        obs = S.Observation(flat_ujy, bandpasses[filt.lower()])
        my_photfnu = 1 / obs.countrate()
        images[filt.lower()] = [im['SCI'].data, im['ERR'].data]

    # Use PySynphot to compute flux calibration factors

    if line_name == 'pab':
        # Pa-beta
        cont_filter, line_filter, line_wave, name = cont, line, wave_pab, 'pab'
    elif line_name == 'ha':
        # H-alpha
        cont_filter, line_filter, line_wave, name = cont, line, wave_ha, 'ha'

    ################
    # Continuum - flat spectrum
    cont = S.FlatSpectrum(1.e-19, fluxunits='flam')

    ###############
    # Continuum - slope spectrum
    cont_wave = np.arange(1000, 2.e4)

    slope = 0  # flat
    slope = 1  # red slope, increasing toward longer wavelengths
    cont_flux = (cont_wave / 1.e4)**slope
    cont = S.ArraySpectrum(cont_wave, cont_flux, fluxunits='flam')

    ################
    # Continuum, galaxy model
    templ = utils.load_templates(full_line_list=[],
                                 line_complexes=False,
                                 alf_template=True)['alf_SSP.dat']
    cont = S.ArraySpectrum(templ.wave * (1 + z), templ.flux, fluxunits='flam')

    # Gaussian line model
    ref_flux = 1.e-17
    line_model = S.GaussianSource(ref_flux,
                                  line_wave * (1 + z),
                                  10,
                                  waveunits='angstrom',
                                  fluxunits='flam')

    cont_contin_countrate = S.Observation(cont,
                                          bandpasses[cont_filter]).countrate()
    line_contin_countrate = S.Observation(cont,
                                          bandpasses[line_filter]).countrate()
    line_emline_countrate = S.Observation(line_model,
                                          bandpasses[line_filter]).countrate()

    # Continuum-subtracted, flux-calibrated
    line_calib = (
        images[line_filter][0] -
        images[cont_filter][0] * line_contin_countrate / cont_contin_countrate)
    line_calib /= line_emline_countrate

    # Propagated error of the subtraction
    err_sub = np.sqrt((images[line_filter][1]**2) +
                      (images[cont_filter][1] * line_contin_countrate /
                       cont_contin_countrate)**2)
    err_sub /= line_emline_countrate

    if plot:
        print("Continuum subtracted image")
        plt.figure()
        plt.imshow(line_calib, vmin=-0.5, vmax=0.5)
        plt.colorbar()

    primary_extn = pyfits.PrimaryHDU()
    sci_extn = pyfits.ImageHDU(data=line_calib, name='SCI')
    err_extn = pyfits.ImageHDU(data=err_sub, name='ERR')
    hdul = pyfits.HDUList([primary_extn, sci_extn, err_extn])
    hdul.writeto('sub_{0}_{1}.fits'.format(line_name, target),
                 output_verify='fix',
                 overwrite=True)

    print(line_name, ' Continuum Subtracted')
예제 #20
0
def specFromSpectralType(sptype, return_list=False, catalog=None):
    """Get Pysynphot Spectrum object from a user-friendly spectral type string.

    Given a spectral type such as 'A0IV' or 'G2V', this uses a fixed lookup table
    to determine an appropriate spectral model from Castelli & Kurucz 2004 or 
    the Phoenix model grids. Depends on pysynphot and CDBS. This is just a
    convenient access function.

    Parameters
    -----------
    catalog: str
        'ck04' for Castelli & Kurucz 2004, 'phoenix' for Phoenix models.
        If not set explicitly, the code will check if the phoenix models are
        present inside the $PYSYN_CDBS directory. If so, those are the default;
        otherwise, it's CK04.

    """
    import pysynphot


    if catalog is None: 
        import os
        cdbs = os.getenv('PYSYN_CDBS')
        if os.path.exists( os.path.join(os.getenv('PYSYN_CDBS'), 'grid', 'phoenix')):
            catalog='phoenix'
        elif os.path.exists( os.path.join(os.getenv('PYSYN_CDBS'), 'grid', 'ck04models')):
            catalog='ck04'
        else:
            raise IOError("Could not find either phoenix or ck04models subdirectories of $PYSYN_CDBS/grid")

    if catalog.lower()  =='ck04':
        catname='ck04models'

        # Recommended lookup table into the CK04 models (from 
        # the documentation of that catalog?)
        lookuptable = {
            "O3V":   (50000, 0.0, 5.0),
            "O5V":   (45000, 0.0, 5.0),
            "O6V":   (40000, 0.0, 4.5),
            "O8V":   (35000, 0.0, 4.0),
            "O5I":   (40000, 0.0, 4.5),
            "O6I":   (40000, 0.0, 4.5),
            "O8I":   (34000, 0.0, 4.0),
            "B0V":   (30000, 0.0, 4.0),
            "B3V":   (19000, 0.0, 4.0),
            "B5V":   (15000, 0.0, 4.0),
            "B8V":   (12000, 0.0, 4.0),
            "B0III": (29000, 0.0, 3.5),
            "B5III": (15000, 0.0, 3.5),
            "B0I":   (26000, 0.0, 3.0),
            "B5I":   (14000, 0.0, 2.5),
            "A0V":   (9500, 0.0, 4.0),
            "A5V":   (8250, 0.0, 4.5),
            "A0I":   (9750, 0.0, 2.0),
            "A5I":   (8500, 0.0, 2.0),
            "F0V":   (7250, 0.0, 4.5),
            "F5V":   (6500, 0.0, 4.5),
            "F0I":   (7750, 0.0, 2.0),
            "F5I":   (7000, 0.0, 1.5),
            "G0V":   (6000, 0.0, 4.5),
            "G5V":   (5750, 0.0, 4.5),
            "G0III": (5750, 0.0, 3.0),
            "G5III": (5250, 0.0, 2.5),
            "G0I":   (5500, 0.0, 1.5),
            "G5I":   (4750, 0.0, 1.0),
            "K0V":   (5250, 0.0, 4.5),
            "K5V":   (4250, 0.0, 4.5),
            "K0III": (4750, 0.0, 2.0),
            "K5III": (4000, 0.0, 1.5),
            "K0I":   (4500, 0.0, 1.0),
            "K5I":   (3750, 0.0, 0.5),
            "M0V":   (3750, 0.0, 4.5),
            "M2V":   (3500, 0.0, 4.5),
            "M5V":   (3500, 0.0, 5.0),
            "M0III": (3750, 0.0, 1.5),
            "M0I":   (3750, 0.0, 0.0),
            "M2I":   (3500, 0.0, 0.0)}
    elif catalog.lower() =='phoenix':
        catname='phoenix'
        # lookup table used in JWST ETCs
        lookuptable = {
            "O3V":   (45000, 0.0, 4.0),
            "O5V":   (41000, 0.0, 4.5),
            "O7V":   (37000, 0.0, 4.0),
            "O9V":   (33000, 0.0, 4.0),
            "B0V":   (30000, 0.0, 4.0),
            "B1V":   (25000, 0.0, 4.0),
            "B3V":   (19000, 0.0, 4.0),
            "B5V":   (15000, 0.0, 4.0),
            "B8V":   (12000, 0.0, 4.0),
            "A0V":   (9500, 0.0, 4.0),
            "A1V":   (9250, 0.0, 4.0),
            "A3V":   (8250, 0.0, 4.0),
            "A5V":   (8250, 0.0, 4.0),
            "F0V":   (7250, 0.0, 4.0),
            "F2V":   (7000, 0.0, 4.0),
            "F5V":   (6500, 0.0, 4.0),
            "F8V":   (6250, 0.0, 4.5),
            "G0V":   (6000, 0.0, 4.5),
            "G2V":   (5750, 0.0, 4.5),
            "G5V":   (5750, 0.0, 4.5),
            "G8V":   (5500, 0.0, 4.5),
            "K0V":   (5250, 0.0, 4.5),
            "K2V":   (4750, 0.0, 4.5),
            "K5V":   (4250, 0.0, 4.5),
            "K7V":   (4000, 0.0, 4.5),
            "M0V":   (3750, 0.0, 4.5),
            "M2V":   (3500, 0.0, 4.5),
            "M5V":   (3500, 0.0, 5.0),
            "B0III": (29000, 0.0, 3.5),
            "B5III": (15000, 0.0, 3.5),
            "G0III": (5750, 0.0, 3.0),
            "G5III": (5250, 0.0, 2.5),
            "K0III": (4750, 0.0, 2.0),
            "K5III": (4000, 0.0, 1.5),
            "M0III": (3750, 0.0, 1.5),
            "O6I":   (39000, 0.0, 4.5),
            "O8I":   (34000, 0.0, 4.0),
            "B0I":   (26000, 0.0, 3.0),
            "B5I":   (14000, 0.0, 2.5),
            "A0I":   (9750, 0.0, 2.0),
            "A5I":   (8500, 0.0, 2.0),
            "F0I":   (7750, 0.0, 2.0),
            "F5I":   (7000, 0.0, 1.5),
            "G0I":   (5500, 0.0, 1.5),
            "G5I":   (4750, 0.0, 1.0),
            "K0I":   (4500, 0.0, 1.0),
            "K5I":   (3750, 0.0, 0.5),
            "M0I":   (3750, 0.0, 0.0),
            "M2I":   (3500, 0.0, 0.0)}

    if return_list:
        sptype_list = lookuptable.keys()
        def sort_sptype(typestr):
            letter = typestr[0]
            lettervals = {'O':0, 'B': 10, 'A': 20,'F': 30, 'G':40, 'K': 50, 'M':60}
            value = lettervals[letter]*1.0
            value += int(typestr[1])
            if "III" in typestr: value += .3
            elif "I" in typestr: value += .1
            elif "V" in typestr: value += .5
            return value
        sptype_list.sort(key=sort_sptype)
        sptype_list.insert(0,"Flat spectrum in F_nu")
        sptype_list.insert(0,"Flat spectrum in F_lambda")
        # add a variety of spectral type slopes, per request from Dean Hines
        for slope in [-3, -2, -1.5, -1, -0.75, -0.5, 0.5, 0.75, 1.0, 1.5, 2, 3]:
            sptype_list.insert(0,"Power law F_nu ~ nu^(%s)" % str(slope))
        #sptype_list.insert(0,"Power law F_nu ~ nu^(-0.75)")
        #sptype_list.insert(0,"Power law F_nu ~ nu^(-1.0)")
        #sptype_list.insert(0,"Power law F_nu ~ nu^(-1.5)")
        #sptype_list.insert(0,"Power law F_nu ~ nu^(-2.0)")
        return sptype_list


    if "Flat" in sptype:
        if sptype == "Flat spectrum in F_nu":    spec = pysynphot.FlatSpectrum( 1, fluxunits = 'fnu')
        elif sptype == "Flat spectrum in F_lambda":  spec= pysynphot.FlatSpectrum( 1, fluxunits = 'flam')
        spec.convert('flam')
        return spec*(1./spec.flux.mean())
    if 'Power law' in sptype:
        import re
        ans = re.search('\((.*)\)', sptype)
        if ans is None: raise ValueError("Invalid power law specification cannot be parsed to get exponent")
        exponent = float(ans.groups(0)[0])
        # note that Pysynphot's PowerLaw class implements a power law in terms of lambda, not nu.
        # but since nu = clight/lambda, it's just a matter of swapping the sign on the exponent. 

        spec = pysynphot.PowerLaw(1, (-1)*exponent, fluxunits='fnu')
        spec.convert('flam')
        spec *= (1./spec.flux.mean())
        spec.name = sptype
        return spec
    else: 
        keys = lookuptable[sptype]
        try:
            return pysynphot.Icat(catname,keys[0], keys[1], keys[2])
        except:
            errmsg = "Could not find a match in catalog {0} for key {1}. Check that is a valid name in the lookup table, and/or that pysynphot is installed properly.".format(catname, sptype)
            _log.critical(errmsg)
            raise LookupError(errmsg)
예제 #21
0
파일: psi.py 프로젝트: abgibbs/psisim
    def get_instrument_background(self, wvs, solidangle):
        '''
        Return the instrument background. 

        Let's use the background limits from Skemer et al. 2018. 


        Inputs: 
        wvs - a list of wavelengths in microns

        Outputs: 
        backgrounds - a list of background values at a given wavelength. Unit TBD
        '''

        # First we'll get the point source limit in a 1-hour integration, basedd on the
        # numbers from Skemer et al. 2018. These numbers likely include both instrument
        # background and sky background numbers. For now we're assuming that it's all due
        # to instrument background until we hear something else.

        if self.current_R <= 10:
            # Assume Imaging
            point_source_limit = {
                'K': 27.4,
                'L': 21.3,
                'M': 18.7
            }.get(self.current_filter,
                  18.7)  #Assume M-band if something goes wrong
        elif (self.current_R > 10) & (self.current_R <= 1000):
            # Low resolution spectroscopy
            point_source_limit = {
                'K': 25.4,
                'L': 19.5,
                'M': 16.7
            }.get(self.current_filter,
                  16.7)  #Assume M-band if something goes wrong
        elif (self.current_R > 1000) & (self.current_R <= 20000):
            # Medium resolution spectrocopy
            point_source_limit = {
                'K': 23.6,
                'L': 17.7,
                'M': 14.9
            }.get(self.current_filter,
                  14.9)  #Assume M-band if something goes wrong
        elif (self.current_R > 20000):
            #High resolution spectroscopy
            point_source_limit = {
                'K': 22.0,
                'L': 16.1,
                'M': 13.3
            }.get(self.current_filter,
                  14.9)  #Assume M-band if something goes wrong

        #Get the central wavelength (in microns) based on Keck filters
        cntr_wv = {
            'K': 2.196,
            'L': 3.776,
            'M': 4.670
        }.get(self.current_filter, 4.670)
        #Now we'll use pysynphot to estimate the number of photons at the given magnitude
        ps.Vega.convert("photlam")
        sp = ps.FlatSpectrum(point_source_limit, fluxunits='vegamag')

        sp.convert('photlam')  #Convert to photons/s/cm^2/Angstrom
        limit = sp(
            np.array([cntr_wv]) * 1e4
        )  #Get the spectrum at the center wavelength (convert cntr_wv to angstrom)

        if isinstance(wvs, float):
            return limit[0]
        else:
            return np.repeat(limit, len(wvs))
예제 #22
0
 def testcompspec(self):
     self.sp = S.BlackBody(5500) + S.FlatSpectrum(1)
     tst = self.sp(3000)
     assert True
예제 #23
0
 def setUp(self):
     self.sp = S.FlatSpectrum(1)
     self.bp = S.ObsBandpass('johnson,v')
예제 #24
0
 def testsum(self):
     sp2 = self.sp + S.FlatSpectrum(1)
     self.assertTrue('FakeWarn' in sp2.warnings)
예제 #25
0
 def setUp(self):
     self.sp = S.FlatSpectrum(10)
예제 #26
0
파일: bg_ISR.py 프로젝트: gbrammer/wfc3
def etc_spectra():
    """
    Make actual spectra for the ETC for the different He bg cases
    """
    import pysynphot as S

    fl0 = 1.e-17
    fwhm = 2  # Angstroms
    heline = S.GaussianSource(fl0, 1.083e4, fwhm, fluxunits='flam')

    continuum = S.FlatSpectrum(60, fluxunits='STMag')
    model_spec = continuum + heline
    model_spec.convert('flam')

    bp = S.ObsBandpass('wfc3,ir,f105w')

    flux = {'50': 0.1, '75': 0.5, '95': 1.5}

    obs = S.Observation(heline, bp)
    for key in flux.keys():
        fl = fl0 * flux[key] / obs.countrate()
        print fl

    fl = fl0 * 1.0 / obs.countrate()

    #### Normalize to "per arcsec"
    fl /= 0.1211 * 0.1355

    heline = S.GaussianSource(fl, 1.083e4, fwhm, fluxunits='flam')
    obs = S.Observation(heline, bp)

    import astropy.io.fits as pyfits

    h = pyfits.Header()
    h['CONTACT'] = ('G. Brammer', 'Person to contact in case of questions')
    h['DESCRIPT'] = ('Airglow line at 10830 A')
    h['MAPKEY'] = ('el10830a')
    h['FILE_TYP'] = ('Airglow line at 10830 Angstroms')
    h['SYSTEMS'] = ('PYETC')
    h['PSYNEXPR'] = ('GaussianSource(%.3e,1.083e4,%.1f,fluxunits="flam")' %
                     (fl, fwhm))
    #h.add_history("This file is a spectrum produced by PySynphot to model the He I 10830 airglow line as a Gaussian with FWHM = 2A. The spectrum is normalized to produce a background countrate of 1 e/s/pix in the WFC3/IR F105W filter.")

    heline.writefits('el10830a_002.fits', clobber=True)
    im = pyfits.open('el10830a_002.fits')
    for card in h.cards:
        im[0].header[card[0]] = (card[1], card[2])
    #
    im[0].header.add_history(
        "This file is a spectrum produced by PySynphot to model the He I 10830 airglow line as a Gaussian with FWHM = 2A.  The spectrum is normalized to produce a background countrate of 1 e-/s/pix in the WFC3/IR F105W filter."
    )
    im[0].header.add_history("")
    im[0].header.add_history(
        "The 50, 75, and 95 percentile fluxes of the line background observed in archival F105W observations are 0.1, 0.5, and 1.5 e/s/pix."
    )
    im[0].header.add_history("")
    im[0].header.add_history(
        "For more information on the He 10830 component to the IR background, see WFC3/ISR 2014-03: Time-varying Excess Earth-glow Backgrounds in the WFC3/IR Channel (Brammer et al.)."
    )

    im.writeto('el10830a_002.fits', clobber=True)

    model_50 = model_spec.renorm(0.1, 'Counts', bp)
    model_75 = model_spec.renorm(0.5, 'Counts', bp)
    model_95 = model_spec.renorm(1.5, 'Counts', bp)

    #### Demo figure
    plt.plot(model_50.wave - 10830,
             model_50.flux / 1.e-17,
             label='F105W 0.1 e/s, 50%')
    plt.plot(model_75.wave - 10830,
             model_75.flux / 1.e-17,
             label='F105W 0.5 e/s, 75%')
    plt.plot(model_95.wave - 10830,
             model_95.flux / 1.e-17,
             label='F105W 1.5 e/s, 95%')
    plt.xlim(-20, 20)
    plt.ylabel(
        r'$f_\lambda$ ($10^{-17}\,\mathrm{erg}\,\mathrm{s}^{-1}\,\mathrm{cm}^{-2}\,\AA^{-1})$'
    )
    plt.xlabel(r'$\lambda - 10830\,\AA$')
    plt.legend(loc='best', fontsize=12)
    plt.savefig('He10830_ETC_spec.png')

    header = """# wavelength flux
# Units: (angstroms)  (erg/s/cm2/A)
# He I 10830 A background component: 50%, 0.1 e/s in F105W
# Created: G. Brammer, 2014-09-18
# (made with PySynphot)
"""
    fp = open('HeI_background_50.dat', 'w')
    fp.write(header)
    np.savetxt(fp, np.array([model_50.wave, model_50.flux]).T, fmt='%.6e')
    fp.close()

    #
    header = """# wavelength flux
# Units: (angstroms)  (erg/s/cm2/A)
# He I 10830 A background component: 75%, 0.5 e/s in F105W
# Created: G. Brammer, 2014-09-18
# (made with PySynphot)
"""
    fp = open('HeI_background_75.dat', 'w')
    fp.write(header)
    np.savetxt(fp, np.array([model_75.wave, model_75.flux]).T, fmt='%.6e')
    fp.close()

    #
    header = """# wavelength flux
# Units: (angstroms)  (erg/s/cm2/A)
# He I 10830 A background component: 95%, 1.5 e/s in F105W
# Created: G. Brammer, 2014-09-18
# (made with PySynphot)
"""
    fp = open('HeI_background_95.dat', 'w')
    fp.write(header)
    np.savetxt(fp, np.array([model_95.wave, model_95.flux]).T, fmt='%.6e')
    fp.close()
예제 #27
0
 def setUp(self):
     self.uspec = S.FlatSpectrum(1.0, fluxunits='flam')
예제 #28
0
    def setUp(self):
        bp = S.ObsBandpass('acs,hrc,f555w')
        spec = S.FlatSpectrum(1)

        self.obs = S.Observation(spec, bp)
예제 #29
0
 def setUp(self):
     self.sp = S.FlatSpectrum(1)
     self.z = 2.5
     self.wavecheck = N.array([550])
예제 #30
0
}

default_spectra = {'specs': {}, 'descs': {}}

for (specid, spec) in specs.items():
    default_spectra['descs'][specid] = spec['desc']
    fesc = 'fesc' in spec['file']
    fits = spec['file'][-1].endswith('fits')
    if fits:
        default_spectra['specs'][specid] = load_pysfits(spec)
    elif fesc:
        default_spectra['specs'][specid] = load_fesc(spec)
    else:
        default_spectra['specs'][specid] = load_txtfile(spec)

flatsp = pys.FlatSpectrum(30.0, fluxunits='abmag')
flatsp = flatsp.renorm(30.0, 'abmag', pys.ObsBandpass('johnson,v'))
flatsp.convert('abmag')
flatsp.convert('nm')
default_spectra['specs']['fab'] = pre_encode(flatsp)
default_spectra['descs']['fab'] = 'Flat (AB)'

flamsp = pys.FlatSpectrum(30.0, fluxunits='flam')
flamsp = flamsp.renorm(30.0, 'abmag', pys.ObsBandpass('galex,fuv'))
flamsp.convert('abmag')
flamsp.convert('nm')
default_spectra['specs']['flam'] = pre_encode(flamsp)
default_spectra['descs']['flam'] = 'Flat in F_lambda'

bb = pys.BlackBody(5000)
bb.convert('abmag')