示例#1
0
def test_box_5000_1():
    sp1 = spparser.parse_spec('box(5000, 1)')
    _single_functioncall(sp1, SpectralElement, Box1D, 'box(5000.0,1.0)',
                         ans_z=None)

    sp2 = SpectralElement(Box1D, amplitude=1, x_0=5000 * u.AA, width=1 * u.AA)
    _compare_spectra(sp1, sp2)
示例#2
0
def test_remote_band_v():
    sp1 = spparser.parse_spec('band(v)')
    _single_functioncall(
        sp1, spectrum.ObservationSpectralElement, Empirical1D, 'band(v)',
        ans_z=None)

    sp2 = SpectralElement.from_filter('johnson_v')
    _compare_spectra(sp1, sp2)
示例#3
0
def test_rn_bb_box_abmag():
    sp1 = spparser.parse_spec('rn(bb(5000), box(5000, 10), 17, abmag)')
    _single_functioncall(sp1, SourceSpectrum, None,
                         'rn(bb(5000.0),box(5000.0,10.0),17.0,abmag)')

    bb = SourceSpectrum(BlackBodyNorm1D, temperature=5000 * u.K)
    box = SpectralElement(Box1D, amplitude=1, x_0=5000 * u.AA, width=10 * u.AA)
    sp2 = bb.normalize(17 * u.ABmag, band=box)
    _compare_spectra(sp1, sp2)
示例#4
0
 def get(cls, filter_name):
     '''
     Return synphot.SpectralElement of the specified filter
     The list of available filter is accessible via Filters.names()
     '''
     if filter_name in cls.SYNPHOT:
         return SpectralElement.from_filter(filter_name)
     else:
         method_to_call = getattr(cls, '_%s' % filter_name)
         return method_to_call()
示例#5
0
def test_remote_rn_powerlaw():
    sp1 = spparser.parse_spec('rn(pl(5000, 1, flam), band(v), 1, photlam)')
    _single_functioncall(sp1, SourceSpectrum, None,
                         'rn(pl(5000.0,1.0,flam),band(v),1.0,photlam)')

    pl = SourceSpectrum(PowerLawFlux1D, amplitude=1 * units.FLAM,
                        x_0=5000 * u.AA, alpha=-1)
    bp = SpectralElement.from_filter('johnson_v')
    sp2 = pl.normalize(1 * units.PHOTLAM, band=bp)
    _compare_spectra(sp1, sp2)
    def __init__(self, throughput_name, interpval=None):
        self.throughput_name = throughput_name

        # Extract bandpass unless component is a CLEAR filter.
        if throughput_name != conf.clear_filter:
            if interpval is None:
                self.throughput = SpectralElement.from_file(throughput_name)
            else:
                self.throughput = interpolate_spectral_element(
                    throughput_name, interpval)
        else:
            self.throughput = None
示例#7
0
def test_remote_rn_calspec_box():
    sp1 = spparser.parse_spec(
        'rn(crcalspec$gd71_mod_005.fits, box(5000, 10), 17, vegamag)')
    _single_functioncall(
        sp1, SourceSpectrum, None,
        'rn(crcalspec$gd71_mod_005.fits,box(5000.0,10.0),17.0,vegamag)')

    gd71 = SourceSpectrum.from_file(resolve_filename(
        os.environ['PYSYN_CDBS'], 'calspec', 'gd71_mod_005.fits'))
    box = SpectralElement(Box1D, amplitude=1, x_0=5000 * u.AA, width=10 * u.AA)
    sp2 = gd71.normalize(17 * units.VEGAMAG, band=box, vegaspec=spectrum.Vega)
    _compare_spectra(sp1, sp2)
    def __init__(self, throughput_name, interpval=None):
        self.throughput_name = throughput_name

        # Extract bandpass unless component is a CLEAR filter.
        if throughput_name != conf.clear_filter:
            if interpval is None:
                self.throughput = SpectralElement.from_file(throughput_name)
            else:
                self.throughput = interpolate_spectral_element(
                    throughput_name, interpval)
        else:
            self.throughput = None
    def sensitivity(self):
        """Sensitivity spectrum to convert flux in
        :math:`erg \\; cm^{-2} \\; s^{-1} \\; \\AA^{-1}` to
        :math:`count s^{-1} \\AA^{-1}`. Calculation is done by
        combining the throughput curves with
        :math:`\\frac{h \\; c}{\\lambda}` .

        """
        x = self.throughput.waveset
        y = self.throughput(x)
        thru = y.value * x.value * self._constant.value
        meta = {'expr': f'Sensitivity for {self._obsmode}'}
        return SpectralElement(
            Empirical1D, points=x, lookup_table=thru, meta=meta)
