Esempio n. 1
0
 def setup_Throughputs(self, rootDir=None, verbose=True):
     """Read bandpasses and dark sky sed.
     Call this method first before doing anything else. """
     self.filterlist = ('u', 'g', 'r', 'i', 'z', 'y')
     if rootDir == None:
         rootDir = os.getenv('LSST_THROUGHPUTS_DEFAULT')            
     if rootDir == None:
         raise Exception('Either provide "rootDir" or set $LSST_THROUGHPUTS_DEFAULT')
     # Read in the total transmission curves. 
     self.lsst = {}
     hardwarecomponentlist = ['detector.dat','lens1.dat', 'lens2.dat', 'lens3.dat',
                              'm1.dat', 'm2.dat', 'm3.dat']
     commoncomponentlist = hardwarecomponentlist + ['atmos_10.dat',]
     for f in self.filterlist:
         componentlist = commoncomponentlist + ['filter_' +f +'.dat',]
         self.lsst[f] = Bandpass()
         self.lsst[f].readThroughputList(componentlist, rootDir=rootDir, verbose=verbose)
     # Read in the hardware-only transmission curves (no atmosphere).
     self.hardware = {}
     for f in self.filterlist:
         componentlist = hardwarecomponentlist + ['filter_' +f +'.dat',]
         self.hardware[f] = Bandpass()
         self.hardware[f].readThroughputList(componentlist, rootDir=rootDir, verbose=verbose)
     # Read in the dark sky SED.
     darkskyfile = 'darksky.dat'
     self.darksky = Sed()
     self.darksky.readSED_flambda(os.path.join(rootDir, darkskyfile))
     # Set up a flat SED.
     self.flatsed = Sed()
     self.flatsed.setFlatSED()
     return        
def ImportSEDfits(filename):
    sed = Sed()
    fits = pyfits.open(filename)
    crdelt = fits[0].header['CDELT1'] * .1 #Converts Angstroms to nanometers
    crval = fits[0].header['CRVAL1'] * .1 #same
    length = len(fits[0].data)
    wavelen = np.arange(crval,crval+length*crdelt,crdelt)
    sed.setSED(wavelen, fits[0].data)
    return(sed)
Esempio n. 3
0
def ImportSEDfits(filename):
    sed = Sed()
    fits = pyfits.open(filename)
    crdelt = fits[0].header['CDELT1'] * .1  #Converts Angstroms to nanometers
    crval = fits[0].header['CRVAL1'] * .1  #same
    length = len(fits[0].data)
    wavelen = np.arange(crval, crval + length * crdelt, crdelt)
    sed.setSED(wavelen, fits[0].data)
    return (sed)
