Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
    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()
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
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
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
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()
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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"
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
 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
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
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
Ejemplo n.º 18
0
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
Ejemplo n.º 19
0
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
Ejemplo n.º 20
0
 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
Ejemplo n.º 21
0
 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
Ejemplo n.º 22
0
    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
Ejemplo n.º 23
0
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
Ejemplo n.º 24
0
 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
Ejemplo n.º 25
0
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)
Ejemplo n.º 26
0
    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
Ejemplo n.º 27
0
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()
Ejemplo n.º 28
0
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
Ejemplo n.º 29
0
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} 
Ejemplo n.º 30
0
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}