示例#10
0
def test_remote_rn_icat_k93():
    sp1 = spparser.parse_spec(
        'rn(icat(k93models, 5000, 0.5, 0), '
        'cracscomp$acs_f814w_hrc_006_syn.fits, 17, obmag)')
    _single_functioncall(
        sp1, SourceSpectrum, None,
        'rn(k93models(T_eff=5000,metallicity=0.5,log_g=0),'
        'cracscomp$acs_f814w_hrc_006_syn.fits,17.0,obmag)')

    k93 = catalog.grid_to_spec('k93models', 5000, 0.5, 0)
    bp = SpectralElement.from_file(resolve_filename(
        os.environ['PYSYN_CDBS'], 'comp', 'acs', 'acs_f814w_hrc_006_syn.fits'))
    sp2 = k93.normalize(17 * units.OBMAG, band=bp, area=conf.area)
    _compare_spectra(sp1, sp2)
示例#11
0
def misc():
    # get_vega() downloads this one
    synphot.specio.read_remote_spec(
        'http://ssb.stsci.edu/cdbs/calspec/alpha_lyr_stis_008.fits')

    # G5V of UVKLIB subset of Pickles library
    # see http://www.stsci.edu/hst/instrumentation/reference-data-for-calibration-and-tools/astronomical-catalogs/pickles-atlas.html
    synphot.specio.read_remote_spec(
        'http://ssb.stsci.edu/cdbs/grid/pickles/dat_uvk/pickles_uk_27.fits')

    # read the sourcespectrum
    spG5V = SourceSpectrum.from_file(
        'http://ssb.stsci.edu/cdbs/grid/pickles/dat_uvk/pickles_uk_27.fits')
    spG2V = SourceSpectrum.from_file(
        'http://ssb.stsci.edu/cdbs/grid/pickles/dat_uvk/pickles_uk_26.fits')

    filtR = SpectralElement.from_filter('johnson_r')
    spG2V_19r = spG2V.normalize(19 * synphot.units.VEGAMAG,
                                filtR,
                                vegaspec=SourceSpectrum.from_vega())

    bp = SpectralElement(Box1D, x_0=700 * u.nm, width=600 * u.nm)
    obs = Observation(spG2V_19r, bp)
    obs.countrate(area=50 * u.m**2)

    bp220 = SpectralElement(Box1D, x_0=800 * u.nm, width=400 * u.nm)
    bpCRed = SpectralElement(Box1D, x_0=1650 * u.nm, width=300 * u.nm) * 0.8

    Observation(spG2V_19r, bp220).countrate(area=50 * u.m**2)
    Observation(spG2V_19r, bpCRed).countrate(area=50 * u.m**2)

    spM0V_8R = get_normalized_star_spectrum('M0V', 8.0, 'johnson_r')

    uPhotonSecM2Micron = u.photon / (u.s * u.m**2 * u.micron)

    spG2V_8R = get_normalized_star_spectrum("G2V", 8.0, 'johnson_r')
    plt.plot(spG2V_8R.waveset,
             spG2V_8R(spG2V_8R.waveset).to(uPhotonSecM2Micron))

    # compare with Armando's
    spG2V_19R = get_normalized_star_spectrum("G2V", 19, 'johnson_r')
    bp = SpectralElement(Box1D, x_0=700 * u.nm, width=600 * u.nm)
    obs = Observation(spG2V_19R, bp)
    obs.countrate(area=50 * u.m**2)

    # zeropoint in filtro r in erg/s/cm2/A
    Observation(get_normalized_star_spectrum('A0V', 0, 'johnson_r'),
                SpectralElement.from_filter('johnson_r')).effstim('flam')
    # zeropoint in ph/s/m2
    Observation(get_normalized_star_spectrum('A0V', 0, 'johnson_r'),
                SpectralElement.from_filter('johnson_r')).countrate(area=1 *
                                                                    u.m**2)
    def test_write_fits(self):
        outfile = os.path.join(self.outdir, 'outspec1.fits')
        self.obs.to_fits(outfile, trim_zero=False, pad_zero_ends=False)

        # Read it back in
        with fits.open(outfile) as pf:
            assert (pf[1].header['grftable'] ==
                    os.path.basename(self.obs.obsmode.gtname))
            assert (pf[1].header['cmptable'] ==
                    os.path.basename(self.obs.obsmode.ctname))

        obs = SpectralElement.from_file(outfile)
        w = self.obs.waveset
        np.testing.assert_allclose(obs.waveset, w)
        np.testing.assert_allclose(obs(w), self.obs(w))
    def test_std_filter(self):
        obs1 = spectrum.band('johnson,v')
        obs2 = SpectralElement.from_filter('johnson_v', encoding='binary')
        w = obs1.waveset
        np.testing.assert_allclose(obs1(w), obs2(w))

        # No pixel scale
        with pytest.raises(synexceptions.SynphotError):
            obs1.thermback()

        # No binset
        with pytest.raises(synexceptions.UndefinedBinset):
            obs1.binned_waverange(5000, 2)
        with pytest.raises(synexceptions.UndefinedBinset):
            obs1.binned_pixelrange([5000, 5002])