Esempio n. 4
0
 def setup_Throughputs(self, rootDir=None, verbose=True):
     """Read bandpasses and dark sky sed.
     Call this method first before doing anything else. """
     self.filterlist = ('u', 'g', 'r', 'i', 'z', 'y')
     if rootDir == None:
         rootDir = os.getenv('LSST_THROUGHPUTS_DEFAULT')
     if rootDir == None:
         raise Exception(
             'Either provide "rootDir" or set $LSST_THROUGHPUTS_DEFAULT')
     # Read in the total transmission curves.
     self.lsst = {}
     hardwarecomponentlist = [
         'detector.dat', 'lens1.dat', 'lens2.dat', 'lens3.dat', 'm1.dat',
         'm2.dat', 'm3.dat'
     ]
     commoncomponentlist = hardwarecomponentlist + [
         'atmos_10.dat',
     ]
     for f in self.filterlist:
         componentlist = commoncomponentlist + [
             'filter_' + f + '.dat',
         ]
         self.lsst[f] = Bandpass()
         self.lsst[f].readThroughputList(componentlist,
                                         rootDir=rootDir,
                                         verbose=verbose)
     # Read in the hardware-only transmission curves (no atmosphere).
     self.hardware = {}
     for f in self.filterlist:
         componentlist = hardwarecomponentlist + [
             'filter_' + f + '.dat',
         ]
         self.hardware[f] = Bandpass()
         self.hardware[f].readThroughputList(componentlist,
                                             rootDir=rootDir,
                                             verbose=verbose)
     # Read in the dark sky SED.
     darkskyfile = 'darksky.dat'
     self.darksky = Sed()
     self.darksky.readSED_flambda(os.path.join(rootDir, darkskyfile))
     # Set up a flat SED.
     self.flatsed = Sed()
     self.flatsed.setFlatSED()
     return
 def calcZP_t(self, expTime=PhotometricDefaults.exptime,
              effarea=PhotometricDefaults.effarea,
              gain=PhotometricDefaults.gain):
     """
     Calculate the instrumental zeropoint for a bandpass.
     """
     # ZP_t is the magnitude of a (F_nu flat) source which produced 1 count per second.
     # This is often also known as the 'instrumental zeropoint'.
     # Set gain to 1 if want to explore photo-electrons rather than adu.
     # The typical LSST exposure time is 15s and this is default here, but typical zp_t definition is for 1s.
     # SED class uses flambda in ergs/cm^2/s/nm, so need effarea in cm^2.
     #
     # Check dlambda value for integral.
     dlambda = self.wavelen[1] - self.wavelen[0]
     # Set up flat source of arbitrary brightness,
     #   but where the units of fnu are Jansky (for AB mag zeropoint = -8.9).
     flatsource = Sed()
     flatsource.setFlatSED(wavelen_min=self.wavelen_min, wavelen_max=self.wavelen_max,
                           wavelen_step=self.wavelen_step)
     adu = flatsource.calcADU(self, expTime=expTime, effarea=effarea, gain=gain)
     # Scale fnu so that adu is 1 count/expTime.
     flatsource.fnu = flatsource.fnu * (1/adu)
     # Now need to calculate AB magnitude of the source with this fnu.
     if self.phi is None:
         self.sbTophi()
     zp_t = flatsource.calcMag(self)
     return zp_t
    def calcM5(self, skysed, hardware, expTime=PhotometricDefaults.exptime,
               nexp=PhotometricDefaults.nexp, readnoise=PhotometricDefaults.rdnoise,
               darkcurrent=PhotometricDefaults.darkcurrent,
               othernoise=PhotometricDefaults.othernoise,
               seeing=PhotometricDefaults.seeing['r'], platescale=PhotometricDefaults.platescale,
               gain=PhotometricDefaults.gain, effarea=PhotometricDefaults.effarea):
        """
        Calculate the AB magnitude of a 5-sigma above sky background source.

        Pass into this function the bandpass, hardware only of bandpass, and sky sed objects.
        The exposure time, nexp, readnoise, darkcurrent, gain,
        seeing and platescale are also necessary.
        """
        #This comes from equation 45 of the SNR document (v1.2, May 2010)
        #www.astro.washington.edu/users/ivezic/Astr511/LSST_SNRdoc.pdf

        #create a flat fnu source
        flatsource = Sed()
        flatsource.setFlatSED(wavelen_min=self.wavelen_min, wavelen_max=self.wavelen_max,
                              wavelen_step=self.wavelen_step)
        snr = 5.0
        v_n, noise_instr_sq, \
        noise_sky_sq, noise_skymeasurement_sq, \
        skycounts, neff = flatsource.calcNonSourceNoiseSq(skysed, hardware, readnoise,
                                                          darkcurrent, othernoise, seeing,
                                                          effarea, expTime, nexp, platescale,
                                                          gain)

        counts_5sigma = (snr**2)/2.0/gain + numpy.sqrt((snr**4)/4.0/gain + (snr**2)*v_n)

        #renormalize flatsource so that it has the required counts to be a 5-sigma detection
        #given the specified background
        counts_flat = flatsource.calcADU(self, expTime=expTime*nexp, effarea=effarea, gain=gain)
        flatsource.multiplyFluxNorm(counts_5sigma/counts_flat)

        # Calculate the AB magnitude of this source.
        mag_5sigma = flatsource.calcMag(self)
        return mag_5sigma
