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)
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)
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)
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()
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
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 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)
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)
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])
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
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 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'])
def _ccd_220(cls): return SpectralElement.from_file(os.path.join(cls._DetectorsFolder(), 'ccd220.dat'), wave_unit=u.um)
def _c_red_one(cls): return SpectralElement.from_file(os.path.join(cls._DetectorsFolder(), 'c_red_one.dat'), wave_unit=u.nm)
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)
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
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)
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)))