示例#14
0
def _convertstr(value):
    """Convert given filename to source spectrum or passband.

    This is used by the interpreter to do the conversion from
    string to spectrum object.

    """
    if not isinstance(value, str):
        return value
    value = irafconvert(value)
    try:
        sp = SourceSpectrum.from_file(value)
    except KeyError:
        sp = SpectralElement.from_file(value)
    return sp
示例#15
0
def test_remote_rn_calspec_u():
    sp1 = spparser.parse_spec(
        'rn(crcalspec$bd_75d325_stis_002.fits, band(u), 9.5, vegamag) * '
        'band(fos, blue, 4.3, g160l)')
    # NOTE: No expr for this combo.
    _single_functioncall(sp1, SourceSpectrum, None, '')

    bd75 = SourceSpectrum.from_file(resolve_filename(
        os.environ['PYSYN_CDBS'], 'calspec', 'bd_75d325_stis_002.fits'))
    bp_u = SpectralElement.from_filter('johnson_u')
    bd75_norm = bd75.normalize(
        9.5 * units.VEGAMAG, band=bp_u, vegaspec=spectrum.Vega)
    bp_fos = spectrum.band('fos, blue, 4.3, g160l')
    sp2 = bd75_norm * bp_fos
    _compare_spectra(sp1, sp2)
    def test_write_fits(self):
        outfile = os.path.join(self.outdir, 'outspec1.fits')
        self.obs.to_fits(outfile, trim_zero=False, pad_zero_ends=False)

        # Read it back in
        with fits.open(outfile) as pf:
            assert (pf[1].header['grftable'] == os.path.basename(
                self.obs.obsmode.gtname))
            assert (pf[1].header['cmptable'] == os.path.basename(
                self.obs.obsmode.ctname))

        obs = SpectralElement.from_file(outfile)
        w = self.obs.waveset
        np.testing.assert_allclose(obs.waveset, w)
        np.testing.assert_allclose(obs(w), self.obs(w))
    def test_std_filter(self):
        obs1 = spectrum.band('johnson,v')
        obs2 = SpectralElement.from_filter('johnson_v', encoding='binary')
        w = obs1.waveset
        np.testing.assert_allclose(obs1(w), obs2(w))

        # No pixel scale
        with pytest.raises(synexceptions.SynphotError):
            obs1.thermback()

        # No binset
        with pytest.raises(synexceptions.UndefinedBinset):
            obs1.binned_waverange(5000, 2)
        with pytest.raises(synexceptions.UndefinedBinset):
            obs1.binned_pixelrange([5000, 5002])
示例#18
0
def readFilter(filterName):
    bp = SpectralElement.from_file(filterName, wave_unit=u.nm)
    return bp