Esempio n. 7
0
class m5calculations():
    def __init__(self, default_y='y4'):
        """Instantiate the object."""
        self.default_y = default_y
        return

    def setup_Throughputs(self, rootDir=None, verbose=True):
        """Read bandpasses and dark sky sed.
        Call this method first before doing anything else. """
        self.filterlist = ('u', 'g', 'r', 'i', 'z', 'y')
        if rootDir == None:
            rootDir = os.getenv('LSST_THROUGHPUTS_DEFAULT')            
        if rootDir == None:
            raise Exception('Either provide "rootDir" or set $LSST_THROUGHPUTS_DEFAULT')
        # Read in the total transmission curves. 
        self.lsst = {}
        hardwarecomponentlist = ['detector.dat','lens1.dat', 'lens2.dat', 'lens3.dat',
                                 'm1.dat', 'm2.dat', 'm3.dat']
        commoncomponentlist = hardwarecomponentlist + ['atmos_10.dat',]
        for f in self.filterlist:
            componentlist = commoncomponentlist + ['filter_' +f +'.dat',]
            self.lsst[f] = Bandpass()
            self.lsst[f].readThroughputList(componentlist, rootDir=rootDir, verbose=verbose)
        # Read in the hardware-only transmission curves (no atmosphere).
        self.hardware = {}
        for f in self.filterlist:
            componentlist = hardwarecomponentlist + ['filter_' +f +'.dat',]
            self.hardware[f] = Bandpass()
            self.hardware[f].readThroughputList(componentlist, rootDir=rootDir, verbose=verbose)
        # Read in the dark sky SED.
        darkskyfile = 'darksky.dat'
        self.darksky = Sed()
        self.darksky.readSED_flambda(os.path.join(rootDir, darkskyfile))
        # Set up a flat SED.
        self.flatsed = Sed()
        self.flatsed.setFlatSED()
        return        
    
    def setup_values(self, expTime=15.0, nexp=2., instrument_noise=None, instrument_noise_visit=None):
        """Set appropriate default values. Allows user to change expTime, nexp, or instrument_noise.
        Call this method second - and potentially many times.
        The exposure time is used to calculate dark current noise, m5 and Cm values, as well as ZP_t/ZP_h.
        These should be separated out when I have more time, to allow variable expTime in calcM5 below. """
        # exposure time (seconds)
        self.expTime = expTime
        # number of exposures per visit (for calculating total m5 per visit rather than per exposure)
        self.nexp = nexp
        # Gain, electrons/adu.
        self.gain = 2.3
        if instrument_noise != None:
            self.instrument_noise = instrument_noise
            self.othernoise = 0.0
            self.rdnoise = self.instrument_noise
        elif instrument_noise_visit != None:
            self.instrument_noise = instrument_noise_visit / numpy.sqrt(self.nexp)
            self.othernoise = 0.0
            self.rdnoise = self.instrument_noise
        else:
            # othernoise == camera electronics noise (electrons/exposure/pixel)
            self.othernoise = 3.9   
            # actual readnoise straight off the camera (electrons/exposure/pixel)
            self.rdnoise = 5.9
            # total instrumental noise (camera readnoise + other). electrons/exposure/pixel.
            #  add 0.5 * gain to (allow for potential undersampling of readnoise. with gain*0.5 term)
            #self.instrument_noise = numpy.sqrt(self.othernoise**2 + self.rdnoise**2 + (self.gain*0.5)**2)
            self.instrument_noise = numpy.sqrt(self.othernoise**2 + self.rdnoise**2)
        # Dark current, electrons/pix/second.
        self.dark_current = 0.2         
        # Plate scale, arcseconds per pixel.
        self.platescale = 0.2
        # Telescope primary mirror diameter, effective collecting area (cm^2). 
        self.effarea = numpy.pi*(6.5*100/2.0)**2
        # Set default y band (for inputs where only 'y' is specified). 
        self.default_y = 'y4'
        # Calculate Tb / Sb (integral of transmission/wavelength) as in LSE-40 (Table 7), to calculate kAtm.
        Tb = {}
        Sb = {}
        self.kAtm = {}
        stepsize = self.lsst[self.filterlist[0]].wavelen[1] - self.lsst[self.filterlist[0]].wavelen[0]
        for f in self.filterlist:
            self.kAtm[f] = [0.0, 0.0]
            Tb[f] = (self.lsst[f].sb / self.lsst[f].wavelen)*stepsize
            Sb[f] = (self.hardware[f].sb / self.hardware[f].wavelen)*stepsize
            if f.startswith('y'):
                condition = (self.lsst[f].wavelen >= 975) | (self.lsst[f].wavelen <= 800)
                self.kAtm[f][0] = -2.5*numpy.log10(Tb[f][condition].sum() / Sb[f][condition].sum())
                condition = (self.lsst[f].wavelen > 800) & (self.lsst[f].wavelen < 975)
                self.kAtm[f][1] = -2.5*numpy.log10(Tb[f][condition].sum() / Sb[f][condition].sum())
            else:
                self.kAtm[f][0] = -2.5*numpy.log10(Tb[f].sum() / Sb[f].sum())
        # Calculate telescope zeropoints. 
        self.zpT = {}
        self.zpH = {}
        for f in self.filterlist:
            self.zpT[f] = self.lsst[f].calcZP_t(expTime=self.nexp*self.expTime, effarea=self.effarea,
                                                gain=self.gain)
            self.zpH[f] = self.hardware[f].calcZP_t(expTime=self.nexp*self.expTime, effarea=self.effarea,
                                                    gain=self.gain)
        return

    def print_values(self):
        """Print a report of the values used in the maglimit calculations."""
        # Calculate some additional stuff which can be printed out. 
        self.C_m = {}
        self.darkskymags = {}
        self.m5 = {}
        for f in self.filterlist:
            self.darkskymags[f] = self.darksky.calcMag(self.hardware[f])
            self.m5[f] = self.lsst[f].calcM5(self.darksky, self.hardware[f], expTime=self.expTime,
                                             nexp=self.nexp, readnoise=self.rdnoise,
                                             othernoise=self.othernoise, darkcurrent=self.dark_current,
                                             gain=self.gain, effarea=self.effarea, 
                                             seeing = 0.7, platescale = self.platescale)
            self.C_m[f] = self.m5[f] - 0.50*(self.darkskymags[f] - 21.0)
        # Start printing stuff to screen.
        print 'Exposure time ', self.expTime
        print 'Number of exposures per visit ', self.nexp
        print 'Gain ', self.gain
        print 'Camera readnoise ', self.rdnoise, ' and other readnoise ', self.othernoise
        print 'Instrumental noise per exposure ', self.instrument_noise
        print 'Dark current per second per pixel ', self.dark_current
        print 'Dark current per exposure ', self.dark_current*self.expTime
        print 'Total camera noise per visit (e/pix/visit) ', \
            numpy.sqrt(self.nexp*self.expTime*self.dark_current + self.nexp*(self.instrument_noise)**2)
        print 'Platescale ', self.platescale
        print 'Telescope effective area ', self.effarea        
        print 'Scaling relation C_m and kAtm values: '
        for f in self.filterlist:
            print '\t \tin filter ', f, ' C_m=', self.C_m[f], ' kAtm= ', self.kAtm[f]
        print 'C_m=', self.C_m
        print 'kAtm=', self.kAtm
        print 'Telescope and Hardware zeropoints (%f sec visit):' %(self.expTime*self.nexp)
        for f in self.filterlist:
            print '\t\tin filter ', f, ' zpT = ', self.zpT[f], ' zpH = ', self.zpH[f]
        print 'Dark sky m5 limits :'
        for f in self.filterlist:
            print '\t\tin filter ', f, ' m5 = ', self.m5[f]
        print 'Dark sky noise (seeing=0.7 arcsec, @ zenith) & camera noise (both in electrons | ADU):'
        for f in self.filterlist:
            skynoise = numpy.sqrt(self.darksky.calcADU(self.hardware[f], expTime=self.nexp*self.expTime,
                                                        gain=self.gain, effarea=self.effarea) \
                                                        * self.platescale**2  * self.gain)  # electrons
            instnoise = numpy.sqrt(self.nexp *(self.dark_current*self.expTime + self.instrument_noise**2)) #electrons
            print '\t\tin filter ', f, ' skynoise = ', skynoise, '|', skynoise/self.gain, ' instnoise = ', instnoise, '|', instnoise/self.gain
        return
      
    def check_filter(self, filter):
        """Check filter array for consistency with internal set. Basically this means replace 'y' with
        the default y band choice. """
        # Might have to generate a new filter array, if the length of the previous values was too short to hold default_y.
        newfilter = numpy.empty(len(filter), dtype=('str', len(self.default_y)))
        condition = (filter == 'y')
        newfilter[condition] = self.default_y
        condition = (filter != 'y')
        newfilter[condition] = filter[condition]
        filter = newfilter
        filters_used = numpy.unique(filter)
        for f in filters_used:
            if f not in self.filterlist:
                print 'Having a problem with %s, which has length %d (spaces?)' %(f, len(f))
                indices = numpy.where(filter==f)
                print 'This pops up at observation(s) ', indices
                raise Exception('I do not recognize filter %s' %(f))
        return filter
    
    def calc_maglimit(self, seeing, skybrightness, filter, airmass, snr=5.0):
        """Calculate limiting magnitude at snr, for nexp/expTime/gain/instNoise/zeropoint values of class,
        under conditions of seeing (arcseconds) and skybrightness (mag/arcsecond^2).
        Returns mag limit. """        
        # neff = 'effective' pixel area for a point source. (see LSE-40 - SNR doc - eqn 31).
        neff = 2.436 * (seeing/self.platescale)**2
        # Calculate sky counts (counts/pixel/exp) in this bandpass from the skybrightness (mag/arcsecond^2).
        filters_used = numpy.unique(filter)
        skycounts = numpy.zeros(len(skybrightness), float)
        for f in filters_used:
            condition = (filter == f)
            # Convert skycounts from mags/''sq to counts/''sq for visit.
            skycounts[condition] = (10.**(-0.4*(skybrightness[condition] - self.zpH[f])))
        # Convert to skycounts per pixel. 
        skycounts = skycounts * self.platescale**2   #(mag/pixel)
        # Calculate the sky noise (squared) in ADU.
        skynoise_sq = skycounts / self.gain
        # Calculate noise (squared) from the instrument, converting result to ADU.
        instnoise_sq = self.nexp*(self.dark_current*self.expTime + self.instrument_noise**2) / (self.gain**2.0)
        # see equation 42 from SNR doc
        noise_sq = (skycounts / self.gain + instnoise_sq) * neff
        # Translate this to the required counts for a source using equations 45/46 from SNR doc.
        #  Counts are in ADU using this formula. 
        counts = (snr**2.0)/self.gain/2.0 + numpy.sqrt((snr**4.0)/(self.gain)**2/4.0 + (snr**2.0)*noise_sq)
        # And translate to counts, at this airmass in this filter.
        #    Note we did not have to correct for extinction for the skycounts, because the sky background
        #    is already extinction-corrected (which is part of the reason we must use hardware ZP only).
        mags = numpy.zeros(len(counts), 'float')
        for f in filters_used:
            condition = (filter == f)
            # Convert to magnitudes
            mags[condition] = -2.5*numpy.log10(counts[condition]) + self.zpT[f]
            # Correct for atmospheric extinction (note there is already a factor of X=1 in the zeropoint). 
            mags[condition] = (mags[condition] - self.kAtm[f][0]*(airmass[condition]-1)
                               - self.kAtm[f][1]*numpy.sqrt(airmass[condition]-1))
        return mags
