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')
def test_conversion1(self): pl = S.PowerLaw(6000, -4, 'angstrom', 'photlam') angflux = pl.sample(self.wave) pl.convert('nm') nmflux = pl.sample(self.wave / 10.) self.assertEqualNumpy(nmflux, angflux)
def test_conversion2(self): pl = S.PowerLaw(6000, -4, 'angstrom', 'photlam') self.assertEqualNumpy( pl.sample(self.wave)[:10], pl.sample(self.wave[:10])) pl.convert('nm') self.assertEqualNumpy( pl.sample(self.wave)[:10], pl.sample(self.wave[:10]))
def test_values(self): ref = np.array([ 16., 15.78843266, 15.58035072, 15.37568551, 15.17436992, 14.97633838, 14.78152682, 14.5898726, 14.40131453, 14.21579277 ]) pl = S.PowerLaw(6000, -4, 'angstrom', 'photlam') test = pl.sample(self.wave[:10]) self.assertApproxNumpy(test, ref)
def __init__(self, refwave, beta, redshift, A=1.0, verbose=False): self.rspec = S.PowerLaw(refwave, beta, waveunits='angstrom', fluxunits='flam') # self.factory = FileSED.GalaxySEDFactory(spec=rspec) # Redshift the spectrum & add IGM attenuation # self.rspec = self.factory.redshift(redshift) # the reference spectrum mag = S.Observation(self.rspec, filters['f160w']).effstim('abmag') # normalize reference spectrum to 25.0 mag in F160W to minimize # round-off errors later in fitting dmag = 25.0 - mag self.rspec = 10.**(-0.4 * dmag) * self.rspec A = np.abs(A) self.rspec = A * self.rspec self.beta = beta self.A = A self.verbose = verbose
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
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)
def setUp(self): self.sp=S.PowerLaw(10000,0.5)