def test_spectra_rescaling():
    """Test the functionality for rescaling input spectra to a given
    magnitude in a given filter
    """
    # JWST primary mirror area in cm^2. Needed for countrate check
    # at the end
    primary_area = 25.326 * (u.m * u.m)

    # Create spectrum: one source to be normalized
    # and the other should not be
    waves = np.arange(0.4, 5.6, 0.01)
    flux = np.repeat(1e-16, len(waves))
    flux2 = np.repeat(4.24242424242e-18, len(waves))  # arbitrary value
    spectra = {
        1: {
            "wavelengths": waves * u.micron,
            "fluxes": flux * u.pct
        },
        2: {
            "wavelengths": waves * u.micron,
            "fluxes": flux2 * units.FLAM
        }
    }

    # Create source catalog containing scaling info
    catalog = Table()
    catalog['index'] = [1, 2]
    catalog['nircam_f322w2_magnitude'] = [18.] * 2
    catalog['niriss_f090w_magnitude'] = [18.] * 2
    #catalog['fgs_magnitude'] = [18.] * 2

    # Instrument info
    instrument = ['nircam', 'niriss']  # , 'fgs']
    filter_name = ['F322W2', 'F090W']  # , 'N/A']
    module = ['B', 'N']  # , 'F']
    detector = ['NRCA1', 'NIS']  # , 'GUIDER1']

    # Magnitude systems of renormalization magnitudes
    mag_sys = ['vegamag', 'abmag', 'stmag']

    # Loop over options and test each
    for inst, filt, mod, det in zip(instrument, filter_name, module, detector):

        # Extract the appropriate column from the catalog information
        magcol = [col for col in catalog.colnames if inst in col]
        sub_catalog = catalog['index', magcol[0]]

        # Filter throughput files
        filter_thru_file = get_filter_throughput_file(instrument=inst,
                                                      filter_name=filt,
                                                      nircam_module=mod,
                                                      fgs_detector=det)

        # Retrieve the correct gain value that goes with the fluxcal info
        if inst == 'nircam':
            gain = MEAN_GAIN_VALUES['nircam']['lwb']
        elif inst == 'niriss':
            gain = MEAN_GAIN_VALUES['niriss']
        elif inst == 'fgs':
            gain = MEAN_GAIN_VALUES['fgs'][det.lower()]

        # Create filter bandpass object, to be used in the final
        # comparison
        filter_tp = ascii.read(filter_thru_file)
        bp_waves = filter_tp['Wavelength_microns'].data * u.micron
        thru = filter_tp['Throughput'].data
        bandpass = SpectralElement(
            Empirical1D, points=bp_waves, lookup_table=thru) / gain

        # Check the renormalization in all photometric systems
        for magsys in mag_sys:
            rescaled_spectra = spec.rescale_normalized_spectra(
                spectra, sub_catalog, magsys, filter_thru_file, gain)

            # Calculate the countrate associated with the renormalized
            # spectrum through the requested filter
            for dataset in rescaled_spectra:
                if dataset == 1:
                    # This block is for the spectra that are rescaled
                    rescaled_spectrum = SourceSpectrum(
                        Empirical1D,
                        points=rescaled_spectra[dataset]['wavelengths'],
                        lookup_table=rescaled_spectra[dataset]['fluxes'])

                    obs = Observation(rescaled_spectrum,
                                      bandpass,
                                      binset=bandpass.waveset)
                    renorm_counts = obs.countrate(area=primary_area)

                    # Calculate the countrate associated with an object of
                    # matching magnitude
                    if inst != 'fgs':
                        mag_col = '{}_{}_magnitude'.format(
                            inst.lower(), filt.lower())
                    else:
                        mag_col = 'fgs_magnitude'
                    filt_info = spec.get_filter_info([mag_col], magsys)
                    magnitude = catalog[mag_col][dataset - 1]
                    photflam, photfnu, zeropoint, pivot = filt_info[mag_col]
                    check_counts = magnitude_to_countrate(
                        'imaging',
                        magsys,
                        magnitude,
                        photfnu=photfnu.value,
                        photflam=photflam.value,
                        vegamag_zeropoint=zeropoint)

                    if magsys != 'vegamag':
                        # As long as the correct gain is used, AB mag and ST mag
                        # count rates agree very well
                        tolerance = 0.0005
                    else:
                        # Vegamag count rates for NIRISS have a sligtly larger
                        # disagreement. Zeropoints were derived assuming Vega = 0.02
                        # magnitudes. This offset has been added to the rescaling
                        # function, but may not be exact.
                        tolerance = 0.0015

                    # This dataset has been rescaled, so check that the
                    # countrate from the rescaled spectrum matches that from
                    # the magnitude it was rescaled to
                    if isinstance(check_counts, u.quantity.Quantity):
                        check_counts = check_counts.value
                    if isinstance(renorm_counts, u.quantity.Quantity):
                        renorm_counts = renorm_counts.value

                    print(inst, filt, magsys, renorm_counts, check_counts,
                          renorm_counts / check_counts)
                    assert np.isclose(renorm_counts, check_counts, atol=0, rtol=tolerance), \
                        print('Failed assertion: ', inst, filt, magsys, renorm_counts, check_counts,
                              renorm_counts / check_counts)
                elif dataset == 2:
                    # Not rescaled. In this case Mirage ignores the magnitude
                    # value in the catalog, so we can't check against check_counts.
                    # Just make sure that the rescaling function did not
                    # change the spectrum at all
                    assert np.all(spectra[dataset]['fluxes'] ==
                                  rescaled_spectra[dataset]['fluxes'])