def ImportSED(filename,d_lambda):
    sed = Sed()
    sed.readSED_flambda(filename)
    sed.synchronizeSED(wavelen_step = d_lambda)
    return(sed)
Esempio n. 9
0
def ImportSED(filename, d_lambda):
    sed = Sed()
    sed.readSED_flambda(filename)
    sed.synchronizeSED(wavelen_step=d_lambda)
    return (sed)
Esempio n. 10
0
class m5calculations():
    def __init__(self, default_y='y4'):
        """Instantiate the object."""
        self.default_y = default_y
        return

    def setup_Throughputs(self, rootDir=None, verbose=True):
        """Read bandpasses and dark sky sed.
        Call this method first before doing anything else. """
        self.filterlist = ('u', 'g', 'r', 'i', 'z', 'y')
        if rootDir == None:
            rootDir = os.getenv('LSST_THROUGHPUTS_DEFAULT')
        if rootDir == None:
            raise Exception(
                'Either provide "rootDir" or set $LSST_THROUGHPUTS_DEFAULT')
        # Read in the total transmission curves.
        self.lsst = {}
        hardwarecomponentlist = [
            'detector.dat', 'lens1.dat', 'lens2.dat', 'lens3.dat', 'm1.dat',
            'm2.dat', 'm3.dat'
        ]
        commoncomponentlist = hardwarecomponentlist + [
            'atmos_10.dat',
        ]
        for f in self.filterlist:
            componentlist = commoncomponentlist + [
                'filter_' + f + '.dat',
            ]
            self.lsst[f] = Bandpass()
            self.lsst[f].readThroughputList(componentlist,
                                            rootDir=rootDir,
                                            verbose=verbose)
        # Read in the hardware-only transmission curves (no atmosphere).
        self.hardware = {}
        for f in self.filterlist:
            componentlist = hardwarecomponentlist + [
                'filter_' + f + '.dat',
            ]
            self.hardware[f] = Bandpass()
            self.hardware[f].readThroughputList(componentlist,
                                                rootDir=rootDir,
                                                verbose=verbose)
        # Read in the dark sky SED.
        darkskyfile = 'darksky.dat'
        self.darksky = Sed()
        self.darksky.readSED_flambda(os.path.join(rootDir, darkskyfile))
        # Set up a flat SED.
        self.flatsed = Sed()
        self.flatsed.setFlatSED()
        return

    def setup_values(self,
                     expTime=15.0,
                     nexp=2.,
                     instrument_noise=None,
                     instrument_noise_visit=None):
        """Set appropriate default values. Allows user to change expTime, nexp, or instrument_noise.
        Call this method second - and potentially many times.
        The exposure time is used to calculate dark current noise, m5 and Cm values, as well as ZP_t/ZP_h.
        These should be separated out when I have more time, to allow variable expTime in calcM5 below. """
        # exposure time (seconds)
        self.expTime = expTime
        # number of exposures per visit (for calculating total m5 per visit rather than per exposure)
        self.nexp = nexp
        # Gain, electrons/adu.
        self.gain = 2.3
        if instrument_noise != None:
            self.instrument_noise = instrument_noise
            self.othernoise = 0.0
            self.rdnoise = self.instrument_noise
        elif instrument_noise_visit != None:
            self.instrument_noise = instrument_noise_visit / numpy.sqrt(
                self.nexp)
            self.othernoise = 0.0
            self.rdnoise = self.instrument_noise
        else:
            # othernoise == camera electronics noise (electrons/exposure/pixel)
            self.othernoise = 3.9
            # actual readnoise straight off the camera (electrons/exposure/pixel)
            self.rdnoise = 5.9
            # total instrumental noise (camera readnoise + other). electrons/exposure/pixel.
            #  add 0.5 * gain to (allow for potential undersampling of readnoise. with gain*0.5 term)
            #self.instrument_noise = numpy.sqrt(self.othernoise**2 + self.rdnoise**2 + (self.gain*0.5)**2)
            self.instrument_noise = numpy.sqrt(self.othernoise**2 +
                                               self.rdnoise**2)
        # Dark current, electrons/pix/second.
        self.dark_current = 0.2
        # Plate scale, arcseconds per pixel.
        self.platescale = 0.2
        # Telescope primary mirror diameter, effective collecting area (cm^2).
        self.effarea = numpy.pi * (6.5 * 100 / 2.0)**2
        # Set default y band (for inputs where only 'y' is specified).
        self.default_y = 'y4'
        # Calculate Tb / Sb (integral of transmission/wavelength) as in LSE-40 (Table 7), to calculate kAtm.
        Tb = {}
        Sb = {}
        self.kAtm = {}
        stepsize = self.lsst[self.filterlist[0]].wavelen[1] - self.lsst[
            self.filterlist[0]].wavelen[0]
        for f in self.filterlist:
            self.kAtm[f] = [0.0, 0.0]
            Tb[f] = (self.lsst[f].sb / self.lsst[f].wavelen) * stepsize
            Sb[f] = (self.hardware[f].sb / self.hardware[f].wavelen) * stepsize
            if f.startswith('y'):
                condition = (self.lsst[f].wavelen >=
                             975) | (self.lsst[f].wavelen <= 800)
                self.kAtm[f][0] = -2.5 * numpy.log10(
                    Tb[f][condition].sum() / Sb[f][condition].sum())
                condition = (self.lsst[f].wavelen >
                             800) & (self.lsst[f].wavelen < 975)
                self.kAtm[f][1] = -2.5 * numpy.log10(
                    Tb[f][condition].sum() / Sb[f][condition].sum())
            else:
                self.kAtm[f][0] = -2.5 * numpy.log10(Tb[f].sum() / Sb[f].sum())
        # Calculate telescope zeropoints.
        self.zpT = {}
        self.zpH = {}
        for f in self.filterlist:
            self.zpT[f] = self.lsst[f].calcZP_t(expTime=self.nexp *
                                                self.expTime,
                                                effarea=self.effarea,
                                                gain=self.gain)
            self.zpH[f] = self.hardware[f].calcZP_t(expTime=self.nexp *
                                                    self.expTime,
                                                    effarea=self.effarea,
                                                    gain=self.gain)
        return

    def print_values(self):
        """Print a report of the values used in the maglimit calculations."""
        # Calculate some additional stuff which can be printed out.
        self.C_m = {}
        self.darkskymags = {}
        self.m5 = {}
        for f in self.filterlist:
            self.darkskymags[f] = self.darksky.calcMag(self.hardware[f])
            self.m5[f] = self.lsst[f].calcM5(self.darksky,
                                             self.hardware[f],
                                             expTime=self.expTime,
                                             nexp=self.nexp,
                                             readnoise=self.rdnoise,
                                             othernoise=self.othernoise,
                                             darkcurrent=self.dark_current,
                                             gain=self.gain,
                                             effarea=self.effarea,
                                             seeing=0.7,
                                             platescale=self.platescale)
            self.C_m[f] = self.m5[f] - 0.50 * (self.darkskymags[f] - 21.0)
        # Start printing stuff to screen.
        print 'Exposure time ', self.expTime
        print 'Number of exposures per visit ', self.nexp
        print 'Gain ', self.gain
        print 'Camera readnoise ', self.rdnoise, ' and other readnoise ', self.othernoise
        print 'Instrumental noise per exposure ', self.instrument_noise
        print 'Dark current per second per pixel ', self.dark_current
        print 'Dark current per exposure ', self.dark_current * self.expTime
        print 'Total camera noise per visit (e/pix/visit) ', \
            numpy.sqrt(self.nexp*self.expTime*self.dark_current + self.nexp*(self.instrument_noise)**2)
        print 'Platescale ', self.platescale
        print 'Telescope effective area ', self.effarea
        print 'Scaling relation C_m and kAtm values: '
        for f in self.filterlist:
            print '\t \tin filter ', f, ' C_m=', self.C_m[
                f], ' kAtm= ', self.kAtm[f]
        print 'C_m=', self.C_m
        print 'kAtm=', self.kAtm
        print 'Telescope and Hardware zeropoints (%f sec visit):' % (
            self.expTime * self.nexp)
        for f in self.filterlist:
            print '\t\tin filter ', f, ' zpT = ', self.zpT[
                f], ' zpH = ', self.zpH[f]
        print 'Dark sky m5 limits :'
        for f in self.filterlist:
            print '\t\tin filter ', f, ' m5 = ', self.m5[f]
        print 'Dark sky noise (seeing=0.7 arcsec, @ zenith) & camera noise (both in electrons | ADU):'
        for f in self.filterlist:
            skynoise = numpy.sqrt(self.darksky.calcADU(self.hardware[f], expTime=self.nexp*self.expTime,
                                                        gain=self.gain, effarea=self.effarea) \
                                                        * self.platescale**2  * self.gain)  # electrons
            instnoise = numpy.sqrt(self.nexp *
                                   (self.dark_current * self.expTime +
                                    self.instrument_noise**2))  #electrons
            print '\t\tin filter ', f, ' skynoise = ', skynoise, '|', skynoise / self.gain, ' instnoise = ', instnoise, '|', instnoise / self.gain
        return

    def check_filter(self, filter):
        """Check filter array for consistency with internal set. Basically this means replace 'y' with
        the default y band choice. """
        # Might have to generate a new filter array, if the length of the previous values was too short to hold default_y.
        newfilter = numpy.empty(len(filter),
                                dtype=('str', len(self.default_y)))
        condition = (filter == 'y')
        newfilter[condition] = self.default_y
        condition = (filter != 'y')
        newfilter[condition] = filter[condition]
        filter = newfilter
        filters_used = numpy.unique(filter)
        for f in filters_used:
            if f not in self.filterlist:
                print 'Having a problem with %s, which has length %d (spaces?)' % (
                    f, len(f))
                indices = numpy.where(filter == f)
                print 'This pops up at observation(s) ', indices
                raise Exception('I do not recognize filter %s' % (f))
        return filter

    def calc_maglimit(self, seeing, skybrightness, filter, airmass, snr=5.0):
        """Calculate limiting magnitude at snr, for nexp/expTime/gain/instNoise/zeropoint values of class,
        under conditions of seeing (arcseconds) and skybrightness (mag/arcsecond^2).
        Returns mag limit. """
        # neff = 'effective' pixel area for a point source. (see LSE-40 - SNR doc - eqn 31).
        neff = 2.436 * (seeing / self.platescale)**2
        # Calculate sky counts (counts/pixel/exp) in this bandpass from the skybrightness (mag/arcsecond^2).
        filters_used = numpy.unique(filter)
        skycounts = numpy.zeros(len(skybrightness), float)
        for f in filters_used:
            condition = (filter == f)
            # Convert skycounts from mags/''sq to counts/''sq for visit.
            skycounts[condition] = (10.**(
                -0.4 * (skybrightness[condition] - self.zpH[f])))
        # Convert to skycounts per pixel.
        skycounts = skycounts * self.platescale**2  #(mag/pixel)
        # Calculate the sky noise (squared) in ADU.
        skynoise_sq = skycounts / self.gain
        # Calculate noise (squared) from the instrument, converting result to ADU.
        instnoise_sq = self.nexp * (self.dark_current * self.expTime +
                                    self.instrument_noise**2) / (self.gain**
                                                                 2.0)
        # see equation 42 from SNR doc
        noise_sq = (skycounts / self.gain + instnoise_sq) * neff
        # Translate this to the required counts for a source using equations 45/46 from SNR doc.
        #  Counts are in ADU using this formula.
        counts = (snr**2.0) / self.gain / 2.0 + numpy.sqrt(
            (snr**4.0) / (self.gain)**2 / 4.0 + (snr**2.0) * noise_sq)
        # And translate to counts, at this airmass in this filter.
        #    Note we did not have to correct for extinction for the skycounts, because the sky background
        #    is already extinction-corrected (which is part of the reason we must use hardware ZP only).
        mags = numpy.zeros(len(counts), 'float')
        for f in filters_used:
            condition = (filter == f)
            # Convert to magnitudes
            mags[condition] = -2.5 * numpy.log10(
                counts[condition]) + self.zpT[f]
            # Correct for atmospheric extinction (note there is already a factor of X=1 in the zeropoint).
            mags[condition] = (
                mags[condition] - self.kAtm[f][0] * (airmass[condition] - 1) -
                self.kAtm[f][1] * numpy.sqrt(airmass[condition] - 1))
        return mags
