Raw File
sky.py
import numpy           as np
import glob            as gb
import collections     as cl
import sys             as sy
import                    os
import                    io
import src.foregrounds as fg
import src.units       as un

#Pickling is different between Python 2 and 3
PY2 = (sy.version_info[0] == 2)
if PY2: import cPickle as pk
else:   import pickle  as pk

class Sky:
    def __init__(self, log, nrealize=1, fgndDict=None, atmFile=None, site=None, pwv=None, pwvDict=None, foregrounds=False):
        #Store passed parameters
        self.log      = log
        self.nrealize = nrealize
        self.fgndDict = fgndDict
        self.atmFile   = atmFile
        self.site      = site
        self.pwv       = pwv
        self.pwvDict   = pwvDict
        self.inclF    = foregrounds

        #Store global parameters
        self.fg       = fg.Foregrounds(self.log, fgndDict=fgndDict, nrealize=nrealize)
        self.nfiles   = 20 #Number of files to break the atmDict.pkl file into
        self.medianPwv = 0.934 #Atacama, as defined by the MERRA-2 dataset
        self.maxPWV    = 8.0
        self.minPWV    = 0.0
        self.atmDir    = os.path.join(os.path.split(__file__)[0], 'atmFiles')
        self.siteDirs  = sorted(gb.glob(os.path.join(self.atmDir, '*'+os.sep)))
        self.siteNames = np.array([siteDir.split(os.sep)[-2] for siteDir in self.siteDirs])
        self.siteDirs  = cl.OrderedDict({self.siteNames[i]: self.siteDirs[i] for i in range(len(self.siteNames))})

        if not self.site.upper() == 'SPACE':
            self.__initATM(create=False)

    #***** Public methods ******
    #Sample PWV distribution
    def pwvSample(self):
        if self.pwv is not None: return self.pwv
        if self.pwvDict is None: return None
        #samp = np.random.choice(np.array(self.pwvDict.keys()).astype(np.float), size=1, p=np.array(self.pwvDict.values()).astype(np.float)/np.sum(np.array(self.pwvDict.values()).astype(np.float)))[0]
        samp = np.random.choice(np.fromiter(self.pwvDict.keys(), dtype=np.float), size=1, p=np.fromiter(self.pwvDict.values(), dtype=np.float)/np.sum(np.fromiter(self.pwvDict.values(), dtype=np.float)))[0]
        if samp < self.minPWV:
            self.log.log('Cannot have PWV %.1f < %.1f. Using %.1f instead' % (samp, self.minPWV, self.minPWV), 2)
            return self.minPWV
        elif samp > self.maxPWV:
            self.log.log('Cannot have PWV %.1f > %.1f. Using %.1f instead' % (samp, self.maxPWV, self.maxPWV), 2)
            return self.maxPWV
        else:
            return samp
    #Retrieve user-defined PWV value
    def getPwv(self):
        return self.pwv
    #Retrieve ATM spectrum given some PWV, elevation, and array of frequencies
    def atmSpectrum(self, pwv, elev, freqs):
        if self.atmFile:
            self.log.log('Using provided ATM file -- ignoring provided PWV and El (%.1f, %.1f)' % (pwv, elev), 1)
            freq, temp, tran = np.loadtxt(self.atmFile, unpack=True, usecols=[0, 2, 3], dtype=np.float)
        else:
            freq, temp, tran = self.atmDict[(int(round(elev,0)), round(pwv,1))]
        freq = freq*un.GHzToHz; temp = np.interp(freqs, freq, temp); tran = np.interp(freqs, freq, tran)
        return freq.flatten().tolist(), temp.flatten().tolist(), tran.flatten().tolist()
    #Retrieve synchrotron spectrum given some array of frequencies
    def synSpectrum(self, freqs):
        return self.fg.syncSpecRad(1.0, freqs)
    #Retrieve dust spectrum given some array of frequencies
    def dstSpectrum(self, freqs):
        return self.fg.dustSpecRad(1.0, freqs)
    #Generate the sky
    def generate(self, pwv, elev, freqs):
        self.Ncmb = ['CMB' for f in freqs]; self.Tcmb = [2.725 for f in freqs]; self.Ecmb = [1. for f in freqs]; self.Acmb = [1. for f in freqs]
        if not self.site.upper() == 'SPACE':
            self.Natm = ['ATM' for f in freqs]; freq, self.Tatm, self.Eatm = self.atmSpectrum(pwv, elev, freqs);     self.Aatm = [1. for f in freqs]
        if self.inclF:
            self.Nsyn = ['SYNC' for f in freqs]; self.Tsyn = self.synSpectrum(freqs); self.Esyn = [1. for f in freqs]; self.Asyn = [1. for f in freqs]
            self.Ndst = ['DUST' for f in freqs]; self.Tdst = self.dstSpectrum(freqs); self.Edst = [1. for f in freqs]; self.Adst = [1. for f in freqs]
            if not self.site.upper() == 'SPACE':
                return ([self.Ncmb, self.Nsyn, self.Ndst, self.Natm],
                        [self.Acmb, self.Asyn, self.Adst, self.Aatm],
                        [self.Ecmb, self.Esyn, self.Edst, self.Eatm],
                        [self.Tcmb, self.Tsyn, self.Tdst, self.Tatm])
            else:
                return ([self.Ncmb, self.Nsyn, self.Ndst],
                        [self.Acmb, self.Asyn, self.Adst],
                        [self.Ecmb, self.Esyn, self.Edst],
                        [self.Tcmb, self.Tsyn, self.Tdst])                
        else:
            if not self.site.upper() == 'SPACE':
                return ([self.Ncmb, self.Natm],
                        [self.Acmb, self.Aatm],
                        [self.Ecmb, self.Eatm],
                        [self.Tcmb, self.Tatm])
            else:
                return ([self.Ncmb],
                        [self.Acmb],
                        [self.Ecmb],
                        [self.Tcmb])                

    #***** Private methods *****
    #Initialize atmosphere. If "create" is True, then create pickle files from text files of spectra
    def __initATM(self, create=False):
        if create:
            atmFileArrs    = cl.OrderedDict({site: np.array(sorted(gb.glob(os.path.join(self.siteDirs[site], 'TXT', 'atm*.txt'))))        for site in self.siteNames})
            self.elevArrs  = cl.OrderedDict({site: np.array([float(os.path.split(atmFile)[-1].split('_')[1][:2])                          for atmFile in atmFileArrs[site]]) for site in self.siteNames})
            self.pwvArrs   = cl.OrderedDict({site: np.array([float(os.path.split(atmFile)[-1].split('_')[2][:4])*1.e-3                    for atmFile in atmFileArrs[site]]) for site in self.siteNames})
            self.atmDicts = cl.OrderedDict({})
            for site in self.siteNames:
                freqArr, tempArr, tranArr = np.hsplit(np.array([np.loadtxt(atmFile, usecols=[0, 2, 3], unpack=True) for atmFile in atmFileArrs[site]]), 3)
                self.atmDicts[site] = cl.OrderedDict({(int(round(self.elevArrs[site][i])), round(self.pwvArrs[site][i],1)): (freqArr[i][0], tempArr[i][0], tranArr[i][0]) for i in range(len(atmFileArrs[site]))})
                for i in range(self.nfiles):        
                    sub_dict = self.atmDicts[site].items()[i::self.nfiles]
                    pk.dump(sub_dict, open(os.path.join(self.siteDirs[site], 'PKL', ('atmDict_%d.pkl' % (i))), 'wb'))
            self.atmDict = self.atmDicts[self.site]
        else:
            #self.atmDict = cl.OrderedDict({})
            self.atmDict = {}
            
            for i in range(self.nfiles):
                if PY2: sub_dict = pk.load(open(os.path.join(self.siteDirs[self.site], 'PKL', ('atmDict_%d.pkl' % (i))), 'rb'))
                else:   sub_dict = pk.load(io.open(os.path.join(self.siteDirs[self.site], 'PKL', ('atmDict_%d.pkl' % (i))), 'rb'), encoding='latin1')
                self.atmDict.update(sub_dict)
back to top