示例#20
0
 def _ccd_220(cls):
     return SpectralElement.from_file(os.path.join(cls._DetectorsFolder(),
                                                   'ccd220.dat'),
                                      wave_unit=u.um)
示例#21
0
 def _c_red_one(cls):
     return SpectralElement.from_file(os.path.join(cls._DetectorsFolder(),
                                                   'c_red_one.dat'),
                                      wave_unit=u.nm)
示例#22
0
 def _eso_etc(cls, filter_name, wavelength_unit):
     return SpectralElement.from_file(os.path.join(
         cls._EsoEtcFiltersFolder(), 'phot_%s.dat' % filter_name),
                                      wave_unit=wavelength_unit)
示例#23
0
def rescale_normalized_spectra(spectra, catalog_info, magnitude_system,
                               bandpass_file, gain_value):
    """Rescale any input spectra that are normalized

    Parameters
    ----------
    spectra : OrderedDict
        Dictionary containing spectra for some/all targets. Dictionary
        keys are the object indexes (such as from the index column in
        the catalog_file. Entries must be e.g.
        d[1] = {"wavelengths": <wavelength_list>,
                "fluxes": <List of spectral flux densities>}
        Wavelengths and fluxes can be lists, or lists with astropy units
        attached. If no units are supplied, Mirage assumes wavelengths
        in microns and flux densities in Flambda units.

    catalog_info : astropy.table.Table
        Index column and magnitude column to use for rescaling. Extracted
        from the original input catalog.

    magnitude_system : str
        Magnitude system corresponding to the input magnitudes (e.g. 'abmag')

    bandpass_file : str
        Name of ascii file containing filter throughput curve. (Generally
        retrieved from config directory)

    gain_value : float
        Gain value (e-/ADU) to use to adjust any rescaled spectra to produce
        given countrates in ADU/sec rather than e-/sec. This is needed
        because the flux calibration info (e.g. photflam, photfnu) were
        created such that they translate from magnitudes to ADU/sec rather
        than to e-/sec

    Returns
    -------
    spec : OrderedDict
        Input dictionary, with flux values rescaled (in FLAM units) to the
        requested magnitude, only for spectra where the flux units are
        astropy.units.pct
    """
    logger = logging.getLogger(
        'mirage.catalogs.spectra_from_catalog.rescale_normalized_spectra')

    # Get the Vega spectrum from synphot. Use the version that was used
    # to create the photom reference files and filter zeropoints
    with syn_conf.set_temp(
            'vega_file',
            'http://ssb.stsci.edu/cdbs/calspec/alpha_lyr_stis_008.fits'):
        vegaspec = SourceSpectrum.from_vega()

    mag_colname = [col for col in catalog_info.colnames
                   if 'index' not in col][0]
    instrument = mag_colname.split('_')[0].lower()

    # Make a copy so we aren't modifying spec in place, which seems to be passed
    # by reference back to the calling function
    spec = copy.deepcopy(spectra)

    for dataset in spec:
        waves = spec[dataset]['wavelengths']
        flux = spec[dataset]['fluxes']
        flux_units = flux.unit
        if (flux_units == u.pct):
            logger.info(
                'SED for source {} is normalized. Rescaling.'.format(dataset))
            match = catalog_info['index'] == dataset

            if not any(match):
                #raise ValueError(('WARNING: No matching target in ascii catalog for normalized source '
                #                  'number {}. Unable to rescale.').format(dataset))
                continue
            magnitude = catalog_info[mag_colname].data[match][0]

            # Create a synphot source spectrum
            fake_flux_units = units.FLAM
            source_spectrum = SourceSpectrum(Empirical1D,
                                             points=waves,
                                             lookup_table=flux.value *
                                             fake_flux_units)

            # Create a synphot SpectralElement containing the filter bandpass
            filter_tp = ascii.read(bandpass_file)
            bp_waves = filter_tp['Wavelength_microns'].data * u.micron
            bp_waves = bp_waves.to(u.Angstrom)
            thru = filter_tp['Throughput'].data

            bandpass = SpectralElement(Empirical1D,
                                       points=bp_waves.value,
                                       lookup_table=thru) / gain_value

            # Renormalize
            magnitude_system = magnitude_system.lower()

            if magnitude_system == 'vegamag':
                magunits = units.VEGAMAG
                vega_spec = vegaspec
            elif magnitude_system == 'abmag':
                magunits = u.ABmag
                vega_spec = None
            elif magnitude_system == 'stmag':
                magunits = u.STmag
                vega_spec = None
            elif magnitude_system == 'counts':
                raise ValueError(
                    'ERROR: normalization to a given countrate not yet supported.'
                )
            if magnitude_system != 'vegamag':
                renorm = source_spectrum.normalize(magnitude * magunits,
                                                   bandpass,
                                                   vegaspec=vega_spec)
            else:
                if instrument == 'nircam':
                    # NIRCam vegamag zeropoints are based on synphot's Vega spectrum
                    renorm = source_spectrum.normalize(magnitude * magunits,
                                                       bandpass,
                                                       vegaspec=vega_spec)
                elif instrument == 'niriss':
                    # NIRISS vegamag zeropoints are based on Vega having a
                    # magnitude of 0.02 in all filters
                    renorm = source_spectrum.normalize(
                        (magnitude - 0.02) * units.VEGAMAG,
                        bandpass,
                        vegaspec=vega_spec)
                elif instrument == 'fgs':
                    # FGS vegamag zeropoints are based on a Sirius spectrum
                    # rather than Vega
                    raise NotImplementedError(
                        "Source spectrum rescaling for FGS not yet supported")
                    sirius_file = 'sirius_mod_003.txt'
                    sirius_tab = ascii.read(sirius_file)
                    sirius_waves = sirius_tab['Wavelength'] * u.Angstrom
                    sirius_flux = sirius_tab['Flux'] * units.FLAM
                    sirius_spectrum = SourceSpectrum(Empirical1D,
                                                     points=sirius_waves,
                                                     lookup_table=sirius_flux)
                    #sirius_spec_norm = sirius_spectrum.normalize(0. * units.VEGAMAG, bandpass, vegaspec=sirius_spectrum)
                    renorm = source_spectrum.normalize(
                        magnitude * units.VEGAMAG,
                        bandpass,
                        vegaspec=sirius_spectrum)

            spec[dataset]['fluxes'] = renorm(waves, flux_unit='flam')
        else:
            logger.info(
                'SED for source {} is already in physical units. NOT RESCALING'
                .format(dataset))

    return spec