Esempio n. 11
0
for f in filterlist:
    Sb[f] = (hardware[f].sb / hardware[f].wavelen).sum() * hardware[f].wavelen_step
    Tb[f] = (total[f].sb / total[f].wavelen).sum() * total[f].wavelen_step

writestring1 = 'Sb: '
writestring2 = 'Tb: ' 
for f in filterlist:
    writestring1 += '%s %.3f ' %(f, Sb[f])
    writestring2 += '%s %.3f ' %(f, Tb[f])
print writestring1
print writestring2

# Set up to calculate m5. 

# Read in the dark sky SED
darksky = Sed()
darksky.readSED_flambda(os.path.join(throughputsDir, 'darksky.dat'))

# Set up a range of exposure times (per exposure, not per visit)
exptimes = numpy.arange(0.1, 100., 5.)
# Set a range of readnoise values and zero out other noise contributions (I think this is what you want, to isolate readnoise completely)
#  (plus the camera team includes 'othernoise' into their 'instrumental noise' value .. this is another potential source of confusion when talking
#  to them about this .. usually when they say 'readnoise' they actually mean the full instrumental noise, but do not consider dark current)
othernoise = 0
darkcurrent = 0
readnoises = [10., 13.]  # noise per VISIT (so set nexp=1 and then exptime = visit time)
nexp = 1

# Calculate m5 values for each of these exposure times. 
for exptime in exptimes:
    for readnoise in readnoises: