def colorMod(): # Load the Filters JBandFilterWave, JBandFilterThru = np.loadtxt('2MASS-2MASS.J.dat').T # load the J filter HBandFilterWave, HBandFilterThru = np.loadtxt('2MASS-2MASS.H.dat').T # load the H filter KBandFilterWave, KBandFilterThru = np.loadtxt('2MASS-2MASS.Ks.dat').T # load the K filter # Interpolate the Filters onto the Stellar Model Wavelength Grid tempModel = S.Icat('phoenix', 5500, 0.0, 4.5) # we are going to use this to setup the filters in the SYNPHOT framework JBandFilterSpline = CubicSpline(JBandFilterWave, JBandFilterThru) HBandFilterSpline = CubicSpline(HBandFilterWave, HBandFilterThru) KBandFilterSpline = CubicSpline(KBandFilterWave, KBandFilterThru) # For some reason pysnphot stores the Vega spectrum with different number of flux points JWaveVRange= (S.Vega.wave >= JBandFilterWave.min()) * (S.Vega.wave <= JBandFilterWave.max()) # isolate model region in JBand HWaveVRange= (S.Vega.wave >= HBandFilterWave.min()) * (S.Vega.wave <= HBandFilterWave.max()) # isolate model region in HBand KWaveVRange= (S.Vega.wave >= KBandFilterWave.min()) * (S.Vega.wave <= KBandFilterWave.max()) # isolate model region in KBand VegaJFlux = np.trapz(S.Vega.flux[JWaveVRange] * JBandFilterSpline(S.Vega.wave[JWaveVRange])) VegaHFlux = np.trapz(S.Vega.flux[HWaveVRange] * HBandFilterSpline(S.Vega.wave[HWaveVRange])) VegaKFlux = np.trapz(S.Vega.flux[KWaveVRange] * KBandFilterSpline(S.Vega.wave[KWaveVRange])) # Now to compare the JHK filters to the PHOENIX models JWaveRange= (tempModel.wave >= JBandFilterWave.min()) * (tempModel.wave <= JBandFilterWave.max()) # isolate model region in JBand HWaveRange= (tempModel.wave >= HBandFilterWave.min()) * (tempModel.wave <= HBandFilterWave.max()) # isolate model region in HBand KWaveRange= (tempModel.wave >= KBandFilterWave.min()) * (tempModel.wave <= KBandFilterWave.max()) # isolate model region in KBand # Loop over the 30 models nModels = 30 Jmags = np.zeros(nModels) Hmags = np.zeros(nModels) Kmags = np.zeros(nModels) teff_list = [x for x in range(2800,5500+100,100)] + [5800] + [6000] # check if I did that write assert(len(teff_list) == nModels) for kt, teff in enumerate(teff_list): modelTeff = S.Icat('phoenix', teff, 0.0, 4.5) # load the model Jmags[kt] = -2.5*np.log10(np.trapz(modelTeff.flux[JWaveRange] * JBandFilterSpline(tempModel.wave[JWaveRange]) / VegaJFlux)) # integrate the flux in the J bandpass Hmags[kt] = -2.5*np.log10(np.trapz(modelTeff.flux[HWaveRange] * HBandFilterSpline(tempModel.wave[HWaveRange]) / VegaHFlux)) # integrate the flux in the H bandpass Kmags[kt] = -2.5*np.log10(np.trapz(modelTeff.flux[KWaveRange] * KBandFilterSpline(tempModel.wave[KWaveRange]) / VegaKFlux)) # integrate the flux in the K bandpass jhmod = Jmags - Hmags hkmod = Hmags - Kmags return jhmod, hkmod, teff_list
def test_things_in_cache(self): fail = False self.tra = {} Cache.reset_catalog_cache() sp = S.Icat('k93models', 6440, 0, 4.3) self.assertTrue(len(Cache.CATALOG_CACHE) == 1) k = next(key for key in Cache.CATALOG_CACHE.keys()) from pysynphot.locations import irafconvert import os.path f = irafconvert("$PYSYN_CDBS/grid/k93models/catalog.fits") f = os.path.normpath(f) f = os.path.normcase(f) fixed_k = os.path.normpath(k) fixed_k = os.path.normcase(fixed_k) if fixed_k != f: self.tra['cache_found'] = k self.tra['cache_found_fixed'] = fixed_k self.tra['cache_expect'] = f fail = True if not isinstance(Cache.CATALOG_CACHE[k], list): self.tra['cache_type_mismatch'] = str(type(Cache.CATALOG_CACHE[k])) fail = True if fail: raise AssertionError()
def get_kurucz_atmosphere(metallicity=0, temperature=20000, gravity=4): """ metallicity in [Fe/H] (def = +0.0): +1.0, +0.5, +0.3, +0.2, +0.1, +0.0, -0.1, -0.2, -0.3, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0, -3.5, -4.0, -4.5, -5.0. temperatures (def = 20,000 Kelvin): Temperature Range Grid Step K K 3000 - 10000 250 10000 - 13000 500 13000 - 35000 1000 35000 - 50000 2500 log gravity (def = 0.0) in the range of 0.0 - 5.0 in 0.5 increments """ sp = pysynphot.Icat('k93models', temperature, metallicity, gravity) # Do some error checking idx = np.where(sp.flux != 0)[0] if len(idx) == 0: print 'Could not find Kurucz 1993 atmosphere model for' print ' temperature = %d' % temperature print ' metallicity = %.1f' % metallicity print ' log gravity = %.1f' % gravity return sp
def uncached_synthetic_radiation_fn(Teff, fe_h, log_g, mag_v=None, model='k93models', lam_min=0, lam_max=np.inf, return_sp=False): sp = None orig_log_g = log_g if isinstance(model, tuple): # give in meters, W/m3 sp = S.spectrum.ArraySourceSpectrum( np.array(model[0]) * 1e10, np.array(model[1]) * 1e-4 * 1e-10 / 1e-7, 'angstrom', 'flam') else: first_try = True if Teff < 3500: print( 'could not init spectral model with given t_eff=%s, using t_eff=3500K instead' % Teff) Teff = 3500 for i in range(15): try: sp = S.Icat(model, Teff, fe_h, log_g) # 'ck04models' or 'k93models' break except: first_try = False log_g = log_g + (0.2 if Teff > 6000 else -0.2) assert sp is not None, 'could not init spectral model with given params: t_eff=%s, log_g=%s, fe_h=%s' % ( Teff, orig_log_g, fe_h) if not first_try: print( 'could not init spectral model with given params (t_eff=%s, log_g=%s, fe_h=%s), changed log_g to %s' % (Teff, orig_log_g, fe_h, log_g)) if mag_v is not None: sp = sp.renorm(mag_v, 'vegamag', S.ObsBandpass('johnson,v')) if return_sp: return sp # for performance reasons (caching) from scipy.interpolate import interp1d I = np.logical_and(sp.wave >= lam_min * 1e10, sp.wave <= lam_max * 1e10) sample_fn = interp1d(sp.wave[I], sp.flux[I], kind='linear', assume_sorted=True) def phi(lam): r = sample_fn( lam * 1e10) # wavelength in Å, result in "flam" (erg/s/cm2/Å) return r * 1e-7 / 1e-4 / 1e-10 # result in W/m3 return phi
def get_castelli_atmosphere(metallicity=0, temperature=20000, gravity=4): """ metallicity in [Fe/H] (def = +0.0): 0.0, -0.5, -1.0, -1.5, -2.0, -2.5. temperatures (def = 20,000 Kelvin): Temperature Range Grid Step K K 2600 - 4000 100 4000 - 10000 200 log gravity (def = 4.0) in the range of 3.5 - 6.0 in 0.5 increments """ sp = pysynphot.Icat('ck04models', temperature, metallicity, gravity) # Do some error checking idx = np.where(sp.flux != 0)[0] if len(idx) == 0: print 'Could not find Castelli and Kurucz 2004 atmosphere model for' print ' temperature = %d' % temperature print ' metallicity = %.1f' % metallicity print ' log gravity = %.1f' % gravity return sp
def get_magnitudes(Teff, FeH=0.0, logg=4.5, Vmag=10, magScale='vegamag'): # Load the Filters bp_j = S.ObsBandpass('j') bp_h = S.ObsBandpass('h') bp_k = S.ObsBandpass('k') bp_v = S.ObsBandpass('johnson,v') # Stellar spectrum normalized to V=10 mags (default Phoenix models) sp = S.Icat( 'phoenix', Teff, FeH, logg) #pynrc.stellar_spectrum(stellarType, Vmag, 'vegamag', bp_v) sp_norm = sp.renorm(Vmag, magScale, bp_v) sp_norm.name = sp.name sp = sp_norm # Observe in J, H, and K obs_j = S.Observation(sp, bp_j, binset=sp.wave) obs_h = S.Observation(sp, bp_h, binset=sp.wave) obs_k = S.Observation(sp, bp_k, binset=sp.wave) # Magnitudes in each filter mag_j = obs_j.effstim(magScale) mag_h = obs_h.effstim(magScale) mag_k = obs_k.effstim(magScale) return mag_j, mag_h, mag_k
def test_reset_catalog_cache(self): sp = S.Icat('k93models', 6440, 0, 4.3) self.assertTrue(len(Cache.CATALOG_CACHE) != 0) Cache.reset_catalog_cache() self.assertTrue(len(Cache.CATALOG_CACHE) == 0)
def testf(fdat, teff, logg, feh): sp = S.Icat('k93models', float(teff), float(feh), float(logg))\ .renorm(0, 'vegamag', S.ObsBandpass('johnson,v')) sp_real = S.ArraySpectrum(wave=fdat[0][0], flux=fdat[0][1], fluxunits='flam')\ .renorm(0, 'vegamag', S.ObsBandpass('johnson,v')) plt.plot(sp_real.wave, sp_real.flux) plt.plot(sp.wave, sp.flux) plt.xlim(3000, 10000) plt.show()
def get_model_spectra(teff, mh, logg, model='ck04models', L=1, ebv=0): ''' For example: Temperature Teff=10000K, [M/H] = +0.1 and gravity log=3.0. model is the stellar model: Castelli-Kurucz - ck04models Kurucz 1993 Atlas - k93models Parameters ---------- teff : float The effective temperature of the star (in K). mh : string The metallicity as [M/H]. logg : float The log g of the stellar model. model : string Gride stellar models that can be used to retrieve the models for stellar spectra. See: https://pysynphot.readthedocs.io/en/latest/appendixa.html for a description. Castelli-Kurucz - ck04models Kurucz 1993 Atlas - k93models Phoenix (F. Allard et al.) - phoenix L : float The bolometric luminosity of the star (in Lsun). It will be used to normalize the spectrum. ebv : float, default: 0 The reddening to be applied to the model spectrum. Returns ------- s: pysynphot ArraySpectrum The spectrum corresponding to the stellar model, scaled to the luminosity. Examples -------- Temperature Teff=10000K, [M/H] = +0.1 and gravity log=3.0 for a star of 1 Lsun and no extinction. s = get_model_spectra(10000, 0.1, 3.0, model='ck04models', L=1, ebv=0) ''' sp = ps.Icat(model, teff, mh, logg) if ebv != 0: sp = sp * ps.Extinction(ebv, 'lmcavg') F_model = sp.trapezoidIntegration(sp.wave, sp.flux)*(u.erg/u.s/u.cm**2) #In erg / s / cm**2 Lmodel = (4 * np.pi * ((10*u.pc).to(u.cm))**2 * F_model ).to(u.Lsun) norm = L/Lmodel newflux = sp.flux * norm s = ps.ArraySpectrum(sp.wave, newflux, fluxunits="flam") return s
def get_ck04models(temp): all_sed = [] for log_g in Set_Log_g: for logz in Set_Log_Z: sed = S.Icat('ck04models', temp, logz, log_g) sed.convert('flam') # to be sure every spectrum is in flam unit if (max(sed.flux) > 0): # remove empty fluxes because of bad parameters all_sed.append(sed) return all_sed
def get_fl(system='kic1255', renormBand='Kmag'): """ Get the fluxes""" if system == 'kic1255': ## From Rappapor et al. 2012 sp = S.Icat('phoenix', 4400, 0.0, 4.63) Jmag = 14.021 Kmag = 13.319 elif system == 'k2-22': ## From Sanchis-Ojeda 2016 sp = S.Icat('phoenix', 3830, 0.0, 4.65) Jmag = 12.726 Kmag = 11.924 else: print 'No Valid System specified' ## Get the 2MASS bandpasses tmassdir = os.path.join(os.environ['TEL_DATA'], '2mass') bpK = S.FileBandpass(os.path.join(tmassdir, '2mass_k_ang.txt')) bpJ = S.FileBandpass(os.path.join(tmassdir, '2mass_j_ang.txt')) # Get the IRAC bandpasses iracdir = os.path.join(os.environ['TEL_DATA'], 'irac') irac45 = S.FileBandpass(os.path.join(iracdir, 'irac_45_ang.txt')) irac36 = S.FileBandpass(os.path.join(iracdir, 'irac_36_ang.txt')) iracnames = ['IRAC 3.6um', 'IRAC 4.5um'] # Renormalize spectrum if renormBand == 'Kmag': renormBandpass = bpK renormMag = Kmag else: renormBandpass = bpJ renormMag = Jmag sp_norm = sp.renorm(renormMag, 'vegamag', renormBandpass) for iracInd, iracBP in enumerate([irac36, irac45]): obs = S.Observation(sp_norm, iracBP) ## Get the flux at the wavelegnth stim = obs.effstim('uJy') print "Flux for " + iracnames[iracInd] + " is " + str(stim) + " uJy"
def get_castelli_kurucz_spectrum(teff, metallicity, logg): ''' A function that returns the pysynphot spectrum given the parameters based on the Castelli-Kurucz Atlas Retuns the pysynphot spectrum object with wavelength units of microns and flux units of photons/s/cm^2/Angstrom ''' sp = ps.Icat('ck04models', teff, metallicity, logg) return sp
def getSpectrum(self,Teff=5800,z=0.,logg=4.43,vega=False,): #default: Sun at 10pc Teff=5800, z=0, logg=4.4, johnson_v_abs=4.68 self.johnson_v = S.ObsBandpass('johnson,v') self.T=Teff self.z=z self.g=logg if vega: self.star= S.FileSpectrum(S.locations.VegaFile) print ' Using default Pysynphot Vega spectrum' else: print self.getFiltername(), self.getSpectrumInfo() self.star= S.Icat('ck04models',self.T,self.z,self.g) #FLAM surface flux units, i.e. ergs cm-2 s-1 A-1 #star = S.BlackBody(6000) #self.star= self.star.renorm(self.j_v_abs,'vegamag',self.johnson_v) #renorm spectrum to (abs_mag, units system, band) return self.star
def Vega(): # Use Vega as our zeropoint... assume V=0.03 mag and all colors = 0.0 temperature = 9550 metallicity = -0.5 gravity = 3.95 vega = pysynphot.Icat('k93models', temperature, metallicity, gravity) vega = spectrum.trimSpectrum(vega, 8000, 25000) # This is (R/d)**2 as reported by Girardi et al. 2002, page 198, col 1. # and is used to convert to flux observed at Earth. vega *= 6.247e-17 return vega
def get_nextgen_atmosphere(metallicity=0, temperature=5000, gravity=4): """ metallicity = [M/H] (def = 0) temperature = Kelvin (def = 5000) gravity = log gravity (def = 4.0) """ sp = pysynphot.Icat('nextgen', temperature, metallicity, gravity) # Do some error checking idx = np.where(sp.flux != 0)[0] if len(idx) == 0: print('Could not find NextGen atmosphere model for') print(' temperature = %d' % temperature) print(' metallicity = %.1f' % metallicity) print(' log gravity = %.1f' % gravity) return sp
def get_amesdusty_atmosphere(metallicity=0, temperature=5000, gravity=4): """ metallicity = [M/H] (def = 0) temperature = Kelvin (def = 5000) gravity = log gravity (def = 4.0) """ sp = pysynphot.Icat('AMESdusty', temperature, metallicity, gravity) # Do some error checking idx = np.where(sp.flux != 0)[0] if len(idx) == 0: print 'Could not find AMESdusty Allard+ 2000 atmosphere model for' print ' temperature = %d' % temperature print ' metallicity = %.1f' % metallicity print ' log gravity = %.1f' % gravity return sp
def get_phoenix_atmosphere(metallicity=0, temperature=5000, gravity=4): """ metallicity = [M/H] (def = 0) temperature = Kelvin (def = 5000) gravity = log gravity (def = 4.0) """ sp = pysynphot.Icat('phoenix', temperature, metallicity, gravity) # Do some error checking idx = np.where(sp.flux != 0)[0] if len(idx) == 0: print( 'Could not find PHOENIX BT-Settl (Allard+ 2011 atmosphere model for' ) print(' temperature = %d' % temperature) print(' metallicity = %.1f' % metallicity) print(' log gravity = %.1f' % gravity) return sp
def get_all_ck04models(): all_sed = [] # common SED container #for key, temp in TypeStar_to_Temperature.iteritems(): for typestar in TypeStar: temp = TypeStar_to_Temperature[typestar] all_sub_sed = [] for log_g in Set_Log_g: for logz in Set_Log_Z: sed = S.Icat('ck04models', temp, logz, log_g) sed.convert( 'flam') # to be sure every spectrum is in flam unit if (max(sed.flux) > 0): # remove empty fluxes because of bad parameters all_sub_sed.append(sed) all_sed.append(all_sub_sed) return all_sed
def get_grid_phoenixmodels(): index = 1 for temp in Temperature_range: for logg in Set_Log_G: for logz in Set_Log_Z: data[index, index_temp] = temp data[index, index_logg] = logg data[index, index_logz] = logz sed = S.Icat('phoenix', temp, logz, logg) sed.convert( 'flam') # to be sure every spectrum is in flam unit if (max(sed.flux) > 0): # remove empty fluxes because of bad parameters data[index, index_val] = 1 func = interp1d(sed.wave, sed.flux, kind='cubic') flux = func(WL) data[index, index_spec:] = flux index += 1
def get_spectrum(self): """ Use pysynphot.Icat() to calculate spectrum and convert to microns/mJy. If self.webapp=True, use key to look up a specified set of parameters. Otherwise, get them from the configured attributes. """ if self.webapp: if self.key not in self.spectra: msg = "Provided SED key, %s, not supported." % self.key raise EngineInputError(value=msg) pars = self.spectra[self.key] m = pars['metallicity'] t = pars['teff'] g = pars['log_g'] else: m = self.metallicity t = self.teff g = self.log_g sp = psyn.Icat("phoenix", t, m, g) sp.convert("microns") sp.convert("mjy") return sp.wave, sp.flux
def make_cluster_rates(self,masses,instrument,filter,bandpass=None,refs=None): coords = np.load(os.path.join(self.gridpath, 'input.npy')) m, t, g, i = self.get_star_info() temps = np.interp(masses,m,t) gravs = np.interp(masses,m,g) mags = np.interp(masses,m,i) metals = np.full_like(mags, self.metallicity) if os.path.exists(os.path.join(self.gridpath, 'result_{}_{}.npy'.format(instrument.lower(), filter.lower()))): values = np.load(os.path.join(self.gridpath, 'result_{}_{}.npy'.format(instrument.lower(), filter.lower()))) interpolation_function = RegularGridInterpolator(tuple([x for x in coords]), values) try: countrates = interpolation_function(np.array((metals, gravs, temps, mags)).T) except ValueError as v: self.log('error', 'Exception caught when interpolating: {}'.format(v)) min_mag = coords[-1][0] max_mag = coords[-1][-1] interpolation_function = RegularGridInterpolator(tuple([x for x in coords]), values, bounds_error=False, fill_value=0.) mags_min = np.full_like(mags, min_mag) mags_max = np.full_like(mags, max_mag) countrates = interpolation_function(np.array((metals, gravs, temps, mags)).T) countrates_min = interpolation_function(np.array((metals, gravs, temps, mags_min)).T) countrates_min = countrates_min * np.power(10, -(mags-min_mag)/2.512) countrates_max = interpolation_function(np.array((metals, gravs, temps, mags_max)).T) countrates_max = countrates_max * np.power(10, -(mags-max_mag)/2.512) countrates[np.where(mags < mags_min)] = countrates_min[np.where(mags < mags_min)] countrates[np.where(mags > mags_max)] = countrates_max[np.where(mags > mags_max)] else: self.log('warning', 'Could not find result file "result_{}_{}.npy"'.format(instrument.lower(), filter.lower())) import pysynphot as ps countrates = np.array(()) ps.setref(**refs) johnson_i = ps.ObsBandpass('johnson,i') for te, log_g, z, j_i in zip(temps, gravs, metals, mags): spectrum = ps.Icat('phoenix', te, z, log_g) spectrum = spectrum.renorm(j_i, 'vegamag', johnson_i) obs = ps.Observation(spectrum, bandpass, binset=spectrum.wave) countrates = np.append(countrates, obs.countrate()) return countrates
def readPhoenixRealtimeTable(self, table, bp, cached=-1): """ Converts a set of Phoenix sources specified as (id, ra, dec, T, Z, log(g), apparent) into individual stars, observes them, and then produces an output catalogue """ ps.setref(**self.REFS) ids = table['id'] ras = table['ra'] decs = table['dec'] temps = table['teff'] gravs = table['log_g'] metallicities = table['metallicity'] apparents = table['apparent'] norm_bp = '{}'.format(apparents.unit) if norm_bp == '': norm_bp = 'johnson,i' rates = np.zeros_like(ras) for index in range(len(ids)): t, g, Z, a = temps[index], gravs[index], metallicities[ index], apparents[index] sp = ps.Icat('phoenix', t, Z, g) sp = self.normalize(sp, a, norm_bp) obs = ps.Observation(sp, bp, binset=sp.wave) rates[index] = obs.countrate() t = Table() t['ra'] = Column(data=ras) t['dec'] = Column(data=decs) t['flux'] = Column(data=rates) t['type'] = Column(data=np.full_like(ras, "point", dtype="S6")) t['n'] = Column(data=np.full_like(ras, "N/A", dtype="S3")) t['re'] = Column(data=np.full_like(ras, "N/A", dtype="S3")) t['phi'] = Column(data=np.full_like(ras, "N/A", dtype="S3")) t['ratio'] = Column(data=np.full_like(ras, "N/A", dtype="S3")) t['id'] = Column(data=ids) t['notes'] = Column(data=np.full_like(ras, "None", dtype="S6")) return t, cached
def create_stellar_obs(aperture, central_obscuration, nwavels, wl_range, star_dict): """ Creates an observation object from pysynphot phoenix models Parameters: Aperture (cm): Aperture of the telescope central_obscuration (cm): diameter of central obscuration of telescope nwaels: number of wavelengths to sample wl_range (Angstroms): [first wavelength, last wavelength] star_dict: dictionary of the following structure {"mag": float, # vega mag "Teff": int, "Z": float, "log g": float} Returns: A pysynphot observation object describing the star being observed through the given telescope architecture """ # Set Telescope values r = (aperture - central_obscuration) / 2 collecting_area = (np.pi * r**2) S.refs.setref(area=collecting_area) # Takes units of cm^2 wavels = np.linspace(wl_range[0], wl_range[1], nwavels) throughput = np.ones(nwavels) bandpass = S.ArrayBandpass(wavels, throughput) # Create star object star_obj = S.Icat('phoenix', star_dict["Teff"], star_dict["Z"], star_dict["log g"]) spec_filt = star_obj.renorm(star_dict["mag"], 'vegamag', bandpass) # Create observation object obs = S.Observation(spec_filt, bandpass, binset=wavels) return obs
def initialize(self): self.readFilters() if (self.useSpecModel): # if (self.T > 3500*units.K): #for Kurucz self.specModelName = 'ck04models' g = np.clip(self.logg, 3, 5.) T = np.clip(self.T.to(units.K).value, 3500., 50000.0) MH = np.clip(self.M_H, -2.5, 0.5) # else: # #phoenix for cooler stars, but appear to be giving more discrepant results than just using the Kurucz model # self.specModelName = 'phoenix' # g = np.clip(self.logg, 0, 4.5) # T = np.clip(self.T.to(units.K).value, 2000., 7000.0) # MH = np.clip(self.M_H, -4, 1) #print("parameters", self.logg,g, self.T.to(units.K).value, T, self.M_H, MH) self.specModel = pyS.Icat(self.specModelName, T, MH, g) self.specModel.nu = (constants.c / (self.specModel.wave * units.angstrom)).to( units.Hz).value self.specModel.fnu = ( (((self.specModel.wave * units.angstrom)**2. / constants.c) * (self.specModel.flux * units.Ba / units.s)).to( units.g / units.s**2.)).value
def test_atmospheres(distance=6000, logAge=7.0, AKs=None): """ Plot synthetic photometry for some main-sequence stars using various atmospheres. This is useful for checking for smooth overlap between atmosphere models valid at different temperature ranges. distance = distance in pc """ # Get solar mettalicity models for a population at a specific age. print 'Loading Geneva Isochrone logAge=%.2f' % logAge evol = evolution.get_geneva_isochrone(logAge=logAge) mass = evol.mass logT = evol.logT logg = evol.logg logL = evol.logL temp = 10**logT # Trim down to just every 10th entry idx = np.arange(0, len(mass), 10) mass = mass[idx] logT = logT[idx] logg = logg[idx] logL = logL[idx] temp = temp[idx] # Get the NIRC2 filter throughputs J_filter = FilterNIRC2('J') H_filter = FilterNIRC2('H') Kp_filter = FilterNIRC2('Kp') Lp_filter = FilterNIRC2('Lp') # Get the throughput spectrum of the Earth's atmosphere earth = EarthAtmosphere() # Get the spectrum of Vega vega = Vega() # Get the reddening law if AKs != None: redlaw = RedLawNishiyama09() else: redlaw = None J_kurucz = np.zeros(len(mass), dtype=float) H_kurucz = np.zeros(len(mass), dtype=float) Kp_kurucz = np.zeros(len(mass), dtype=float) Lp_kurucz = np.zeros(len(mass), dtype=float) J_castelli = np.zeros(len(mass), dtype=float) H_castelli = np.zeros(len(mass), dtype=float) Kp_castelli = np.zeros(len(mass), dtype=float) Lp_castelli = np.zeros(len(mass), dtype=float) J_nextgen = np.zeros(len(mass), dtype=float) H_nextgen = np.zeros(len(mass), dtype=float) Kp_nextgen = np.zeros(len(mass), dtype=float) Lp_nextgen = np.zeros(len(mass), dtype=float) # Loop through the models in the isochrone and derive their # synthetic photometry. for ii in range(len(temp)): print 'Working on Teff=%5d logg=%4.1f' % (temp[ii], logg[ii]) L = 10**(logL[ii]) * c.Lsun # luminosity in erg/s T = temp[ii] # in Kelvin # Get the radius R = math.sqrt(L / (4.0 * math.pi * c.sigma * T**4)) # in cm R /= (c.cm_in_AU * c.AU_in_pc) # in pc scaleFactor = (R / distance)**2 # Get the Kurucz atmosphere model k93 = pysynphot.Icat('k93models', temp[ii], 0, logg[ii]) k93 *= scaleFactor # Get the Castelli atmosphere model ck04 = pysynphot.Icat('ck04models', temp[ii], 0, logg[ii]) ck04 *= scaleFactor # Get the NextGen atmosphere model ngen = pysynphot.Icat('nextgen', temp[ii], 0, logg[ii]) ngen *= scaleFactor # Calculate the photometry J_kurucz[ii] = magnitude_in_filter(J_filter, k93, redlaw, AKs, None, vega) H_kurucz[ii] = magnitude_in_filter(H_filter, k93, redlaw, AKs, None, vega) Kp_kurucz[ii] = magnitude_in_filter(Kp_filter, k93, redlaw, AKs, None, vega) Lp_kurucz[ii] = magnitude_in_filter(Lp_filter, k93, redlaw, AKs, None, vega) J_castelli[ii] = magnitude_in_filter(J_filter, ck04, redlaw, AKs, None, vega) H_castelli[ii] = magnitude_in_filter(H_filter, ck04, redlaw, AKs, None, vega) Kp_castelli[ii] = magnitude_in_filter(Kp_filter, ck04, redlaw, AKs, None, vega) Lp_castelli[ii] = magnitude_in_filter(Lp_filter, ck04, redlaw, AKs, None, vega) J_nextgen[ii] = magnitude_in_filter(J_filter, ngen, redlaw, AKs, None, vega) H_nextgen[ii] = magnitude_in_filter(H_filter, ngen, redlaw, AKs, None, vega) Kp_nextgen[ii] = magnitude_in_filter(Kp_filter, ngen, redlaw, AKs, None, vega) Lp_nextgen[ii] = magnitude_in_filter(Lp_filter, ngen, redlaw, AKs, None, vega) if np.isnan(Kp_nextgen[ii]): pdb.set_trace() foo = magnitude_in_filter(Kp_filter, nextgen, redlaw, AKs, None, vega) # Now lets plot up some differences vs. effective temp # Everything is done with reference to Kurucz. J_diff_cast = J_castelli - J_kurucz J_diff_ngen = J_nextgen - J_kurucz J_diff_cast_ngen = J_nextgen - J_castelli H_diff_cast = H_castelli - H_kurucz H_diff_ngen = H_nextgen - H_kurucz H_diff_cast_ngen = H_nextgen - H_castelli Kp_diff_cast = Kp_castelli - Kp_kurucz Kp_diff_ngen = Kp_nextgen - Kp_kurucz Kp_diff_cast_ngen = Kp_nextgen - Kp_castelli Lp_diff_cast = Lp_castelli - Lp_kurucz Lp_diff_ngen = Lp_nextgen - Lp_kurucz Lp_diff_cast_ngen = Lp_nextgen - Lp_castelli outdir = '/u/jlu/work/models/test/atmospheres/' outsuffix = '_%dpc_%.1fage' % (distance, logAge) if AKs != None: outsuffix += '_AKs%.1f' % (AKs) outsuffix += '.png' # Plut luminosity differences: py.clf() py.plot(temp, Kp_diff_cast, 'r.', label='Castelli - Kurucz') py.plot(temp, Kp_diff_ngen, 'b.', label='NextGen - Kurucz') py.plot(temp, Kp_diff_cast_ngen, 'g.', label='NextGen - Castelli') py.xlabel('Effective Temperature (deg)') py.ylabel('Kp Magnitude Difference') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) py.legend(numpoints=1, loc='upper left') py.savefig(outdir + 'diff_kp' + outsuffix) py.xlim(3000, 10000) py.ylim(-0.2, 0.2) py.savefig(outdir + 'diff_kp_zoom' + outsuffix) py.clf() py.plot(temp, H_diff_cast, 'r.', label='Castelli - Kurucz') py.plot(temp, H_diff_ngen, 'b.', label='NextGen - Kurucz') py.plot(temp, H_diff_cast_ngen, 'g.', label='NextGen - Castelli') py.xlabel('Effective Temperature (deg)') py.ylabel('H Magnitude Difference') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) py.legend(numpoints=1, loc='upper left') py.savefig(outdir + 'diff_h' + outsuffix) py.xlim(3000, 10000) py.ylim(-0.2, 0.2) py.savefig(outdir + 'diff_h_zoom' + outsuffix) py.clf() py.plot(temp, J_diff_cast, 'r.', label='Castelli - Kurucz') py.plot(temp, J_diff_ngen, 'b.', label='NextGen - Kurucz') py.plot(temp, J_diff_cast_ngen, 'g.', label='NextGen - Castelli') py.xlabel('Effective Temperature (deg)') py.ylabel('J Magnitude Difference') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) py.legend(numpoints=1, loc='upper left') py.savefig(outdir + 'diff_j' + outsuffix) py.xlim(3000, 10000) py.ylim(-0.2, 0.2) py.savefig(outdir + 'diff_j_zoom' + outsuffix) py.clf() py.plot(temp, Lp_diff_cast, 'r.', label='Castelli - Kurucz') py.plot(temp, Lp_diff_ngen, 'b.', label='NextGen - Kurucz') py.plot(temp, Lp_diff_cast_ngen, 'g.', label='NextGen - Castelli') py.xlabel('Effective Temperature (deg)') py.ylabel('Lp Magnitude Difference') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) py.legend(numpoints=1, loc='upper left') py.savefig(outdir + 'diff_lp' + outsuffix) py.xlim(3000, 10000) py.ylim(-0.2, 0.2) py.savefig(outdir + 'diff_lp_zoom' + outsuffix) # Now calculate color differences. JKp_kurucz = J_kurucz - Kp_kurucz JKp_castelli = J_castelli - Kp_castelli JKp_nextgen = J_nextgen - Kp_nextgen HKp_kurucz = H_kurucz - Kp_kurucz HKp_castelli = H_castelli - Kp_castelli HKp_nextgen = H_nextgen - Kp_nextgen KpLp_kurucz = Kp_kurucz - Lp_kurucz KpLp_castelli = Kp_castelli - Lp_castelli KpLp_nextgen = Kp_nextgen - Lp_nextgen py.clf() py.plot(temp, JKp_castelli - JKp_kurucz, 'r.', label='Castelli - Kurucz') py.plot(temp, JKp_nextgen - JKp_kurucz, 'b.', label='NextGen - Kurucz') py.plot(temp, JKp_nextgen - JKp_castelli, 'g.', label='NextGen - Castelli') py.xlabel('Effective Temperature (deg)') py.ylabel('J - Kp Color Difference') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) py.legend(numpoints=1, loc='upper left') py.savefig(outdir + 'diff_j_kp' + outsuffix) py.xlim(3000, 10000) py.ylim(-0.2, 0.2) py.savefig(outdir + 'diff_j_kp_zoom' + outsuffix) py.clf() py.plot(temp, HKp_castelli - HKp_kurucz, 'r.', label='Castelli - Kurucz') py.plot(temp, HKp_nextgen - HKp_kurucz, 'b.', label='NextGen - Kurucz') py.plot(temp, HKp_nextgen - HKp_castelli, 'g.', label='NextGen - Castelli') py.xlabel('Effective Temperature (deg)') py.ylabel('H - Kp Color Difference') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) py.legend(numpoints=1, loc='upper left') py.savefig(outdir + 'diff_h_kp' + outsuffix) py.xlim(3000, 10000) py.ylim(-0.2, 0.2) py.savefig(outdir + 'diff_h_kp_zoom' + outsuffix) py.clf() py.plot(temp, KpLp_castelli - KpLp_kurucz, 'r.', label='Castelli - Kurucz') py.plot(temp, KpLp_nextgen - KpLp_kurucz, 'b.', label='NextGen - Kurucz') py.plot(temp, KpLp_nextgen - KpLp_castelli, 'g.', label='NextGen - Castelli') py.xlabel('Effective Temperature (deg)') py.ylabel('Kp - Lp Color Difference') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) py.legend(numpoints=1, loc='upper left') py.savefig(outdir + 'diff_kp_lp' + outsuffix) py.xlim(3000, 10000) py.ylim(-0.2, 0.2) py.savefig(outdir + 'diff_kp_lp_zoom' + outsuffix) # Plot the color-magnitude diagrams for each. Rather than the differences. py.clf() py.semilogx(temp, J_kurucz, 'r.', label='Kurucz') py.plot(temp, J_castelli, 'b.', label='Castelli') py.plot(temp, J_nextgen, 'g.', label='NextGen') py.xlabel('Effective Temperature (deg)') py.ylabel('J Magnitude') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) rng = py.axis() py.axis([rng[1], rng[0], rng[3], rng[2]]) py.legend(numpoints=1, loc='lower left') py.savefig(outdir + 'temp_j' + outsuffix) py.clf() py.semilogx(temp, H_kurucz, 'r.', label='Kurucz') py.plot(temp, H_castelli, 'b.', label='Castelli') py.plot(temp, H_nextgen, 'g.', label='NextGen') py.xlabel('Effective Temperature (deg)') py.ylabel('H Magnitude') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) rng = py.axis() py.axis([rng[1], rng[0], rng[3], rng[2]]) py.legend(numpoints=1, loc='lower left') py.savefig(outdir + 'temp_h' + outsuffix) py.clf() py.semilogx(temp, Kp_kurucz, 'r.', label='Kurucz') py.plot(temp, Kp_castelli, 'b.', label='Castelli') py.plot(temp, Kp_nextgen, 'g.', label='NextGen') py.xlabel('Effective Temperature (deg)') py.ylabel('Kp Magnitude') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) rng = py.axis() py.axis([rng[1], rng[0], rng[3], rng[2]]) py.legend(numpoints=1, loc='lower left') py.savefig(outdir + 'temp_kp' + outsuffix) py.clf() py.semilogx(temp, Lp_kurucz, 'r.', label='Kurucz') py.plot(temp, Lp_castelli, 'b.', label='Castelli') py.plot(temp, Lp_nextgen, 'g.', label='NextGen') py.xlabel('Effective Temperature (deg)') py.ylabel('Lp Magnitude') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) rng = py.axis() py.axis([rng[1], rng[0], rng[3], rng[2]]) py.legend(numpoints=1, loc='lower left') py.savefig(outdir + 'temp_lp' + outsuffix) py.clf() py.semilogx(temp, JKp_kurucz, 'r.', label='Kurucz') py.plot(temp, JKp_castelli, 'b.', label='Castelli') py.plot(temp, JKp_nextgen, 'g.', label='NextGen') py.xlabel('Effective Temperature (deg)') py.ylabel('J - Kp Color') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) rng = py.axis() py.xlim(rng[1], rng[0]) py.legend(numpoints=1, loc='lower left') py.savefig(outdir + 'temp_jkp' + outsuffix) py.clf() py.semilogx(temp, HKp_kurucz, 'r.', label='Kurucz') py.plot(temp, HKp_castelli, 'b.', label='Castelli') py.plot(temp, HKp_nextgen, 'g.', label='NextGen') py.xlabel('Effective Temperature (deg)') py.ylabel('H - Kp Color') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) rng = py.axis() py.xlim(rng[1], rng[0]) py.legend(numpoints=1, loc='lower left') py.savefig(outdir + 'temp_hkp' + outsuffix) py.clf() py.semilogx(temp, KpLp_kurucz, 'r.', label='Kurucz') py.plot(temp, KpLp_castelli, 'b.', label='Castelli') py.plot(temp, KpLp_nextgen, 'g.', label='NextGen') py.xlabel('Effective Temperature (deg)') py.ylabel('Kp - Lp Color') py.title('Distance = %.1f logAge = %.2f' % (distance / 10**3, logAge)) rng = py.axis() py.xlim(rng[1], rng[0]) py.legend(numpoints=1, loc='lower left') py.savefig(outdir + 'temp_kplp' + outsuffix)
def _getWeights(self, source=None, nlambda=5, monochromatic=None, verbose=False): """ Return the set of discrete wavelengths, and weights for each wavelength, that should be used for a PSF calculation. Uses pysynphot (if installed), otherwise assumes simple-minded flat spectrum """ if monochromatic is not None: poppy_core._log.info(" monochromatic calculation requested.") return (np.asarray([monochromatic]), np.asarray([1]) ) elif _HAS_PYSYNPHOT and (isinstance(source, pysynphot.spectrum.SourceSpectrum) or source is None): """ Given a pysynphot.SourceSpectrum object, perform synthetic photometry for nlambda bins spanning the wavelength range of interest. Because this calculation is kind of slow, cache results for reuse in the frequent case where one is computing many PSFs for the same spectral source. """ poppy_core._log.debug("Calculating spectral weights using pysynphot, nlambda=%d, source=%s" % (nlambda, str(source))) if source is None: try: source = pysynphot.Icat('ck04models',5700,0.0,2.0) except: poppy_core._log.error("Could not load Castelli & Kurucz stellar model from disk; falling back to 5700 K blackbody") source = pysynphot.BlackBody(5700) poppy_core._log.debug("Computing spectral weights for source = "+str(source)) try: key = self._getSpecCacheKey(source, nlambda) if key in self._spectra_cache.keys(): poppy_core._log.debug("Previously computed spectral weights found in cache, just reusing those") return self._spectra_cache[keys] except: pass # in case sourcespectrum lacks a name element so the above lookup fails - just do the below calc. poppy_core._log.info("Computing wavelength weights using synthetic photometry for %s..." % self.filter) band = self._getSynphotBandpass(self.filter) # choose reasonable min and max wavelengths w_above10 = np.where(band.throughput > 0.10*band.throughput.max()) minwave = band.wave[w_above10].min() maxwave = band.wave[w_above10].max() poppy_core._log.debug("Min, max wavelengths = %f, %f" % (minwave/1e4, maxwave/1e4)) wave_bin_edges = np.linspace(minwave,maxwave,nlambda+1) wavesteps = (wave_bin_edges[:-1] + wave_bin_edges[1:])/2 deltawave = wave_bin_edges[1]-wave_bin_edges[0] effstims = [] for wave in wavesteps: poppy_core._log.debug("Integrating across band centered at %.2f microns with width %.2f" % (wave/1e4,deltawave/1e4)) box = pysynphot.Box(wave, deltawave) * band if box.throughput.max() == 0: # watch out for pathological cases with no overlap (happens with MIRI FND at high nlambda) result = 0.0 else: binset = np.linspace(wave-deltawave, wave+deltawave, 30) # what wavelens to use when integrating across the sub-band? result = pysynphot.Observation(source, box, binset=binset).effstim('counts') effstims.append(result) effstims = np.array(effstims) effstims /= effstims.sum() wave_m = band.waveunits.Convert(wavesteps,'m') # convert to meters newsource = (wave_m, effstims) if verbose: _log.info( " Wavelengths and weights computed from pysynphot: "+str( newsource)) self._spectra_cache[ self._getSpecCacheKey(source,nlambda)] = newsource return newsource elif isinstance(source, dict) and ('wavelengths' in source) and ('weights' in source): # Allow providing directly a set of specific weights and wavelengths, as in poppy.calcPSF source option #2 return (source['wavelengths'], source['weights']) elif isinstance(source, tuple) and len(source) == 2: # Allow user to provide directly a tuple, as in poppy.calcPSF source option #3 return source else: #Fallback simple code for if we don't have pysynphot. poppy_core._log.warning("Pysynphot unavailable (or invalid source supplied)! Assuming flat # of counts versus wavelength.") # compute a source spectrum weighted by the desired filter curves. # The existing FITS files all have wavelength in ANGSTROMS since that is the pysynphot convention... filterfile = self._filters[self.filter].filename filterfits = fits.open(filterfile) filterdata = filterfits[1].data try: f1 = filterdata.WAVELENGTH d2 = filterdata.THROUGHPUT except: raise ValueError("The supplied file, {0}, does not appear to be a FITS table with WAVELENGTH and THROUGHPUT columns.".format(filterfile)) if 'WAVEUNIT' in filterfits[1].header.keys(): waveunit = filterfits[1].header['WAVEUNIT'] if re.match(r'[Aa]ngstroms?', waveunit) is None: raise ValueError("The supplied file, {0}, has WAVEUNIT='{1}'. Only WAVEUNIT = Angstrom supported when Pysynphot is not installed.".format(filterfile, waveunit)) else: poppy_core._log.warn("CAUTION: no WAVEUNIT keyword found in filter file {0}. Assuming = Angstroms by default".format(filterfile)) waveunit = 'Angstrom' poppy_core._log.warn("CAUTION: Just interpolating rather than integrating filter profile, over {0} steps".format(nlambda)) wtrans = np.where(filterdata.THROUGHPUT > 0.4) lrange = filterdata.WAVELENGTH[wtrans] * 1e-10 # convert from Angstroms to Meters lambd = np.linspace(np.min(lrange), np.max(lrange), nlambda) filter_fn = scipy.interpolate.interp1d(filterdata.WAVELENGTH * 1e-10, filterdata.THROUGHPUT, kind='cubic', bounds_error=False) weights = filter_fn(lambd) return lambd, weights
def airy_model_residuals(params,*args,**kwargs): """ Residual function for an L-M fit (i.e. scipy.optimize.least_squares). Params: [plate_scale, psf_radius, stellar_teff,flux,ycentre,xcentre] If extra parameters are given to this function, more things will be fit: [plate_scale, psf_radius, stellar_teff,flux,ycentre,xcentre, filter_centre,RV] Units: [arcsec/pix, pixels, K, ~max counts in image, pixels, pixels, metres, km/s] if kwargs['filter_centre'] or kwargs['RV'] are set, they will _not_ be fit, and the value in kwargs will be used instead. Setting kwargs['mask'] will return residuals[mask] """ # Unpack everything image = kwargs['image'] aperture = kwargs['aperture'] wavs = kwargs['wavs'] if 'cutout_sz' in kwargs.keys(): cutout_sz = kwargs['cutout_sz'] else: cutout_sz = 50 if 'debug' in kwargs.keys(): print(params) npix = image.shape[0] # assume square nwavs = wavs.size plate_scale = params[0] psf_radius = params[1] # Use a Phoenix spectrum and the filter stellar_teff = params[2] flux = params[3] if 'filter_centre' in kwargs.keys(): filter_centre = kwargs['filter_centre'] elif len(params) > 6: filter_centre = params[6] else: filter_centre = 550e-9 # m if 'RV' in kwargs.keys(): rv = kwargs['RV'] elif len(params) > 7: rv = params[7] else: rv = 0. # km/s source_rest_wavs = wavs/(1+rv*u.km/u.s/constants.c) acenA = S.Icat('phoenix',stellar_teff,0.2,4.3) specA = acenA.sample(source_rest_wavs*1e10) # This needs angstroms as input if 'filter_sigma' in kwargs.keys(): filter_sigma = kwargs['filter_sigma'] else: filter_sigma = 105e-9 if 'filter_n' in kwargs.keys(): filter_n = kwargs['filter_n'] else: filter_n = 8 filter_spec = supergaussian(wavs,filter_centre,sigma=filter_sigma,n=filter_n) spectrum = filter_spec*specA spectrum *= flux/np.max(spectrum) # Calculate model image model = airy_model_image(npix,wavs,spectrum,psf_radius,aperture,plate_scale,offset=params[4:6],cutout_sz=cutout_sz) resids = image-model if 'mask' in kwargs.keys(): resids = resids[kwargs['mask']] return resids.ravel()
def generate_PSF(img, outdir, nruns, x0, y0, grid_step, side, max_step, sigmaTA, sigmaFSM, mask_coron, pupil_stop, lambda0, jitter, rms, fovarcsec): src=pysynphot.Icat("ck04models",5800, 0.0, 4.44) #temp, z, logg print src njitter=50 #number of PSF to use to create the final jittered PSF for n in xrange(1,nruns+1): grid = make_ref_grid(n, outdir, x0, y0, side, max_step, grid_step, sigmaTA, sigmaFSM) ######################################### # GENERATE PSF FOR EACH POSITION IN GRID ######################################### for isgd in xrange(len(grid)+1): if isgd==0 : label='Unocculted' elif isgd==1 : label='ScienceTarget' elif isgd==2 : label='ReferenceTarget' else: label='Reference_dither%i' %(isgd-2) output_name='PSF_%i_run%i_%s_%i.fits' %(np.round(lambda0*100),n,label,rms) if isgd==0: img.image_mask=None else: img.image_mask=mask_coron img.pupil_mask=pupil_stop if isgd == 0 or isgd == 1: currentPointing=grid[0] else: currentPointing = grid[isgd-1] offset= np.sqrt(np.sum( currentPointing**2 ) )/1000 offset_theta= -np.arctan2(currentPointing[0],currentPointing[1])*180/math.pi img.options['source_offset_r'] = offset # offset in arcseconds img.options['source_offset_theta'] = offset_theta # degrees counterclockwise from instrumental +Y in the science frame print isgd,output_name, currentPointing, offset,offset_theta,"\n" psf = img.calcPSF(source=src, fft_oversample=4, detector_oversample= 1, fov_arcsec=fovarcsec ) #fov_pixels=fovpixels) finalPSF = psf[0].data hdr = psf[0].header string="LAJOIE: optimal source offset for bar occulter: %f arcseconds" %x0 hdr.add_history(string) string="LAJOIE: actual radial offset is %f arcseconds" %offset hdr.add_history(string) string="LAJOIE: actual angular offset is %f degrees" %offset_theta hdr.add_history(string) if img.image_mask==None : hdr.set("CORONMSK",img.image_mask,before='PUPIL') if jitter!=0: sumPSF=finalPSF for j in xrange(njitter): jitter_pos=np.array([np.random.normal(currentPointing[0],jitter),np.random.normal(currentPointing[1],jitter)]) off_jitt = np.sqrt(np.sum( jitter_pos**2 ) )/1000 # arcseconds off_jitt_theta =-np.arctan2(jitter_pos[0],jitter_pos[1])*180/math.pi # degrees img.options['source_offset_r'] = off_jitt # offset in arcseconds img.options['source_offset_theta'] = off_jitt_theta # degrees counterclockwise from instrumental +Y in the science frame tmp=img.calcPSF(source=src, fft_oversample=4, detector_oversample= 1, fov_arcsec=fovarcsec) #fov_pixels=fovpixels) sumPSF+=tmp[0].data finalPSF=sumPSF/(njitter+1) string="LAJOIE: Jitter (%4.1f mas 1-sigma/axis) included, %d points drawn from Gaussian dist." %(jitter,njitter) hdr.add_history(string) else: hdr.add_history("LAJOIE: No jitter included") ########################## # WRITE OUTPUT IMAGE ########################## outHDU=astropy.io.fits.PrimaryHDU(data=finalPSF, header=hdr ) outHDU.writeto(outdir+output_name) return
def outTrans(input) : """Compute out of transit spectra Computes the out of transit spectra by normalizing flux to specified magnitude and convert to specified Pandeia units of milliJy and microns. Parameters ---------- input : dict stellar scene which includes parameters to extract phoenix database or a filename which points to a stellar spectrum Return ------ dict contains wave and flux_out_trans """ if input['type'] == 'user': star = np.genfromtxt(input['starpath'], dtype=(float, float), names='w, f') #pyfits.getdata(input['starpath'],1) #get flux flux = star['f'] #star.field(input['logg']) #get wavelength and reference wavelength for mag normalization wave = star['w'] #star.field('WAVELENGTH') #sort if not in ascending order sort = np.array([wave,flux]).T sort= sort[sort[:,0].argsort()] wave = sort[:,0] flux = sort[:,1] sp=np.nan elif input['type'] =='phoenix': #make sure metal is not out of bounds if input['metal'] > 0.5: input['metal'] = 0.5 sp = psyn.Icat("phoenix", input['temp'], input['metal'], input['logg']) sp.convert("microns") sp.convert("jy") wave = sp.wave flux = sp.flux input['w_unit'] ='um' input['f_unit'] = 'Jy' else: raise Exception('Wrong input type for stellar spectra') ref_wave = float(input['ref_wave']) ref_wave = ref_wave*1e3 #Convert evrything to nanometer for converstion based on gemini.edu if input['w_unit'] == 'um': wave = wave*1e3 elif input['w_unit'] == 'nm': wave = wave elif input['w_unit'] == 'cm' : wave = wave*1e7 elif input['w_unit'] == 'Angs' : wave = wave*1e-1 elif input['w_unit'] == 'Hz' : wave = 3e17/wave else: raise Exception('Units are not correct. Pick um, nm, cm or Angs') #convert to photons/s/nm/m^2 for flux normalization based on #http://www.gemini.edu/sciops/instruments/integration-time-calculators/itc-help/source-definition if input['f_unit'] == 'Jy': flux = flux*1.509e7/wave #eq. C elif input['f_unit'] == 'W/m2/um': flux = flux*wave/1.988e-13 #eq. D elif input['f_unit'] == 'FLAM' : flux = flux*wave/1.988e-14 #eq. E elif input['f_unit'] == 'erg/s/cm2/Hz': flux = flux*1.509e30/wave #*4.0*np.pi else: raise Exception('Units are not correct. Pick W/m2/um, FLAM, Jy, or erg/s/cm2/Hz') #normalize to specific mag mag = float(input['mag']) norm_flux = np.interp(ref_wave, wave, flux) #get zero point for J H and K if (ref_wave <= 1.3e3) & (ref_wave >= 1.2e3): zeropoint = 1.97e7 elif (ref_wave <= 1.7e3) & (ref_wave >= 1.6e3): zeropoint = 9.6e6 elif (ref_wave <= 2.3e3) & (ref_wave >= 2.1e3): zeropoint = 4.5e6 else: raise Exception('Only J H and K zeropoints are included') flux = flux/norm_flux*zeropoint*10**(-mag/2.5) #return to Pandeia units... milliJy and micron flux_out_trans = flux*wave/1.509e7*1e3 #inverse of eq. C times 1e3 to get to milliJy instead of Jy wave = wave*1e-3 #nm to micron return {'flux_out_trans': flux_out_trans, 'wave': wave,'phoenix':sp}
def outTrans(input): """Compute out of transit spectra Computes the out of transit spectra by normalizing flux to specified magnitude and convert to specified Pandeia units of milliJy and microns. Parameters ---------- input : dict stellar scene which includes parameters to extract phoenix database or a filename which points to a stellar spectrum Return ------ dict contains wave and flux_out_trans """ ref_wave = float(input['ref_wave']) mag = float(input['mag']) ################# USER #################################### if input['type'] == 'user': star = np.genfromtxt( input['starpath'], dtype=(float, float), names='w, f') #pyfits.getdata(input['starpath'],1) #get flux flux = star['f'] #star.field(input['logg']) #get wavelength and reference wavelength for mag normalization wave = star['w'] #star.field('WAVELENGTH') #sort if not in ascending order sort = np.array([wave, flux]).T sort = sort[sort[:, 0].argsort()] wave = sort[:, 0] flux = sort[:, 1] if input['w_unit'] == 'um': PANDEIA_WAVEUNITS = 'um' elif input['w_unit'] == 'nm': PANDEIA_WAVEUNITS = 'nm' elif input['w_unit'] == 'cm': PANDEIA_WAVEUNITS = 'cm' elif input['w_unit'] == 'Angs': PANDEIA_WAVEUNITS = 'angstrom' elif input['w_unit'] == 'Hz': PANDEIA_WAVEUNITS = 'Hz' else: raise Exception( 'Units are not correct. Pick um, nm, cm, hz, or Angs') #convert to photons/s/nm/m^2 for flux normalization based on #http://www.gemini.edu/sciops/instruments/integration-time-calculators/itc-help/source-definition if input['f_unit'] == 'Jy': PANDEIA_FLUXUNITS = 'jy' elif input['f_unit'] == 'FLAM': PANDEIA_FLUXUNITS = 'FLAM' else: raise Exception('Units are not correct. Pick FLAM or Jy') sp = psyn.ArraySpectrum( wave, flux, waveunits=PANDEIA_WAVEUNITS, fluxunits=PANDEIA_FLUXUNITS ) #Convert evrything to nanometer for converstion based on gemini.edu sp.convert("nm") sp.convert('jy') ############ PHOENIX ################################################ elif input['type'] == 'phoenix': #make sure metal is not out of bounds if input['metal'] > 0.5: input['metal'] = 0.5 sp = psyn.Icat("phoenix", input['temp'], input['metal'], input['logg']) sp.convert("nm") sp.convert("jy") wave = sp.wave flux = sp.flux input['w_unit'] = 'nm' input['f_unit'] = 'jy' else: raise Exception('Wrong input type for stellar spectra') ############ NORMALIZATION ################################################ refdata = os.environ.get("pandeia_refdata") all_bps = { "H": 'bessell_h_004_syn.fits', "J": 'bessell_j_003_syn.fits', "K": 'bessell_k_003_syn.fits' } if (ref_wave <= 1.3) & (ref_wave >= 1.2): filt = 'J' elif (ref_wave <= 1.7) & (ref_wave >= 1.6): filt = 'H' elif (ref_wave <= 2.3) & (ref_wave >= 2.1): filt = 'K' else: raise Exception('Only J H and K zeropoints are included') bp_path = os.path.join(refdata, "normalization", "bandpass", all_bps[filt]) bp = psyn.FileBandpass(bp_path) sp.convert('angstroms') bp.convert('angstroms') rn_sp = sp.renorm(mag, 'vegamag', bp) rn_sp.convert("microns") rn_sp.convert("mjy") flux_out_trans = rn_sp.flux wave = rn_sp.wave return {'flux_out_trans': flux_out_trans, 'wave': wave, 'phoenix': sp}