示例#24
0
def interpolate_spectral_element(parfilename, interpval, ext=1):
    """Interpolate (or extrapolate) throughput spectra in given
    parameterized FITS table to given parameter value.

    FITS table is parsed with :func:`stsynphot.stio.read_interp_spec`.
    Parameterized values must be in ascending order in the
    table columns.

    If extrapolation is needed but not allowed, default throughput
    from ``THROUGHPUT`` column will be used.

    Parameters
    ----------
    parfilename : str
        Parameterized filename contains a suffix followed by
        a column name specificationin between square brackets.
        For example, ``path/acs_fr656n_006_syn.fits[fr656n#]``.

    interpval : float
        Desired parameter value.

    ext : int, optional
        FITS extension index of the data table.

    Returns
    -------
    sp : `synphot.spectrum.SpectralElement`
        Empirical bandpass at ``interpval``.

    Raises
    ------
    synphot.exceptions.ExtrapolationNotAllowed
        Extrapolation is not allowed by data table.

    synphot.exceptions.SynphotError
        No columns available for interpolation or extrapolation.

    """
    def_colname = 'THROUGHPUT'
    warndict = {}

    # Separate real filename and column name specification
    xre = _interpfilepatt.search(parfilename)
    if xre is None:
        raise synexceptions.SynphotError(
            '{0} must be in the format of "path/filename.fits'
            '[col#]"'.format(parfilename))
    filename = parfilename[0:xre.start()]
    col_prefix = xre.group('col').upper()

    # Read data table
    data, wave_unit, doshift, extrapolate = stio.read_interp_spec(
        filename, tab_ext=ext)
    wave_unit = units.validate_unit(wave_unit)
    wave0 = data['WAVELENGTH']

    # Determine the columns that bracket the desired value.
    # Grab all columns that begin with the parameter name (e.g. 'MJD#')
    # and then split off the numbers after the '#'.
    col_names = []
    col_pars = []
    for n in data.names:
        cn = n.upper()
        if cn.startswith(col_prefix):
            col_names.append(cn)
            col_pars.append(float(cn.split('#')[1]))

    if len(col_names) < 1:
        raise synexceptions.SynphotError(
            '{0} contains no interpolated columns for {1}.'.format(
                filename, col_prefix))

    # Assumes ascending order of parameter values in table.
    min_par = col_pars[0]
    max_par = col_pars[-1]

    # Exact match. No interpolation needed.
    if interpval in col_pars:
        thru = data[col_names[col_pars.index(interpval)]]

    # Need interpolation.
    elif (interpval > min_par) and (interpval < max_par):
        upper_ind = np.searchsorted(col_pars, interpval)
        lower_ind = upper_ind - 1

        thru = _interp_spec(
            interpval, wave0, col_pars[lower_ind], col_pars[upper_ind],
            data[col_names[lower_ind]], data[col_names[upper_ind]], doshift)

    # Need extrapolation, if allowed.
    elif extrapolate:
        # Extrapolate below lowest columns.
        if interpval < min_par:
            thru = _extrap_spec(interpval, min_par, col_pars[1],
                                data[col_names[0]], data[col_names[1]])

        # Extrapolate above highest columns.
        else:  # interpval > max_par
            thru = _extrap_spec(interpval, col_pars[-2], max_par,
                                data[col_names[-2]], data[col_names[-1]])

    # Extrapolation not allowed.
    else:
        # Use default, if available.
        if def_colname in data.names:
            warnings.warn(
                'Extrapolation not allowed, using default throughput for '
                '{0}.'.format(parfilename), AstropyUserWarning)
            warndict['DefaultThroughput'] = True
            thru = data[def_colname]

        # Nothing can be done.
        else:
            raise synexceptions.ExtrapolationNotAllowed(
                'No default throughput for {0}.'.format(parfilename))

    meta = {'expr': '{0}#{1:g}'.format(filename, interpval),
            'warnings': warndict}
    return SpectralElement(
        Empirical1D, points=wave0*wave_unit, lookup_table=thru, meta=meta)
示例#25
0
    def p_functioncall(self, tree):
        # Where all the real interpreter action is.
        # Note that things that should only be done at the top level
        # are performed in :func:`interpret` defined below.
        """ V ::= function_call ( V LPAREN V RPAREN ) """
        if not isinstance(tree[2].value, list):
            args = [tree[2].value]
        else:
            args = tree[2].value

        fname = tree[0].value
        metadata = {'expr': '{0}{1}'.format(fname, tuple(args))}

        if fname not in _SYFUNCTIONS:
            log.error('Unknown function: {0}'.format(fname))
            self.error(fname)

        else:
            # Constant spectrum
            if fname == 'unit':
                if args[1] not in _SYFORMS:
                    log.error('Unrecognized unit: {0}'.format(args[1]))
                    self.error(fname)
                try:
                    fluxunit = units.validate_unit(args[1])
                    tree.value = SourceSpectrum(ConstFlux1D,
                                                amplitude=args[0] * fluxunit,
                                                meta=metadata)
                except NotImplementedError as e:
                    log.error(str(e))
                    self.error(fname)

            # Black body
            elif fname == 'bb':
                tree.value = SourceSpectrum(BlackBodyNorm1D,
                                            temperature=args[0])

            # Power law
            elif fname == 'pl':
                if args[2] not in _SYFORMS:
                    log.error('Unrecognized unit: {0}'.format(args[2]))
                    self.error(fname)
                try:
                    fluxunit = units.validate_unit(args[2])
                    tree.value = SourceSpectrum(PowerLawFlux1D,
                                                amplitude=1 * fluxunit,
                                                x_0=args[0],
                                                alpha=-args[1],
                                                meta=metadata)
                except (synexceptions.SynphotError, NotImplementedError) as e:
                    log.error(str(e))
                    self.error(fname)

            # Box throughput
            elif fname == 'box':
                tree.value = SpectralElement(Box1D,
                                             amplitude=1,
                                             x_0=args[0],
                                             width=args[1],
                                             meta=metadata)

            # Source spectrum from file
            elif fname == 'spec':
                tree.value = SourceSpectrum.from_file(irafconvert(args[0]))
                tree.value.meta.update(metadata)

            # Passband
            elif fname == 'band':
                tree.value = spectrum.band(tree[2].svalue)
                tree.value.meta.update(metadata)

            # Gaussian emission line
            elif fname == 'em':
                if args[3] not in _SYFORMS:
                    log.error('Unrecognized unit: {0}'.format(args[3]))
                    self.error(fname)
                x0 = args[0]
                fluxunit = units.validate_unit(args[3])
                totflux = units.convert_flux(x0, args[2] * fluxunit,
                                             units.PHOTLAM).value
                tree.value = SourceSpectrum(GaussianFlux1D,
                                            total_flux=totflux,
                                            mean=x0,
                                            fwhm=args[1])

            # Catalog interpolation
            elif fname == 'icat':
                tree.value = grid_to_spec(*args)

            # Renormalize source spectrum
            elif fname == 'rn':
                sp = args[0]
                bp = args[1]
                fluxunit = units.validate_unit(args[3])
                rnval = args[2] * fluxunit

                if not isinstance(sp, SourceSpectrum):
                    sp = SourceSpectrum.from_file(irafconvert(sp))

                if not isinstance(bp, SpectralElement):
                    bp = SpectralElement.from_file(irafconvert(bp))

                # Always force the renormalization to occur: prevent exceptions
                # in case of partial overlap. Less robust but duplicates
                # IRAF SYNPHOT. Force the renormalization in the case of
                # partial overlap, but raise an exception if the spectrum and
                # bandpass are entirely disjoint.
                try:
                    tree.value = sp.normalize(rnval,
                                              band=bp,
                                              area=conf.area,
                                              vegaspec=spectrum.Vega)
                except synexceptions.PartialOverlap:
                    tree.value = sp.normalize(rnval,
                                              band=bp,
                                              area=conf.area,
                                              vegaspec=spectrum.Vega,
                                              force=True)
                    tree.value.warnings = {
                        'force_renorm': ('Renormalization exceeds the limit '
                                         'of the specified passband.')
                    }
                tree.value.meta.update(metadata)

            # Redshift source spectrum (flat spectrum if fails)
            elif fname == 'z':
                sp = args[0]

                # ETC generates junk (i.e., 'null') sometimes
                if isinstance(sp, str) and sp != 'null':
                    sp = SourceSpectrum.from_file(irafconvert(sp))

                if isinstance(sp, SourceSpectrum):
                    tree.value = sp
                    tree.value.z = args[1]
                else:
                    tree.value = SourceSpectrum(ConstFlux1D, amplitude=1)

                tree.value.meta.update(metadata)

            # Extinction
            elif fname == 'ebmvx':
                try:
                    tree.value = spectrum.ebmvx(args[1], args[0])
                except synexceptions.SynphotError as e:
                    log.error(str(e))
                    self.error(fname)
                tree.value.meta.update(metadata)

            # Default
            else:
                tree.value = ('would call {0} with the following args: '
                              '{1}'.format(fname, repr(args)))