def Calc_m5(self, filtre): filtre_trans = self.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) flatSedb = Sed() flatSedb.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * self.mag_sky[filtre]) flatSedb.multiplyFluxNorm(flux0b) photParams = PhotometricParameters(bandpass=filtre) norm = photParams.platescale**2 / 2. * photParams.exptime / photParams.gain if self.atmos: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.atmosphere[filtre], self.system[filtre], photParams=photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU(bandpass=self.atmosphere[filtre], photParams=photParams) self.data['flux_sky'][filtre] = adu_int * norm else: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.system[filtre], self.system[filtre], photParams=photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU(bandpass=self.system[filtre], photParams=photParams) self.data['flux_sky'][filtre] = adu_int * norm
def __call__(self, filter_name='u', magNorm=None): """ This method calls the SkyCountsPerSec object and calculates the sky counts. @param [in] filter_name is a string that indicates the name of the filter for which to make the calculation. @param [in] magNorm is an option to calculate the sky counts for a given magnitude. When calculating the counts from just the information in skyModel this should be set as MagNorm=None. """ bandpass = self.bandpassdic[filter_name] wave, spec = self.skyModel.returnWaveSpec() skymodel_Sed = Sed(wavelen=wave, flambda=spec[0, :]) if magNorm: skymodel_fluxNorm = skymodel_Sed.calcFluxNorm(magNorm, bandpass) skymodel_Sed.multiplyFluxNorm(skymodel_fluxNorm) sky_counts = skymodel_Sed.calcADU(bandpass=bandpass, photParams=self.photParams) expTime = self.photParams.nexp * self.photParams.exptime * u.s sky_counts_persec = sky_counts * 0.2**2 / expTime return sky_counts_persec
def ZP_filtre(self, filtre): self.data['Skyb'][filtre] = self.Cte * np.power( self.Diameter / 6.5, 2.) * np.power(self.DeltaT / 30., 2.) * np.power( self.platescale, 2.) * np.power( 10., 0.4 * (25. - self.mag_sky[filtre])) * self.Sigmab[filtre] Zb = 181.8 * np.power(self.Diameter / 6.5, 2.) * self.Tb[filtre] mbZ = 25. + 2.5 * np.log10(Zb) filtre_trans = self.throughputs.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) flatSed = Sed() flatSed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0 = np.power(10., -0.4 * mbZ) flatSed.multiplyFluxNorm(flux0) counts = flatSed.calcADU( bandpass, photParams=self.photParams) #number of counts for exptime self.data['zp'][filtre] = mbZ #print 'hello',counts/self.photParams.exptime self.data['counts_zp'][filtre] = counts / self.photParams.exptime
def sky_counts_per_sec(skyModel, photParams, bandpass, magNorm=None): """ Compute the sky background counts per pixel per second. Note that the gain in photParams is applied to the return value such that "counts" are in units of ADU. Parameters ---------- skyModel: lsst.sims.skybrightness.SkyModel Model of the sky for the current epoch. photParams: lsst.sims.photUtils.PhotometricParameters Object containing parameters of the photometric response of the telescope, including pixel scale, gain, effective area, exposure time, number of exposures, etc. bandpass: lsst.sims.photUtils.Bandpass Instrumental throughput for a particular passband. magNorm: float [None] If not None, then renormalize the sky SED to have a monochromatic magnitude of magNorm at 500nm. Otherwise, use the default skyModel normalization. Returns ------- ADUs per second per pixel """ wave, spec = skyModel.returnWaveSpec() sed = Sed(wavelen=wave, flambda=spec[0, :]) if magNorm is not None: flux_norm = sed.calcFluxNorm(magNorm, bandpass) sed.multiplyFluxNorm(flux_norm) countrate_per_arcsec = sed.calcADU(bandpass=bandpass, photParams=photParams) exptime = photParams.nexp * photParams.exptime return countrate_per_arcsec * photParams.platescale**2 / exptime
def ZP_filtre(self, filtre): photParams = PhotometricParameters(bandpass=filtre) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter Cte = 3631. * np.pi * Diameter**2 * 2. * photParams.exptime / 4 / h / 1.e36 #print('hello Cte',Cte,Diameter,h,photParams.exptime) self.data['Skyb'][filtre] = Cte * np.power( Diameter / 6.5, 2.) * np.power( 2. * photParams.exptime / 30., 2.) * np.power( photParams.platescale, 2.) * np.power( 10., 0.4 * (25. - self.mag_sky[filtre])) * self.Sigmab[filtre] Zb = 181.8 * np.power(Diameter / 6.5, 2.) * self.Tb[filtre] mbZ = 25. + 2.5 * np.log10(Zb) filtre_trans = self.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) flatSed = Sed() flatSed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0 = np.power(10., -0.4 * mbZ) flatSed.multiplyFluxNorm(flux0) photParams = PhotometricParameters(bandpass=filtre) counts = flatSed.calcADU( bandpass, photParams=photParams) #number of counts for exptime self.data['zp'][filtre] = mbZ #print 'hello',counts/self.photParams.exptime self.data['counts_zp'][filtre] = counts / 2. * photParams.exptime
def setM5(m5target, skysed, totalBandpass, hardware, photParams, FWHMeff=None): """ Take an SED representing the sky and normalize it so that m5 (the magnitude at which an object is detected in this bandpass at 5-sigma) is set to some specified value. The 5-sigma limiting magnitude (m5) for an observation is determined by a combination of the telescope and camera parameters (such as diameter of the mirrors and the readnoise) together with the sky background. This method (setM5) scales a provided sky background Sed so that an observation would have a target m5 value, for the provided hardware parameters. Using the resulting Sed in the 'calcM5' method will return this target value for m5. @param [in] the desired value of m5 @param [in] skysed is an instantiation of the Sed class representing sky emission @param [in] totalBandpass is an instantiation of the Bandpass class representing the total throughput of the telescope (instrumentation plus atmosphere) @param [in] hardware is an instantiation of the Bandpass class representing the throughput due solely to instrumentation. @param [in] photParams is an instantiation of the PhotometricParameters class that carries details about the photometric response of the telescope. @param [in] FWHMeff in arcseconds @param [out] returns an instantiation of the Sed class that is the skysed renormalized so that m5 has the desired value. Note that the returned SED will be renormalized such that calling the method self.calcADU(hardwareBandpass) on it will yield the number of counts per square arcsecond in a given bandpass. """ #This is based on the LSST SNR document (v1.2, May 2010) #www.astro.washington.edu/users/ivezic/Astr511/LSST_SNRdoc.pdf if FWHMeff is None: FWHMeff = LSSTdefaults().FWHMeff('r') skyCountsTarget = calcSkyCountsPerPixelForM5(m5target, totalBandpass, FWHMeff=FWHMeff, photParams=photParams) skySedOut = Sed(wavelen=numpy.copy(skysed.wavelen), flambda=numpy.copy(skysed.flambda)) skyCounts = skySedOut.calcADU(hardware, photParams=photParams) \ * photParams.platescale * photParams.platescale skySedOut.multiplyFluxNorm(skyCountsTarget / skyCounts) return skySedOut
def setM5(m5target, skysed, totalBandpass, hardware, photParams, FWHMeff = None): """ Take an SED representing the sky and normalize it so that m5 (the magnitude at which an object is detected in this bandpass at 5-sigma) is set to some specified value. The 5-sigma limiting magnitude (m5) for an observation is determined by a combination of the telescope and camera parameters (such as diameter of the mirrors and the readnoise) together with the sky background. This method (setM5) scales a provided sky background Sed so that an observation would have a target m5 value, for the provided hardware parameters. Using the resulting Sed in the 'calcM5' method will return this target value for m5. @param [in] the desired value of m5 @param [in] skysed is an instantiation of the Sed class representing sky emission @param [in] totalBandpass is an instantiation of the Bandpass class representing the total throughput of the telescope (instrumentation plus atmosphere) @param [in] hardware is an instantiation of the Bandpass class representing the throughput due solely to instrumentation. @param [in] photParams is an instantiation of the PhotometricParameters class that carries details about the photometric response of the telescope. @param [in] FWHMeff in arcseconds @param [out] returns an instantiation of the Sed class that is the skysed renormalized so that m5 has the desired value. Note that the returned SED will be renormalized such that calling the method self.calcADU(hardwareBandpass) on it will yield the number of counts per square arcsecond in a given bandpass. """ #This is based on the LSST SNR document (v1.2, May 2010) #www.astro.washington.edu/users/ivezic/Astr511/LSST_SNRdoc.pdf if FWHMeff is None: FWHMeff = LSSTdefaults().FWHMeff('r') skyCountsTarget = calcSkyCountsPerPixelForM5(m5target, totalBandpass, FWHMeff=FWHMeff, photParams=photParams) skySedOut = Sed(wavelen=numpy.copy(skysed.wavelen), flambda=numpy.copy(skysed.flambda)) skyCounts = skySedOut.calcADU(hardware, photParams=photParams) \ * photParams.platescale * photParams.platescale skySedOut.multiplyFluxNorm(skyCountsTarget/skyCounts) return skySedOut
def Calc_m5(self, filtre): """ Calc_m5(filtre): Compute m5 or SNR at five sigma Tool function implemented by Phillie Gris (IN2P3) """ # get telescope passband (no atmosphere) filtre_trans = self.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) # create a Flat sed S_nu from the sky brightness magnitude flatSedb = Sed() flatSedb.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * self.mag_sky[filtre]) flatSedb.multiplyFluxNorm(flux0b) # Get LSST photometric parameters photParams = PhotometricParameters(bandpass=filtre) norm = photParams.platescale**2 / 2. * photParams.exptime / photParams.gain # Use LSST sims (SignalToNoise) to calculate M5 with atmosphere or without atmosphere if self.atmos: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.atmosphere[filtre], self.system[filtre], photParams=photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU(bandpass=self.atmosphere[filtre], photParams=photParams) self.data['flux_sky'][filtre] = adu_int * norm else: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.system[filtre], self.system[filtre], photParams=photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU(bandpass=self.system[filtre], photParams=photParams) self.data['flux_sky'][filtre] = adu_int * norm
def calcADUwrapper(sedName=None, magNorm=None, redshift=None, internalAv=None, internalRv=None, galacticAv=None, galacticRv=None, bandpass=None): """ Read in an SED and calculat the number of ADU produced by that SED in a specified bandpass Parameters ---------- sedName is a string specifying the file name of the SED magNorm is the normalizing magnitude of the SED in the imsimBandpass redshift is the redshift of the SED internalAv is the Av due to internal dust of the source (if a galaxy) internalRv is the Rv due to internal dust of the source (if a galaxy) galacticAv is the Av due to Milky Way dust between observer and source galacticRv is the Rv due to Milky Way dust between observer and source bandpass is an intantiation of Bandpass representing the band in which the ADUs are measured Returns ------- A float representing the number of ADUs measured in the bandpass """ imsimband = Bandpass() imsimband.imsimBandpass() sed = Sed() sed.readSED_flambda(sedName) fNorm = sed.calcFluxNorm(magNorm, imsimband) sed.multiplyFluxNorm(fNorm) if internalAv is not None and internalRv is not None: if internalAv != 0.0 and internalRv != 0.0: a_int, b_int = sed.setupCCM_ab() sed.addDust(a_int, b_int, A_v=internalAv, R_v=internalRv) if redshift is not None and redshift != 0.0: sed.redshiftSED(redshift, dimming=True) a_int, b_int = sed.setupCCM_ab() sed.addDust(a_int, b_int, A_v=galacticAv, R_v=galacticRv) adu = sed.calcADU(bandpass, photParams=PhotometricParameters()) return adu
def Calc_m5(self, filtre): filtre_trans = self.throughputs.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) flatSedb = Sed() flatSedb.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * self.mag_sky[filtre]) flatSedb.multiplyFluxNorm(flux0b) if self.atmos: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.throughputs.atmosphere[filtre], self.throughputs.system[filtre], photParams=self.photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU( bandpass=self.throughputs.atmosphere[filtre], photParams=self.photParams) self.data['flux_sky'][ filtre] = adu_int * self.pixel_area / self.expTime[ filtre] / self.gain else: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.throughputs.system[filtre], self.throughputs.system[filtre], photParams=self.photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU( bandpass=self.throughputs.system[filtre], photParams=self.photParams) self.data['flux_sky'][ filtre] = adu_int * self.pixel_area / self.expTime[ filtre] / self.gain
def testApplication(self): """ Test that PhotometricParameters get properly propagated into Sed methods. We will test this using Sed.calcADU, since the ADU scale linearly with the appropriate parameter. """ testSed = Sed() testSed.setFlatSED() testBandpass = Bandpass() testBandpass.readThroughput(os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'total_g.dat')) control = testSed.calcADU(testBandpass, photParams=PhotometricParameters()) testCase = PhotometricParameters(exptime=30.0) test = testSed.calcADU(testBandpass, photParams=testCase) self.assertGreater(control, 0.0) self.assertEqual(control, 0.5*test)
def Calc_Sky(self, paper, infos, transmission): Diameter = 6.5 #m Deltat = 30 #s platescale = 0.2 #arsec gain = 2.3 for filtre in self.filters: filtre_trans = transmission.lsst_system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) photParams = PhotometricParameters() #photParams._exptime=30. bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) infos['Skyb'][filtre] = 5455 * np.power( Diameter / 6.5, 2.) * np.power(Deltat / 30., 2.) * np.power( platescale, 2.) * np.power( 10., 0.4 * (25. - infos['mbsky'][filtre])) * infos['Sigmab'][filtre] Zb = 181.8 * np.power(Diameter / 6.5, 2.) * infos['Tb'][filtre] mbZ = 25. + 2.5 * np.log10(Zb) flatSed = Sed() flatSed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0 = np.power(10., -0.4 * mbZ) flatSed.multiplyFluxNorm(flux0) counts = flatSed.calcADU( bandpass, photParams=photParams) #number of counts for exptime infos['mb_Z'][filtre] = mbZ infos['counts_mb_Z'][filtre] = counts / photParams.exptime flatSedb = Sed() flatSedb.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * infos['mbsky'][filtre]) flatSedb.multiplyFluxNorm(flux0b) FWHMeff = SignalToNoise.FWHMgeom2FWHMeff(paper['Seeing'][filtre]) #FWHMeff = paper['Seeing'][filtre] #m5_calc=SignalToNoise.calcM5(flatSedb,transmission.lsst_atmos[filtre],transmission.lsst_system[filtre],photParams=photParams,FWHMeff=FWHMeff) m5_calc = SignalToNoise.calcM5( flatSedb, transmission.lsst_atmos[filtre], transmission.lsst_system[filtre], photParams=photParams, FWHMeff=self.paper['FWHMeff'][filtre]) infos['fiveSigmaDepth'][filtre] = m5_calc
def mag_to_flux_e_sec(self, mag, band, exptime, nexp): """ Mag to flux (in photoelec/sec) conversion Parameters -------------- mag : float input magnitudes band : str input bands exptime : float input exposure times nexp: int number of exposures Returns ---------- counts : float number of ADU counts e_per_sec : float flux in photoelectron per sec. """ if not hasattr(mag, '__iter__'): wavelen_min, wavelen_max, wavelen_step = self.atmosphere[ band].getWavelenLimits(None, None, None) sed = Sed() sed.setFlatSED() flux0 = sed.calcFluxNorm(mag, self.atmosphere[band]) sed.multiplyFluxNorm(flux0) photParams = PhotometricParameters(exptime=exptime, nexp=nexp) counts = sed.calcADU(bandpass=self.atmosphere[band], photParams=photParams) e_per_sec = counts # counts per sec e_per_sec /= (exptime * nexp) # conversion to pe e_per_sec *= photParams.gain return counts, e_per_sec else: r = [] for m, b, expt, nexpos in zip(mag, band, exptime, nexp): counts, flux_e = self.mag_to_flux_e_sec(m, b, expt, nexpos) r.append((counts, flux_e)) return np.asarray(r)
def testApplication(self): """ Test that PhotometricParameters get properly propagated into Sed methods. We will test this using Sed.calcADU, since the ADU scale linearly with the appropriate parameter. """ testSed = Sed() testSed.setFlatSED() testBandpass = Bandpass() testBandpass.readThroughput( os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'total_g.dat')) control = testSed.calcADU(testBandpass, photParams=PhotometricParameters()) testCase = PhotometricParameters(exptime=30.0) test = testSed.calcADU(testBandpass, photParams=testCase) self.assertTrue(control > 0.0) self.assertEqual(control, 0.5 * test)
def ZP_filtre(self, filtre): """ ZP_filtre() : Compute zero point in filter band - platescale is 0.2 arcsec per pixel Tool function implemented by Phillie Gris (IN2P3) """ # extract parameters from lsst_sims photParams = PhotometricParameters(bandpass=filtre) # compute Diameter in meters : D=2*R = 2*sqrt(S/pi) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter # AB flux is 3.6307805477e-20 erg/cm2/s/Hz or 3.6307805477e-16 erg/m2/s/Hz # or 3.6307e-23 J/m2/s/Hz, h=6.626e-34 J.s # What is the meaning of this Cte ???? # especcialy what is 1e36 ? Cte = 3631. * np.pi * Diameter**2 * 2. * photParams.exptime / 4 / h / 1.e36 #print('Telescope::ZP_filtre: hello Cte=',Cte, ' Diam=',Diameter, 'h=',h,' exptime=',photParams.exptime) # What is the meaning of Skyb ????? self.data['Skyb'][filtre] = Cte * np.power( Diameter / 6.5, 2.) * np.power( 2. * photParams.exptime / 30., 2.) * np.power( photParams.platescale, 2.) * np.power( 10., 0.4 * (25. - self.mag_sky[filtre])) * self.Sigmab[filtre] #What is the meaning of Sigmab, Tb, Zb such Zb is used to calculate zero point Zb = 181.8 * np.power(Diameter / 6.5, 2.) * self.Tb[filtre] mbZ = 25. + 2.5 * np.log10(Zb) #filter without atmosphere filtre_trans = self.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) flatSed = Sed() flatSed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0 = np.power(10., -0.4 * mbZ) flatSed.multiplyFluxNorm(flux0) photParams = PhotometricParameters(bandpass=filtre) counts = flatSed.calcADU( bandpass, photParams=photParams) #number of counts for exptime self.data['zp'][filtre] = mbZ #print('Telescope::ZP_filtre hello',counts/self.photParams.exptime) self.data['counts_zp'][filtre] = counts / 2. * photParams.exptime
def get_zp(self, what, band): """ decorator get zero points formula used here are extracted from LSE-40 Parameters --------------- what: str parameter to estimate band: str filter """ photParams = PhotometricParameters(bandpass=band) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter Cte = 3631. * np.pi * Diameter**2 * 2. * photParams.exptime / 4 / h / 1.e36 self.data['Skyb'][band] = Cte*np.power(Diameter/6.5, 2.)\ * np.power(2.*photParams.exptime/30., 2.)\ * np.power(photParams.platescale, 2.)\ * 10.**0.4*(25.-self.mag_sky(band))\ * self.Sigmab(band) Zb = 181.8 * np.power(Diameter / 6.5, 2.) * self.Tb(band) mbZ = 25. + 2.5 * np.log10(Zb) filtre_trans = self.system[band] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) flatSed = Sed() flatSed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0 = np.power(10., -0.4 * mbZ) flatSed.multiplyFluxNorm(flux0) photParams = PhotometricParameters(bandpass=band) # number of counts for exptime counts = flatSed.calcADU(bandpass, photParams=photParams) self.data['zp'][band] = mbZ self.data['counts_zp'][band] = counts / 2. * photParams.exptime
def calcADUwrapper(sedName=None, magNorm=None, redshift=None, internalAv=None, internalRv=None, galacticAv=None, galacticRv=None, bandpass=None): imsimband = Bandpass() imsimband.imsimBandpass() sed = Sed() sed.readSED_flambda(sedName) fNorm = sed.calcFluxNorm(magNorm, imsimband) sed.multiplyFluxNorm(fNorm) if internalAv is not None and internalRv is not None: if internalAv != 0.0 and internalRv != 0.0: a_int, b_int = sed.setupCCMab() sed.addCCMDust(a_int, b_int, A_v=internalAv, R_v=internalRv) if redshift is not None and redshift != 0.0: sed.redshiftSED(redshift, dimming=True) a_int, b_int = sed.setupCCMab() sed.addCCMDust(a_int, b_int, A_v=galacticAv, R_v=galacticRv) adu = sed.calcADU(bandpass, photParams=PhotometricParameters()) return adu
def Simulate_LC_last(self): sed_SN=self.SN.get_SED(self.obs['mjd']) #print 'SED loaded' for i in range(len(sed_SN.wavelen)): obs=self.obs[i] sed=Sed(wavelen=sed_SN.wavelen[i],flambda=sed_SN.flambda[i]) visittime=obs['exptime'] filtre=obs['band'][-1] photParams = PhotometricParameters(nexp=visittime/15.) e_per_sec = sed.calcADU(bandpass=self.transmission.lsst_atmos_aerosol[filtre], photParams=photParams) #number of ADU counts for expTime e_per_sec/=visittime/photParams.gain flux_SN=sed.calcFlux(bandpass=self.transmission.lsst_atmos_aerosol[filtre]) FWHMeff=obs['FWHMeff'] if flux_SN >0: mag_SN=-2.5 * np.log10(flux_SN / 3631.0) m5_calc,snr_m5_through=self.Get_m5(filtre,mag_SN,obs['sky'],photParams,FWHMeff) self.table_LC.add_row(('LSST::'+filtre,obs['mjd'],visittime,FWHMeff,obs['moon_frac'],obs['sky'],obs['kAtm'],obs['airmass'],obs['m5sigmadepth'],obs['Nexp'],e_per_sec,e_per_sec/snr_m5_through))
def get(self, what, band): """ Decorator to access quantities Parameters --------------- what: str parameter to estimate band: str filter """ filter_trans = self.system[band] wavelen_min, wavelen_max, wavelen_step = filter_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filter_trans.wavelen, sb=filter_trans.sb) flatSedb = Sed() flatSedb.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * self.mag_sky(band)) flatSedb.multiplyFluxNorm(flux0b) photParams = PhotometricParameters(bandpass=band) norm = photParams.platescale**2 / 2. * photParams.exptime / photParams.gain trans = filter_trans if self.atmos: trans = self.atmosphere[band] self.data['m5'][band] = SignalToNoise.calcM5( flatSedb, trans, filter_trans, photParams=photParams, FWHMeff=self.FWHMeff(band)) adu_int = flatSedb.calcADU(bandpass=trans, photParams=photParams) self.data['flux_sky'][band] = adu_int * norm
def testSedMagErrors(self): """Test error handling at mag and adu calculation levels of sed.""" sedwavelen = np.arange(self.wmin+50, self.wmax, 1) sedflambda = np.ones(len(sedwavelen)) testsed = Sed(wavelen=sedwavelen, flambda=sedflambda) # Test handling in calcMag with warnings.catch_warnings(record=True) as w: mag = testsed.calcMag(self.testbandpass) self.assertEqual(len(w), 1) self.assertIn("non-overlap", str(w[-1].message)) np.testing.assert_equal(mag, np.NaN) # Test handling in calcADU with warnings.catch_warnings(record=True) as w: adu = testsed.calcADU(self.testbandpass, photParams=PhotometricParameters()) self.assertEqual(len(w), 1) self.assertIn("non-overlap", str(w[-1].message)) np.testing.assert_equal(adu, np.NaN) # Test handling in calcFlux with warnings.catch_warnings(record=True) as w: flux = testsed.calcFlux(self.testbandpass) self.assertEqual(len(w), 1) self.assertIn("non-overlap", str(w[-1].message)) np.testing.assert_equal(flux, np.NaN)
def testSedMagErrors(self): """Test error handling at mag and adu calculation levels of sed.""" sedwavelen = np.arange(self.wmin + 50, self.wmax, 1) sedflambda = np.ones(len(sedwavelen)) testsed = Sed(wavelen=sedwavelen, flambda=sedflambda) # Test handling in calcMag with warnings.catch_warnings(record=True) as w: mag = testsed.calcMag(self.testbandpass) self.assertEqual(len(w), 1) self.assertIn("non-overlap", str(w[-1].message)) np.testing.assert_equal(mag, np.NaN) # Test handling in calcADU with warnings.catch_warnings(record=True) as w: adu = testsed.calcADU(self.testbandpass, photParams=PhotometricParameters()) self.assertEqual(len(w), 1) self.assertIn("non-overlap", str(w[-1].message)) np.testing.assert_equal(adu, np.NaN) # Test handling in calcFlux with warnings.catch_warnings(record=True) as w: flux = testsed.calcFlux(self.testbandpass) self.assertEqual(len(w), 1) self.assertIn("non-overlap", str(w[-1].message)) np.testing.assert_equal(flux, np.NaN)
np_sed['flambda']) phys_params = PhysicalParameters() phot = flambda * np_filter['wav_nm'] / (phys_params.planck * phys_params.lightspeed * 1.0e9) integral = 0.5 * ( (phot[1:] * np_filter['throughput'][1:] + phot[:-1] * np_filter['throughput'][:-1]) * (np_filter['wav_nm'][1:] - np_filter['wav_nm'][:-1])).sum() effarea = np.pi * (6.423 * 100.0 / 2.0)**2 exptime = 30.0 nexp = 1.0 integral *= effarea * exptime * nexp # print results print('\n%s' % bp_name) print('catsim_counts (by hand) %e' % integral) if _LSST_STACK_INSTALLED: adu = spec.calcADU(bp, phot_params) print('catsim_counts (with sims_photUtils) %e' % (adu * phot_params.gain)) if bp_name != 'y': assert np.abs(adu * phot_params.gain - integral) < 0.01 * integral print('phosim_counts %e' % phosim_truth) print('catsim_counts/phosim_counts %e' % (integral / phosim_truth))
def testObjectPlacement(self): """ Test that GalSim places objects on the correct pixel by drawing images, reading them in, and then comparing the flux contained in circles of 2 fwhm radii about the object's expected positions with the actual expected flux of the objects. """ scratchDir = tempfile.mkdtemp(dir=ROOT, prefix='testObjectPlacement-') catName = os.path.join(scratchDir, 'placementCatalog.dat') imageRoot = os.path.join(scratchDir, 'placementImage') dbFileName = os.path.join(scratchDir, 'placementInputCatalog.dat') cameraDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData') camera = ReturnCamera(cameraDir) detector = camera[0] imageName = '%s_%s_u.fits' % (imageRoot, detector.getName()) controlSed = Sed() controlSed.readSED_flambda(os.path.join(getPackageDir('sims_sed_library'), 'flatSED', 'sed_flat.txt.gz')) uBandpass = Bandpass() uBandpass.readThroughput(os.path.join(getPackageDir('throughputs'), 'baseline', 'total_u.dat')) controlBandpass = Bandpass() controlBandpass.imsimBandpass() ff = controlSed.calcFluxNorm(self.magNorm, uBandpass) controlSed.multiplyFluxNorm(ff) a_int, b_int = controlSed.setupCCMab() controlSed.addCCMDust(a_int, b_int, A_v=0.1, R_v=3.1) nSamples = 3 rng = np.random.RandomState(42) pointingRaList = rng.random_sample(nSamples)*360.0 pointingDecList = rng.random_sample(nSamples)*180.0 - 90.0 rotSkyPosList = rng.random_sample(nSamples)*360.0 fwhmList = rng.random_sample(nSamples)*1.0 + 0.3 actualCounts = None for pointingRA, pointingDec, rotSkyPos, fwhm in \ zip(pointingRaList, pointingDecList, rotSkyPosList, fwhmList): obs = ObservationMetaData(pointingRA=pointingRA, pointingDec=pointingDec, boundType='circle', boundLength=4.0, mjd=49250.0, rotSkyPos=rotSkyPos) xDisplacementList = rng.random_sample(nSamples)*60.0-30.0 yDisplacementList = rng.random_sample(nSamples)*60.0-30.0 create_text_catalog(obs, dbFileName, xDisplacementList, yDisplacementList, mag_norm=[self.magNorm]*len(xDisplacementList)) db = placementFileDBObj(dbFileName, runtable='test') cat = placementCatalog(db, obs_metadata=obs) cat.camera_wrapper = GalSimCameraWrapper(camera) if actualCounts is None: actualCounts = controlSed.calcADU(uBandpass, cat.photParams) psf = SNRdocumentPSF(fwhm=fwhm) cat.setPSF(psf) cat.write_catalog(catName) cat.write_images(nameRoot=imageRoot) objRaList = [] objDecList = [] with open(catName, 'r') as inFile: for line in inFile: if line[0] != '#': words = line.split(';') objRaList.append(np.radians(np.float(words[2]))) objDecList.append(np.radians(np.float(words[3]))) objRaList = np.array(objRaList) objDecList = np.array(objDecList) self.assertGreater(len(objRaList), 0) # make sure we aren't testing # an empty catalog/image self.check_placement(imageName, objRaList, objDecList, [fwhm]*len(objRaList), np.array([actualCounts]*len(objRaList)), cat.photParams.gain, detector, camera, obs, epoch=2000.0) if os.path.exists(dbFileName): os.unlink(dbFileName) if os.path.exists(catName): os.unlink(catName) if os.path.exists(imageName): os.unlink(imageName) if os.path.exists(scratchDir): shutil.rmtree(scratchDir)
from lsst.sims.photUtils import PhotometricParameters, Bandpass phot_params = PhotometricParameters(nexp=1, exptime=30.0, gain=1) imsim = Bandpass() imsim.imsimBandpass() target=20000.0 for name in galaxy_sed_list: magnorm_interp[name] = {} magnorm_interp[name]['z'] = np.arange(0.0, 2.4, 0.2) magnorm_interp[name]['mag'] = np.zeros(len(magnorm_interp[name]['z']), dtype=float) for i_zz, zz in enumerate(magnorm_interp[name]['z']): ss = Sed() ss.readSED_flambda(os.path.join(galaxy_dir, name)) mag = ss.calcMag(imsim) ss.redshiftSED(zz, dimming=True) cts = ss.calcADU(bp_dict['r'], photParams=phot_params) magnorm = mag -2.5*np.log10(target/cts) ss = Sed() ss.readSED_flambda(os.path.join(galaxy_dir, name)) fnorm = ss.calcFluxNorm(magnorm, imsim) ss.multiplyFluxNorm(fnorm) ss.redshiftSED(zz, dimming=True) new_cts = ss.calcADU(bp_dict['r'], photParams=phot_params) d_ct = np.abs(new_cts-target) magnorm_interp[name]['mag'][i_zz] = magnorm if d_ct>500.0: raise RuntimeWarning('d_ct %e' % d_ct)
# scaled properly, in other bandpasses). mag_desired = 24.5 print "Now going to apply a scaling factor to the SED to set magnitude to %.4f" %(mag_desired) # Calculate the scaling factor. fluxnorm = star.calcFluxNorm(mag_desired, rband) # Apply the scaling factor. star.multiplyFluxNorm(fluxnorm) # Try the magnitude calculation again. mag = star.calcMag(rband) print "After scaling, magnitude of SED is now %.4f (desired magnitude was %.4f)" %(mag, mag_desired) # And let's calculate what the expected photon counts for LSST would be. counts = star.calcADU(rband, expTime=30) print "This would correspond to roughly %f counts in the LSST focal plane, in a 30s exposure." %(counts) # For fun, let's see what else can happen. ebv = 0.5 print "" print "Let's try adding %.2f E(B-V) dust extinction to this star." %(ebv) a, b = star.setupCCMab() # You can use addCCMDust on the 'star' object itself, but I'm illustrating here how you could also # do otherwise - preserve the original 'star' object as is, and create a new Sed object that does # include the effects of dust ('dustystar'). Star's data will be unchanged by the dust. dustywavelen, dustyflambda = star.addCCMDust(a, b, ebv=ebv, wavelen=star.wavelen, flambda=star.flambda) dustystar = Sed(wavelen=dustywavelen, flambda=dustyflambda) magdust = dustystar.calcMag(rband) print "With this dust, the magnitude of the star in this bandpass is now %.4f." %(magdust)
def calcM5(hardware, system, atmos, title='m5', X=1.0, return_t2_values=False): """ Calculate m5 values for all filters in hardware and system. Prints all values that go into "table 2" of the overview paper. Returns dictionary of m5 values. """ # photParams stores default values for the exposure time, nexp, size of the primary, # readnoise, gain, platescale, etc. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/PhotometricParameters.py effarea = np.pi * (6.423/2.*100.)**2 photParams_zp = PhotometricParameters(exptime=1, nexp=1, gain=1, effarea=effarea, readnoise=8.8, othernoise=0, darkcurrent=0.2) photParams = PhotometricParameters(gain=1.0, effarea=effarea, readnoise=8.8, othernoise=0, darkcurrent=0.2) photParams_infinity = PhotometricParameters(gain=1.0, readnoise=0, darkcurrent=0, othernoise=0, effarea=effarea) # lsstDefaults stores default values for the FWHMeff. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/LSSTdefaults.py lsstDefaults = LSSTdefaults() darksky = Sed() darksky.readSED_flambda(os.path.join(getPackageDir('syseng_throughputs'), 'siteProperties', 'darksky.dat')) flatSed = Sed() flatSed.setFlatSED() m5 = {} Tb = {} Sb = {} kAtm = {} Cm = {} dCm_infinity = {} sourceCounts = {} skyCounts = {} skyMag = {} gamma = {} zpT = {} FWHMgeom = {} FWHMeff = {} for f in system: zpT[f] = system[f].calcZP_t(photParams_zp) eff_wavelen = system[f].calcEffWavelen()[1] FWHMeff[f] = scale_seeing(0.62, eff_wavelen, X)[0] m5[f] = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams, FWHMeff=FWHMeff[f]) fNorm = flatSed.calcFluxNorm(m5[f], system[f]) flatSed.multiplyFluxNorm(fNorm) sourceCounts[f] = flatSed.calcADU(system[f], photParams=photParams) # Calculate the Skycounts expected in this bandpass. skyCounts[f] = (darksky.calcADU(hardware[f], photParams=photParams) * photParams.platescale**2) # Calculate the sky surface brightness. skyMag[f] = darksky.calcMag(hardware[f]) # Calculate the gamma value. gamma[f] = SignalToNoise.calcGamma(system[f], m5[f], photParams) # Calculate the "Throughput Integral" (this is the hardware + atmosphere) dwavelen = np.mean(np.diff(system[f].wavelen)) Tb[f] = np.sum(system[f].sb / system[f].wavelen) * dwavelen # Calculate the "Sigma" 'system integral' (this is the hardware only) Sb[f] = np.sum(hardware[f].sb / hardware[f].wavelen) * dwavelen # Calculate km - atmospheric extinction in a particular bandpass kAtm[f] = -2.5*np.log10(Tb[f] / Sb[f]) # Calculate the Cm and Cm_Infinity values. # m5 = Cm + 0.5*(msky - 21) + 2.5log10(0.7/FWHMeff) + 1.25log10(t/30) - km(X-1.0) # Assumes atmosphere used in system throughput is X=1.0 Cm[f] = (m5[f] - 0.5*(skyMag[f] - 21) - 2.5*np.log10(0.7/FWHMeff[f]) - 1.25*np.log10((photParams.exptime*photParams.nexp)/30.0) + kAtm[f]*(X-1.0)) # Calculate Cm_Infinity by setting readout noise to zero. m5inf = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams_infinity, FWHMeff=FWHMeff[f]) Cm_infinity = (m5inf - 0.5*(skyMag[f] - 21) - 2.5*np.log10(0.7/FWHMeff[f]) - 1.25*np.log10((photParams.exptime*photParams.nexp)/30.0) + kAtm[f]*(X-1.0)) dCm_infinity[f] = Cm_infinity - Cm[f] print('Filter FWHMeff FWHMgeom SkyMag SkyCounts Zp_t Tb Sb kAtm Gamma Cm dCm_infinity m5 SourceCounts') for f in ('u', 'g' ,'r', 'i', 'z', 'y'): FWHMgeom[f] = SignalToNoise.FWHMeff2FWHMgeom(FWHMeff[f]) print('%s %.2f %.2f %.2f %.1f %.2f %.3f %.3f %.4f %.6f %.2f %.2f %.2f %.2f'\ % (f, FWHMeff[f], FWHMgeom[f], skyMag[f], skyCounts[f], zpT[f], Tb[f], Sb[f], kAtm[f], gamma[f], Cm[f], dCm_infinity[f], m5[f], sourceCounts[f])) for f in filterlist: m5_cm = Cm[f] + 0.5*(skyMag[f] - 21.0) + 2.5*np.log10(0.7/FWHMeff[f]) - kAtm[f]*(X-1.0) if m5_cm - m5[f] > 0.001: raise ValueError('Cm calculation for %s band is incorrect! m5_cm != m5_snr' %f) if return_t2_values: return {'FWHMeff': FWHMeff, 'FWHMgeom': FWHMgeom, 'skyMag': skyMag, 'skycounts': skyCounts, 'zpT': zpT, 'Tb': Tb, 'Sb': Sb, 'kAtm': kAtm, 'gamma': gamma, 'Cm': Cm, 'dCm_infinity': dCm_infinity, 'm5': m5, 'sourceCounts': sourceCounts} # Show what these look like individually (add sky & m5 limits on throughput curves) plt.figure() for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2, label=f) plt.plot(atmos.wavelen, atmos.sb, 'k:', label='X=1.0') plt.legend(loc='center right', fontsize='smaller') plt.xlim(300, 1100) plt.ylim(0, 1) plt.xlabel('Wavelength (nm)') plt.ylabel('Throughput') plt.title('System Throughputs') plt.grid(True) plt.savefig('../plots/throughputs.png', format='png') plt.figure() ax = plt.gca() # Add dark sky ax2 = ax.twinx() plt.sca(ax2) skyab = np.zeros(len(darksky.fnu)) condition = np.where(darksky.fnu > 0) skyab[condition] = -2.5*np.log10(darksky.fnu[condition]) - darksky.zp ax2.plot(darksky.wavelen, skyab, 'k-', linewidth=0.8, label='Dark sky mags') ax2.set_ylabel('AB mags') ax2.set_ylim(24, 14) plt.sca(ax) # end of dark sky handles = [] for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2) myline = mlines.Line2D([], [], color=filtercolors[f], linestyle='-', linewidth=2, label = '%s: m5 %.1f (sky %.1f)' %(f, m5[f], skyMag[f])) handles.append(myline) plt.plot(atmos.wavelen, atmos.sb, 'k:', label='Atmosphere, X=1.0') # Add legend for dark sky. myline = mlines.Line2D([], [], color='k', linestyle='-', label='Dark sky AB mags/arcsec^2') handles.append(myline) # end of dark sky legend line plt.legend(loc=(0.01, 0.69), handles=handles, fancybox=True, numpoints=1, fontsize='small') plt.ylim(0, 1) plt.xlim(300, 1100) plt.xlabel('Wavelength (nm)') plt.ylabel('Fractional Throughput Response') plt.title('System total response curves %s' %(title)) plt.savefig('../plots/system+sky' + title + '.png', format='png', dpi=600) return m5
class Telescope(Throughputs): def __init__(self, airmass=1, atmos=True, aerosol=False, libradtran=False, **kwargs): Throughputs.__init__(self, **kwargs) print("**** Telescope.__init__******") #self.filters=filterlist params = [ 'mag_sky', 'm5', 'FWHMeff', 'Tb', 'Sigmab', 'zp', 'counts_zp', 'Skyb', 'flux_sky' ] self.data = {} for par in params: self.data[par] = {} self.data['FWHMeff'] = dict( zip('ugrizy', [0.92, 0.87, 0.83, 0.80, 0.78, 0.76])) self.atmos = atmos self.libradtran = libradtran self.Load_Atmosphere(airmass) self.sed = None self.sedAB0 = None self.Inputs() self.Sky() self.ZP() self.Set_SED_AB0() # set a AB reference source #------------------------------------------------------------------------- @property def FWHMeff(self): return self.data['FWHMeff'] #------------------------------------------------------------------------- @property def mag_sky(self): return self.data['mag_sky'] #------------------------------------------------------------------------- @property def m5(self): return self.data['m5'] #------------------------------------------------------------------------- @property def Tb(self): return self.data['Tb'] #------------------------------------------------------------------------- @property def Sigmab(self): return self.data['Sigmab'] #------------------------------------------------------------------------- @property def zp(self): return self.data['zp'] #------------------------------------------------------------------------- @property def ADU_zp(self): return self.data['counts_zp'] #------------------------------------------------------------------------- @property def flux_sky(self): return self.data['flux_sky'] #------------------------------------------------------------------------- def Inputs(self): for filtre in self.filterlist: myup = self.Calc_Integ_Sed(self.darksky, self.system[filtre]) self.data['Tb'][filtre] = self.Calc_Integ(self.atmosphere[filtre]) self.data['Sigmab'][filtre] = self.Calc_Integ(self.system[filtre]) self.data['mag_sky'][filtre] = -2.5 * np.log10( myup / (3631. * self.Sigmab[filtre])) #------------------------------------------------------------------------- def Sky(self): for filtre in self.filterlist: self.Calc_m5(filtre) #------------------------------------------------------------------------- def Calc_m5(self, filtre): """ Calc_m5(filtre): Compute m5 or SNR at five sigma Tool function implemented by Phillie Gris (IN2P3) """ # get telescope passband (no atmosphere) filtre_trans = self.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) # create a Flat sed S_nu from the sky brightness magnitude flatSedb = Sed() flatSedb.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * self.mag_sky[filtre]) flatSedb.multiplyFluxNorm(flux0b) # Get LSST photometric parameters photParams = PhotometricParameters(bandpass=filtre) norm = photParams.platescale**2 / 2. * photParams.exptime / photParams.gain # Use LSST sims (SignalToNoise) to calculate M5 with atmosphere or without atmosphere if self.atmos: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.atmosphere[filtre], self.system[filtre], photParams=photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU(bandpass=self.atmosphere[filtre], photParams=photParams) self.data['flux_sky'][filtre] = adu_int * norm else: self.data['m5'][filtre] = SignalToNoise.calcM5( flatSedb, self.system[filtre], self.system[filtre], photParams=photParams, FWHMeff=self.FWHMeff[filtre]) adu_int = flatSedb.calcADU(bandpass=self.system[filtre], photParams=photParams) self.data['flux_sky'][filtre] = adu_int * norm #------------------------------------------------------------------------- def ZP(self): for filtre in self.filterlist: self.ZP_filtre(filtre) #print 'zeropoints',self.data['zp'],self.data['counts_zp'] #self.data['zp']=dict(zip(['u','g','r','i','z','y'],[27.03,28.53,28.27,27.91,27.49,26.78])) #------------------------------------------------------------------------- def ZP_filtre(self, filtre): """ ZP_filtre() : Compute zero point in filter band - platescale is 0.2 arcsec per pixel Tool function implemented by Phillie Gris (IN2P3) """ # extract parameters from lsst_sims photParams = PhotometricParameters(bandpass=filtre) # compute Diameter in meters : D=2*R = 2*sqrt(S/pi) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter # AB flux is 3.6307805477e-20 erg/cm2/s/Hz or 3.6307805477e-16 erg/m2/s/Hz # or 3.6307e-23 J/m2/s/Hz, h=6.626e-34 J.s # What is the meaning of this Cte ???? # especcialy what is 1e36 ? Cte = 3631. * np.pi * Diameter**2 * 2. * photParams.exptime / 4 / h / 1.e36 #print('Telescope::ZP_filtre: hello Cte=',Cte, ' Diam=',Diameter, 'h=',h,' exptime=',photParams.exptime) # What is the meaning of Skyb ????? self.data['Skyb'][filtre] = Cte * np.power( Diameter / 6.5, 2.) * np.power( 2. * photParams.exptime / 30., 2.) * np.power( photParams.platescale, 2.) * np.power( 10., 0.4 * (25. - self.mag_sky[filtre])) * self.Sigmab[filtre] #What is the meaning of Sigmab, Tb, Zb such Zb is used to calculate zero point Zb = 181.8 * np.power(Diameter / 6.5, 2.) * self.Tb[filtre] mbZ = 25. + 2.5 * np.log10(Zb) #filter without atmosphere filtre_trans = self.system[filtre] wavelen_min, wavelen_max, wavelen_step = filtre_trans.getWavelenLimits( None, None, None) bandpass = Bandpass(wavelen=filtre_trans.wavelen, sb=filtre_trans.sb) flatSed = Sed() flatSed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0 = np.power(10., -0.4 * mbZ) flatSed.multiplyFluxNorm(flux0) photParams = PhotometricParameters(bandpass=filtre) counts = flatSed.calcADU( bandpass, photParams=photParams) #number of counts for exptime self.data['zp'][filtre] = mbZ #print('Telescope::ZP_filtre hello',counts/self.photParams.exptime) self.data['counts_zp'][filtre] = counts / 2. * photParams.exptime #------------------------------------------------------------------------- def Calc_Integ(self, bandpass): """ Calc_Integ(): Compute sum F(lambda).dlambda/lambda in band (no unit) - F(lamba) : pass band - lambda : wavelength Tool function implemented by Phillie Gris (IN2P3) """ resu = 0. dlam = 0 for i, wave in enumerate(bandpass.wavelen): if i < len(bandpass.wavelen) - 1: dlam = bandpass.wavelen[i + 1] - wave resu += dlam * bandpass.sb[i] / wave #resu+=dlam*bandpass.sb[i] return resu #------------------------------------------------------------------------- def Calc_Integ_Sed(self, sed, bandpass, wavelen=None, fnu=None): """ Calc_Integ_Sed(self,sed,bandpass,wavelen=None, fnu=None) Compute sum of S_nu*F(lambda).dlambda/lambda in band units in erg/cm2/s/Hz - S_nu : SED in erg/cm2/s/Hz - F(lamba) : pass band - lambda : wavelength - force to use the SED S_nu (erg/cm2/s/Hz) instead of S_lamba (erg/cm2/s/nm) Tool function implemented by Phillie Gris (IN2P3) """ use_self = sed._checkUseSelf(wavelen, fnu) # Use self values if desired, otherwise use values passed to function. if use_self: # Calculate fnu if required. if sed.fnu is None: # If fnu not present, calculate. (does not regrid). sed.flambdaTofnu() wavelen = sed.wavelen fnu = sed.fnu # Make sure wavelen/fnu are on the same wavelength grid as bandpass. wavelen, fnu = sed.resampleSED(wavelen, fnu, wavelen_match=bandpass.wavelen) fnu = np.nan_to_num( fnu) # SDC(29/06/18) reset to 0 out of band where there are nan # Calculate the number of photons. nphoton = (fnu / wavelen * bandpass.sb).sum() dlambda = wavelen[1] - wavelen[0] return nphoton * dlambda #--------------------------------------------------------------- def CalcMyMagnitudes(self): """ CalcMyMagnitudes(sed) - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 4th 2018 Check how LSST Sim compute the magnitudes. Compute here with self.Calc_Integ_Sed() and Sed.calcMag() Used just for debug purpose """ all_mag1 = [] all_mag2 = [] #sed.flambdaTofnu() for i, band in enumerate(self.filterlist): filter = self.lsst_atmos[band] #phinorm=filter.sbTophi() # resample the wavelength each time for the filter wl, fnu = self.sed.getSED_fnu() wavelen, fnu = self.sed.resampleSED(wl, fnu, wavelen_match=filter.wavelen) fnu = np.nan_to_num( fnu ) # SDC(29/06/18) reset to 0 out of band where there are nan self.sed = Sed(wavelen=wavelen, fnu=fnu, name=self.sed.name) mag1 = self.sed.calcMag(bandpass=filter, wavelen=wavelen, fnu=fnu) mag2 = -2.5 * np.log10(self.Calc_Integ_Sed(self.sed, filter)) all_mag1.append(mag1) all_mag2.append(mag2) print('CalcMyMagnitudes :: band = {}, mag1= {} , mag2= {}'.format( i, mag1, mag2)) return np.array(all_mag1), np.array(all_mag2) #--------------------------------------------------------------- def CalcMyZP(self): """ CalcMyZP() - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 5th 2018 Calculate the Zero Points for all bands. This calculation should assume 1 second exposure and unit electronic gain """ for i, band in enumerate(self.filterlist): #for filtre in self.filterlist: filtre = self.lsst_atmos[band] # parameters photParams = PhotometricParameters(bandpass=band) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter exptime = 2 * photParams.exptime gain = photParams.gain # lsst sim calculation # by definition Zero point is defined for unit gain and unit exposure zp1 = filtre.calcZP_t(photParams) + 2.5 * np.log10(gain / exptime) # my calculation : Zero point should be calculated for unit gain and per second of exposure # in Jansky divided by J (photon energy E=hc/lambda) Snu_Tl_dldivl_AB0 = self.Calc_Integ_Sed(self.sedAB0, filtre) # in photoelectron per meter squared per meters per second # h is the Planck constant h=6.626x 10^-34 J.s dN_PhEl_AB0 = Snu_Tl_dldivl_AB0 / h * 1e-26 * np.pi * Diameter**2 / 4. zp2 = +2.5 * np.log10(dN_PhEl_AB0) print( "CalcMyZP :: band = {}, zp1(lsst_sim) = {}, zp2(me)= {}, deltaZP= {}" .format(i, zp1, zp2, zp1 - zp2)) #--------------------------------------------------------------- def CalcMyPhElMagnitudes(self): """ CalcMyElectronagnitudes(sed) - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 5th 2018 Calculate the instrumental magnitude (Photoelectrn unit) for all bands. """ all_magPhEl = [] for i, band in enumerate(self.filterlist): filter = self.lsst_atmos[band] #typical parameters of the band photParams = PhotometricParameters(bandpass=band) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter exptime = 2 * photParams.exptime # resample the wavelength each time for the filter wl, fnu = self.sed.getSED_fnu() wavelen, fnu = self.sed.resampleSED(wl, fnu, wavelen_match=filter.wavelen) fnu = np.nan_to_num( fnu ) # SDC(29/06/18) reset to 0 out of band where there are nan #this SED_nu is now in Jansky, units of 10-23 erg/cm2/s/Hz # 1 erg=10-7 J # 1 cm^-2 = 10^4 m^-2 # we have to multiply the SED_nu by 10-26 to be in J/m2/s/Hz self.sed = Sed(wavelen=wavelen, fnu=fnu, name=self.sed.name) # in Jansky divided by J (photon energy E=hc/lambda) Snu_Tl_dldivl = self.Calc_Integ_Sed(self.sed, filter) # in photoelectron per meter squared per meters per second # h is the Planck constant h=6.626x 10^-34 J.s dN_el = Snu_Tl_dldivl / h * 1e-26 * np.pi * Diameter**2 / 4. * exptime mag_el = -2.5 * np.log10(dN_el) print('CalcMyPhElMagnitudes :: band = {}, mag= {}'.format( i, mag_el)) all_magPhEl.append(mag_el) return np.array(all_magPhEl) #--------------------------------------------------------------- def CalcMyADUMagnitudes(self): """ CalcMyADUMagnitudes(sed) - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 5th 2018 Calculate the instrumental magnitude (ADU unit) for all bands. """ all_magADU = [] for i, band in enumerate(self.filterlist): filter = self.lsst_atmos[band] #typical parameters of the band photParams = PhotometricParameters(bandpass=band) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter exptime = 2 * photParams.exptime gain = photParams.gain # resample the wavelength each time for the filter wl, fnu = self.sed.getSED_fnu() wavelen, fnu = self.sed.resampleSED(wl, fnu, wavelen_match=filter.wavelen) fnu = np.nan_to_num( fnu ) # SDC(29/06/18) reset to 0 out of band where there are nan #this SED_nu is now in Jansky, units of 10-23 erg/cm2/s/Hz # 1 erg=10-7 J # 1 cm^-2 = 10^4 m^-2 # we have to multiply the SED_nu by 10-26 to be in J/m2/s/Hz self.sed = Sed(wavelen=wavelen, fnu=fnu, name=self.sed.name) # in Jansky divided by J (photon energy E=hc/lambda) Snu_Tl_dldivl = self.Calc_Integ_Sed(self.sed, filter) # in photoelectron per meter squared per meters per second # h is the Planck constant h=6.626x 10^-34 J.s dN_ADU = Snu_Tl_dldivl / h * 1e-26 * np.pi * Diameter**2 / 4. * exptime / gain mag_ADU = -2.5 * np.log10(dN_ADU) mag_ADU2 = -2.5 * np.log10( self.sed.calcADU(bandpass=filter, photParams=photParams, wavelen=wavelen, fnu=fnu)) print( 'CalcMyADUMagnitudes :: band = {}, mag1= {}, mag2={}, deltaM={}' .format(i, mag_ADU, mag_ADU2, mag_ADU - mag_ADU2)) all_magADU.append(mag_ADU) return np.array(all_magADU) #--------------------------------------------------------------- def CalcMyADUMagnitude_filter(self, band): """ CalcMyADUMagnitude_filter(band) - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 5th 2018 Calculate the instrumental magnitude (ADU unit) for one band. """ filter = self.lsst_atmos[band] #typical parameters of the band photParams = PhotometricParameters(bandpass=band) Diameter = 2. * np.sqrt( photParams.effarea * 1.e-4 / np.pi) # diameter in meter exptime = 2 * photParams.exptime gain = photParams.gain # resample the wavelength each time for the filter wl, fnu = self.sed.getSED_fnu() wavelen, fnu = self.sed.resampleSED(wl, fnu, wavelen_match=filter.wavelen) fnu = np.nan_to_num( fnu) # SDC(29/06/18) reset to 0 out of band where there are nan #this SED_nu is now in Jansky, units of 10-23 erg/cm2/s/Hz # 1 erg=10-7 J # 1 cm^-2 = 10^4 m^-2 # we have to multiply the SED_nu by 10-26 to be in J/m2/s/Hz self.sed = Sed(wavelen=wavelen, fnu=fnu, name=self.sed.name) # in Jansky divided by J (photon energy E=hc/lambda) Snu_Tl_dldivl = self.Calc_Integ_Sed(self.sed, filter) # in photoelectron per meter squared per meters per second # h is the Planck constant h=6.626x 10^-34 J.s dN_ADU = Snu_Tl_dldivl / h * 1e-26 * np.pi * Diameter**2 / 4. * exptime / gain mag_ADU = -2.5 * np.log10(dN_ADU) mag_ADU2 = -2.5 * np.log10( self.sed.calcADU(bandpass=filter, photParams=photParams, wavelen=wavelen, fnu=fnu)) #print('CalcMyADUMagnitude_filter :: band = {}, mag1(me)= {}, mag2(lsst_sim)={}, deltaM={}'.format(band,mag_ADU,mag_ADU2,mag_ADU-mag_ADU2)) return mag_ADU #--------------------------------------------------------------------- def CalcMyABMagnitudes(self): """ CalcMyABMagnitudes() - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 4th 2018 Calculate the magnitude in AB system unit for all bands. """ all_magAB = [] for i, band in enumerate(self.filterlist): filter = self.lsst_atmos[band] # resample the wavelength each time for the filter wl, fnu = self.sed.getSED_fnu() wavelen, fnu = self.sed.resampleSED(wl, fnu, wavelen_match=filter.wavelen) fnu = np.nan_to_num( fnu ) # SDC(29/06/18) reset to 0 out of band where there are nan self.sed = Sed(wavelen=wavelen, fnu=fnu, name=self.sed.name) mag1 = -2.5 * np.log10(self.Calc_Integ_Sed(self.sed, filter)) mag2 = -2.5 * np.log10(self.Calc_Integ_Sed(self.sedAB0, filter)) all_magAB.append(mag1 - mag2) mag3 = self.sed.calcMag(bandpass=filter, wavelen=wavelen, fnu=fnu) print( 'CalcMyABMagnitudes :: band = {}, mag1={} , mag2={} , deltaM(me)={}, mag3(lsst)={}' .format(i, mag1, mag2, mag1 - mag2, mag3)) return np.array(all_magAB) #--------------------------------------------------------------------- def CalcMyABMagnitude_filter(self, band): """ CalcMyABMagnitudes_filter() - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 4th 2018 Calculate the magnitude in AB system unit for all bands. """ filter = self.lsst_atmos[band] # resample the wavelength each time for the filter wl, fnu = self.sed.getSED_fnu() wavelen, fnu = self.sed.resampleSED(wl, fnu, wavelen_match=filter.wavelen) fnu = np.nan_to_num( fnu) # SDC(29/06/18) reset to 0 out of band where there are nan self.sed = Sed(wavelen=wavelen, fnu=fnu, name=self.sed.name) mag1 = -2.5 * np.log10(self.Calc_Integ_Sed(self.sed, filter)) mag2 = -2.5 * np.log10(self.Calc_Integ_Sed(self.sedAB0, filter)) mag3 = self.sed.calcMag(bandpass=filter, wavelen=wavelen, fnu=fnu) #print('CalcMyABMagnitude_filter :: band = {}, mag1={} , mag2={} , deltaM(me)={}, mag3(lsst)={}'.format(band,mag1,mag2,mag1-mag2,mag3)) return mag3 #--------------------------------------------------------------- def CalcMyABMagnitudesErrors(self): """ CalcMyABMagnitudesErrors(self) - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 4th 2018 Calculate magnitude errors for all bands """ all_magABErr = [] for i, band in enumerate(self.filterlist): filtre_atm = self.lsst_atmos[band] filtre_syst = self.lsst_system[band] wavelen_min, wavelen_max, wavelen_step = filtre_syst.getWavelenLimits( None, None, None) photParams = PhotometricParameters(bandpass=band) FWHMeff = self.data['FWHMeff'][band] # create a Flat sed S_nu from the sky brightness magnitude skysed = Sed() skysed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * self.mag_sky[band]) skysed.multiplyFluxNorm(flux0b) #calcMagError filled according doc magerr=SignalToNoise.calcMagError_sed( \ self.sed,filtre_atm,skysed,filtre_syst,photParams,FWHMeff,verbose=False) all_magABErr.append(magerr) return np.array(all_magABErr) #--------------------------------------------------------------- def CalcMyABMagnitudesError_filter(self, band, SkyBrightnessMag, FWHMGeom): """ CalcMyABMagnitudesError_filter(self,band,SkyBrightnessMag,FWHMGeom) - author : Sylvie Dagoret-Campagne - affiliation : LAL/IN2P3/CNRS/FRANCE - date : July 5th 2018 Calculate magnitude errors for one band. Input args: - band : filter band - SkyBrighnessMag : Sky Brighness Magnitude in the band - FWHMGeom : Geometrical PSF in the band """ filtre_atm = self.lsst_atmos[band] filtre_syst = self.lsst_system[band] wavelen_min, wavelen_max, wavelen_step = filtre_syst.getWavelenLimits( None, None, None) #calculation of effective PSF FWHMeff = SignalToNoise.FWHMgeom2FWHMeff(FWHMGeom) photParams = PhotometricParameters(bandpass=band) # create a Flat sed S_nu from the sky brightness magnitude skysed = Sed() skysed.setFlatSED(wavelen_min, wavelen_max, wavelen_step) flux0b = np.power(10., -0.4 * SkyBrightnessMag) skysed.multiplyFluxNorm(flux0b) #calcMagError filled according doc mag_err = SignalToNoise.calcMagError_sed(self.sed, filtre_atm, skysed, filtre_syst, photParams, FWHMeff, verbose=False) return mag_err #--------------------------------------------------------------- def Plot_Filter(self): plt.figure(figsize=(5, 4)) for i, band in enumerate(self.filterlist): filter = self.lsst_atmos[band] #phinorm=filter.sbTophi() #print('phinorm',phinorm) plt.plot(filter.wavelen, filter.sb, 'k:') #plt.plot(filter.wavelen, phinorm, 'r.') plt.show() #------------------------------------------------------------------------- def flux_to_mag(self, flux, band, zp=None): if zp is None: zp = self.zero_points(band) print('Telescope::flux_to_mag: zp', zp, band) m = -2.5 * np.log10(flux) + zp return m #------------------------------------------------------------------------- def mag_to_flux(self, mag, band, zp=None): if zp is None: zp = self.zero_points(band) return np.power(10., -0.4 * (mag - zp)) #------------------------------------------------------------------------- def zero_points(self, band): return np.asarray([self.zp[b] for b in band]) #------------------------------------------------------------------------- def mag_to_flux_e_sec(self, mag, band, trans, sed): #this should be debugged at some point photrams = PhotometricParameters(bandpass=band) E_per_sec = sed.calcADU(bandpass=trans, photParams=photParams) e_per_sec /= exptime / photParams.gain return e_per_sec #------------------------------------------------------------------------- def Set_SEDAB(self): """ Set AB source : Enter the SED in erg/cm2/s/nm, """ M0 = 48.6 # magnitude of a AB source S_nu0 = 10**(-M0 / 2.5) # flux in erg/cm2/s/Hz : 3.630780547701003e-20 c = 2.99792458e10 # speed of light in cm/s in CGS nm_to_cm = 1e-7 # conversion nm to cm wavelength = np.arange(300., 1151., 1) S_lambda0 = S_nu0 * c / (nm_to_cm) / wavelength**2 # in erg/cm2/s/nm self.Set_SED(wavel=wavelength, newsed=S_lambda0, name='AB-source') #------------------------------------------------------------------------- def Set_SED_AB0(self): """ Set AB source : Enter the SED in erg/cm2/s/nm, """ M0 = 48.6 # magnitude of a AB source S_nu0 = 10**(-M0 / 2.5) # flux in erg/cm2/s/Hz : 3.630780547701003e-20 c = 2.99792458e10 # speed of light in cm/s in CGS nm_to_cm = 1e-7 # conversion nm to cm wavelength = np.arange(300., 1151., 1) S_lambda0 = S_nu0 * c / (nm_to_cm) / wavelength**2 # in erg/cm2/s/nm self.sedAB0 = Sed(wavelen=wavelength, flambda=S_lambda0, fnu=None, name='AB0-source') self.sedAB0.flambdaTofnu() #------------------------------------------------------------------------- def Set_SED(self, wavel, newsed, name='Pickles'): """ Set_SED(self,wavel,sed): Enter the SED in erg/cm2/s/nm, """ self.sed = Sed(wavelen=wavel, flambda=newsed, fnu=None, name=name) self.sed.flambdaTofnu() #------------------------------------------------------------------------- def Plot_SED(self): wl, fnu = self.sed.getSED_fnu() plt.plot(wl, fnu, 'b-') plt.xlabel("$\lambda$ (nm)") plt.ylabel("Flux in Jansky ($10^{-23}erg/cm^2/s/Hz$") title = 'SED ' plt.title(title) plt.grid(True)
def calcM5(hardware, system, atmos, title='m5', return_t2_values=False): """ Calculate m5 values for all filters in hardware and system. Prints all values that go into "table 2" of the overview paper. Returns dictionary of m5 values. """ # photParams stores default values for the exposure time, nexp, size of the primary, # readnoise, gain, platescale, etc. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/PhotometricParameters.py effarea = np.pi * (6.423/2.*100.)**2 photParams_zp = PhotometricParameters(exptime=1, nexp=1, gain=1, effarea=effarea, readnoise=8.8, othernoise=0, darkcurrent=0.2) photParams = PhotometricParameters(gain=1.0, effarea=effarea, readnoise=8.8, othernoise=0, darkcurrent=0.2) photParams_infinity = PhotometricParameters(gain=1.0, readnoise=0, darkcurrent=0, othernoise=0, effarea=effarea) # lsstDefaults stores default values for the FWHMeff. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/LSSTdefaults.py lsstDefaults = LSSTdefaults() darksky = Sed() darksky.readSED_flambda(os.path.join(getPackageDir('syseng_throughputs'), 'siteProperties', 'darksky.dat')) flatSed = Sed() flatSed.setFlatSED() m5 = {} Tb = {} Sb = {} kAtm = {} Cm = {} dCm_infinity = {} sourceCounts = {} skyCounts = {} skyMag = {} gamma = {} zpT = {} FWHMgeom = {} FWHMeff = {} for f in system: zpT[f] = system[f].calcZP_t(photParams_zp) m5[f] = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams, FWHMeff=lsstDefaults.FWHMeff(f)) fNorm = flatSed.calcFluxNorm(m5[f], system[f]) flatSed.multiplyFluxNorm(fNorm) sourceCounts[f] = flatSed.calcADU(system[f], photParams=photParams) # Calculate the Skycounts expected in this bandpass. skyCounts[f] = (darksky.calcADU(hardware[f], photParams=photParams) * photParams.platescale**2) # Calculate the sky surface brightness. skyMag[f] = darksky.calcMag(hardware[f]) # Calculate the gamma value. gamma[f] = SignalToNoise.calcGamma(system[f], m5[f], photParams) # Calculate the "Throughput Integral" (this is the hardware + atmosphere) dwavelen = np.mean(np.diff(system[f].wavelen)) Tb[f] = np.sum(system[f].sb / system[f].wavelen) * dwavelen # Calculate the "Sigma" 'system integral' (this is the hardware only) Sb[f] = np.sum(hardware[f].sb / hardware[f].wavelen) * dwavelen # Calculate km - atmospheric extinction in a particular bandpass kAtm[f] = -2.5*np.log10(Tb[f] / Sb[f]) # Calculate the Cm and Cm_Infinity values. # m5 = Cm + 0.5*(msky - 21) + 2.5log10(0.7/FWHMeff) + 1.25log10(t/30) - km(X-1.0) # Assumes atmosphere used in system throughput is X=1.0 X = 1.0 Cm[f] = (m5[f] - 0.5*(skyMag[f] - 21) - 2.5*np.log10(0.7/lsstDefaults.FWHMeff(f)) - 1.25*np.log10((photParams.exptime*photParams.nexp)/30.0) + kAtm[f]*(X-1.0)) # Calculate Cm_Infinity by setting readout noise to zero. m5inf = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams_infinity, FWHMeff=lsstDefaults.FWHMeff(f)) Cm_infinity = (m5inf - 0.5*(skyMag[f] - 21) - 2.5*np.log10(0.7/lsstDefaults.FWHMeff(f)) - 1.25*np.log10((photParams.exptime*photParams.nexp)/30.0) + kAtm[f]*(X-1.0)) dCm_infinity[f] = Cm_infinity - Cm[f] print 'Filter FWHMeff FWHMgeom SkyMag SkyCounts Zp_t Tb Sb kAtm Gamma Cm dCm_infinity m5 SourceCounts' for f in ('u', 'g' ,'r', 'i', 'z', 'y'): FWHMeff[f] = lsstDefaults.FWHMeff(f) FWHMgeom[f] = SignalToNoise.FWHMeff2FWHMgeom(lsstDefaults.FWHMeff(f)) print '%s %.2f %.2f %.2f %.1f %.2f %.3f %.3f %.4f %.6f %.2f %.2f %.2f %.2f'\ % (f, FWHMeff[f], FWHMgeom[f], skyMag[f], skyCounts[f], zpT[f], Tb[f], Sb[f], kAtm[f], gamma[f], Cm[f], dCm_infinity[f], m5[f], sourceCounts[f]) if return_t2_values: return {'FHWMeff': FWHMeff, 'FWHMgeom': FWHMgeom, 'skyMag': skyMag, 'skycounts': skyCounts, 'zpT': zpT, 'Tb': Tb, 'Sb': Sb, 'kAtm': kAtm, 'gamma': gamma, 'Cm': Cm, 'dCm_infinity': dCm_infinity, 'm5': m5, 'sourceCounts': sourceCounts} for f in filterlist: m5_cm = Cm[f] + 0.5*(skyMag[f] - 21.0) + 2.5*np.log10(0.7/lsstDefaults.FWHMeff(f)) if m5_cm - m5[f] > 0.001: raise ValueError('Cm calculation for %s band is incorrect! m5_cm != m5_snr' %f) # Show what these look like individually (add sky & m5 limits on throughput curves) plt.figure() for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2, label=f) plt.plot(atmosphere.wavelen, atmosphere.sb, 'k:', label='X=1.0') plt.legend(loc='center right', fontsize='smaller') plt.xlim(300, 1100) plt.ylim(0, 1) plt.xlabel('Wavelength (nm)') plt.ylabel('Throughput') plt.title('System Throughputs') plt.grid(True) plt.savefig('../plots/throughputs.png', format='png') plt.figure() ax = plt.gca() # Add dark sky ax2 = ax.twinx() plt.sca(ax2) skyab = np.zeros(len(darksky.fnu)) condition = np.where(darksky.fnu > 0) skyab[condition] = -2.5*np.log10(darksky.fnu[condition]) - darksky.zp ax2.plot(darksky.wavelen, skyab, 'k-', linewidth=0.8, label='Dark sky mags') ax2.set_ylabel('AB mags') ax2.set_ylim(24, 14) plt.sca(ax) # end of dark sky handles = [] for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2) myline = mlines.Line2D([], [], color=filtercolors[f], linestyle='-', linewidth=2, label = '%s: m5 %.1f (sky %.1f)' %(f, m5[f], skyMag[f])) handles.append(myline) plt.plot(atmos.wavelen, atmos.sb, 'k:', label='Atmosphere, X=1.0') # Add legend for dark sky. myline = mlines.Line2D([], [], color='k', linestyle='-', label='Dark sky AB mags/arcsec^2') handles.append(myline) # end of dark sky legend line plt.legend(loc=(0.01, 0.69), handles=handles, fancybox=True, numpoints=1, fontsize='small') plt.ylim(0, 1) plt.xlim(300, 1100) plt.xlabel('Wavelength (nm)') plt.ylabel('Fractional Throughput Response') plt.title('System total response curves %s' %(title)) plt.savefig('../plots/system+sky' + title + '.png', format='png', dpi=600) return m5
out_name = os.path.join( out_dir, 'instcat_galaxy_grid_%.1f_%d.txt' % (redshift, i_filter)) with open(out_name, 'w') as instcat_handle: phosim_header['obshistid'] = i_filter * 100 + int( redshift / 0.1) + 1 write_phoSim_header(obs, instcat_handle, phosim_header) for ii, (rr, dd) in enumerate(zip(ra, dec)): unqid = ii + 1 instcat_handle.write('object %d ' % unqid) instcat_handle.write('%.17f %.17f %.6f ' % (rr, dd, magnorm)) instcat_handle.write('galaxySED/%s ' % sed_names[ii]) instcat_handle.write( '%1.f 0 0 0 0 0 point none none\n' % redshift) if i_filter == 0: ss = Sed() ss.readSED_flambda( os.path.join(galaxy_dir, sed_names[ii])) fnorm = ss.calcFluxNorm(magnorm, imsim) ss.multiplyFluxNorm(fnorm) ss.redshiftSED(redshift, dimming=True) ref_handle.write('%d %.17f %.17f ' % (unqid, rr, dd)) for bp in bp_dict: adu = ss.calcADU(bp_dict[bp], photParams=phot_params) ref_handle.write('%e ' % adu) ref_handle.write('\n')
def process_instance_catalog(catalog_name, centroid_dir, bp_dict): sed_dir = getPackageDir('sims_sed_library') i_filter = -1 obshistid = -1 with open(catalog_name, 'r') as in_file: for line in in_file: params = line.strip().split() if params[0] == 'filter': i_filter = int(params[1]) if params[0] == 'obshistid': obshistid = int(params[1]) if i_filter >= 0 and obshistid >= 0: break filter_name = 'ugrizy'[i_filter] bp = bp_dict[filter_name] objid_arr = [] flux_arr = [] redshift_arr = [] magnorm_arr = [] phot_params = PhotometricParameters(nexp=1, exptime=30.0, gain=1.0) with open(catalog_name, 'r') as in_file: for line in in_file: params = line.strip().split() if params[0] != 'object': continue sed_name = params[5] obj_id = int(params[1]) magnorm = float(params[4]) redshift = float(params[6]) spec = Sed() spec.readSED_flambda(os.path.join(sed_dir, sed_name)) fnorm = getImsimFluxNorm(spec, magnorm) spec.multiplyFluxNorm(fnorm) spec.redshiftSED(redshift, dimming=True) adu = spec.calcADU(bp, photParams=phot_params) objid_arr.append(obj_id) flux_arr.append(adu) redshift_arr.append(redshift) magnorm_arr.append(magnorm) centroid_files = os.listdir(centroid_dir) phosim_objid_arr = [] phosim_flux_arr = [] x_arr = [] y_arr = [] chip_name_arr = [] dtype = np.dtype([('id', int), ('phot', float), ('x', float), ('y', float)]) for file_name in centroid_files: if 'e_%d' % obshistid not in file_name or 'f%d' % i_filter not in file_name: continue name_params = file_name.split('_') raft = name_params[5] sensor = name_params[6] chip_name = '%s:%s,%s %s:%s,%s' % (raft[0], raft[1], raft[2], sensor[0], sensor[1], sensor[2]) full_name = os.path.join(centroid_dir, file_name) data = np.genfromtxt(full_name, dtype=dtype, skip_header=1) for line in data: phosim_objid_arr.append(line['id']) phosim_flux_arr.append(line['phot']) x_arr.append(line['x']) y_arr.append(line['y']) chip_name_arr.append(chip_name) objid_arr = np.array(objid_arr) flux_arr = np.array(flux_arr) redshift_arr = np.array(redshift_arr) magnorm_arr = np.array(magnorm_arr) phosim_objid_arr = np.array(phosim_objid_arr) phosim_flux_arr = np.array(phosim_flux_arr) x_arr = np.array(x_arr) y_arr = np.array(y_arr) chip_name_arr = np.array(chip_name_arr) sorted_dex = np.argsort(objid_arr) objid_arr = objid_arr[sorted_dex] flux_arr = flux_arr[sorted_dex] redshift_arr = redshift_arr[sorted_dex] magnorm_arr = magnorm_arr[sorted_dex] sorted_dex = np.argsort(phosim_objid_arr) phosim_objid_arr = phosim_objid_arr[sorted_dex] phosim_flux_arr = phosim_flux_arr[sorted_dex] x_arr = x_arr[sorted_dex] y_arr = y_arr[sorted_dex] chip_name_arr = chip_name_arr[sorted_dex] np.testing.assert_array_equal(phosim_objid_arr, objid_arr) return (objid_arr, flux_arr, phosim_flux_arr, redshift_arr, magnorm_arr, x_arr, y_arr, chip_name_arr, filter_name)
def test_object_extraction_stars(self): """ Test that method to get GalSimCelestialObjects from InstanceCatalogs works """ commands = desc.imsim.metadata_from_file(self.phosim_file) obs_md = desc.imsim.phosim_obs_metadata(commands) phot_params = desc.imsim.photometricParameters(commands) with desc.imsim.fopen(self.phosim_file, mode='rt') as input_: lines = [x for x in input_ if x.startswith('object')] truth_dtype = np.dtype([('uniqueId', str, 200), ('x_pupil', float), ('y_pupil', float), ('sedFilename', str, 200), ('magNorm', float), ('raJ2000', float), ('decJ2000', float), ('pmRA', float), ('pmDec', float), ('parallax', float), ('v_rad', float), ('Av', float), ('Rv', float)]) truth_data = np.genfromtxt(os.path.join(self.data_dir, 'truth_stars.txt'), dtype=truth_dtype, delimiter=';') truth_data.sort() gs_object_arr, gs_object_dict \ = sources_from_list(lines, obs_md, phot_params, self.phosim_file) id_arr = [None] * len(gs_object_arr) for i_obj in range(len(gs_object_arr)): id_arr[i_obj] = gs_object_arr[i_obj].uniqueId id_arr = sorted(id_arr) np.testing.assert_array_equal(truth_data['uniqueId'], id_arr) ######## test that pupil coordinates are correct to within ######## half a milliarcsecond x_pup_test, y_pup_test = _pupilCoordsFromRaDec( truth_data['raJ2000'], truth_data['decJ2000'], pm_ra=truth_data['pmRA'], pm_dec=truth_data['pmDec'], v_rad=truth_data['v_rad'], parallax=truth_data['parallax'], obs_metadata=obs_md) for gs_obj in gs_object_arr: i_obj = np.where(truth_data['uniqueId'] == gs_obj.uniqueId)[0][0] dd = np.sqrt((x_pup_test[i_obj] - gs_obj.xPupilRadians)**2 + (y_pup_test[i_obj] - gs_obj.yPupilRadians)**2) dd = arcsecFromRadians(dd) self.assertLess(dd, 0.0005) ######## test that fluxes are correctly calculated bp_dict = BandpassDict.loadTotalBandpassesFromFiles() imsim_bp = Bandpass() imsim_bp.imsimBandpass() phot_params = PhotometricParameters(nexp=1, exptime=30.0) for gs_obj in gs_object_arr: i_obj = np.where(truth_data['uniqueId'] == gs_obj.uniqueId)[0][0] sed = Sed() full_sed_name = os.path.join(os.environ['SIMS_SED_LIBRARY_DIR'], truth_data['sedFilename'][i_obj]) sed.readSED_flambda(full_sed_name) fnorm = sed.calcFluxNorm(truth_data['magNorm'][i_obj], imsim_bp) sed.multiplyFluxNorm(fnorm) sed.resampleSED(wavelen_match=bp_dict.wavelenMatch) a_x, b_x = sed.setupCCM_ab() sed.addDust(a_x, b_x, A_v=truth_data['Av'][i_obj], R_v=truth_data['Rv'][i_obj]) for bp in ('u', 'g', 'r', 'i', 'z', 'y'): flux = sed.calcADU(bp_dict[bp], phot_params) * phot_params.gain self.assertAlmostEqual(flux / gs_obj.flux(bp), 1.0, 10) ######## test that objects are assigned to the right chip in ######## gs_object_dict unique_id_dict = {} for chip_name in gs_object_dict: local_unique_id_list = [] for gs_object in gs_object_dict[chip_name]: local_unique_id_list.append(gs_object.uniqueId) local_unique_id_list = set(local_unique_id_list) unique_id_dict[chip_name] = local_unique_id_list valid = 0 valid_chip_names = set() for unq, xpup, ypup in zip(truth_data['uniqueId'], truth_data['x_pupil'], truth_data['y_pupil']): chip_name = chipNameFromPupilCoordsLSST(xpup, ypup) if chip_name is not None: self.assertIn(unq, unique_id_dict[chip_name]) valid_chip_names.add(chip_name) valid += 1 self.assertGreater(valid, 10) self.assertGreater(len(valid_chip_names), 5)
def calcM5(hardware, system, atmos, title='m5'): """ Calculate m5 values for all filters in hardware and system. Prints all values that go into "table 2" of the overview paper. Returns dictionary of m5 values. """ # photParams stores default values for the exposure time, nexp, size of the primary, # readnoise, gain, platescale, etc. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/PhotometricParameters.py effarea = np.pi * (6.423 / 2. * 100.)**2 photParams_zp = PhotometricParameters(exptime=1, nexp=1, gain=1, effarea=effarea, readnoise=8.8, othernoise=0, darkcurrent=0.2) photParams = PhotometricParameters(gain=1.0, effarea=effarea, readnoise=8.8, othernoise=0, darkcurrent=0.2) photParams_infinity = PhotometricParameters(gain=1.0, readnoise=0, darkcurrent=0, othernoise=0, effarea=effarea) # lsstDefaults stores default values for the FWHMeff. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/LSSTdefaults.py lsstDefaults = LSSTdefaults() darksky = Sed() darksky.readSED_flambda(os.path.join('../siteProperties', 'darksky.dat')) flatSed = Sed() flatSed.setFlatSED() m5 = {} Tb = {} Sb = {} kAtm = {} Cm = {} dCm_infinity = {} sourceCounts = {} skyCounts = {} skyMag = {} gamma = {} for f in system: m5[f] = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams, FWHMeff=lsstDefaults.FWHMeff(f)) fNorm = flatSed.calcFluxNorm(m5[f], system[f]) flatSed.multiplyFluxNorm(fNorm) sourceCounts[f] = flatSed.calcADU(system[f], photParams=photParams) # Calculate the Skycounts expected in this bandpass. skyCounts[f] = (darksky.calcADU(hardware[f], photParams=photParams) * photParams.platescale**2) # Calculate the sky surface brightness. skyMag[f] = darksky.calcMag(hardware[f]) # Calculate the gamma value. gamma[f] = SignalToNoise.calcGamma(system[f], m5[f], photParams) # Calculate the "Throughput Integral" (this is the hardware + atmosphere) dwavelen = np.mean(np.diff(system[f].wavelen)) Tb[f] = np.sum(system[f].sb / system[f].wavelen) * dwavelen # Calculate the "Sigma" 'system integral' (this is the hardware only) Sb[f] = np.sum(hardware[f].sb / hardware[f].wavelen) * dwavelen # Calculate km - atmospheric extinction in a particular bandpass kAtm[f] = -2.5 * np.log10(Tb[f] / Sb[f]) # Calculate the Cm and Cm_Infinity values. # m5 = Cm + 0.5*(msky - 21) + 2.5log10(0.7/FWHMeff) + 1.25log10(t/30) - km(X-1.0) # Exptime should be 30 seconds and X=1.0 exptime = photParams.exptime * photParams.nexp if exptime != 30.0: print "Whoa, exposure time was not as expected - got %s not 30 seconds. Please edit Cm calculation." % ( exptime) # Assumes atmosphere used in system throughput is X=1.0 X = 1.0 Cm[f] = (m5[f] - 0.5 * (skyMag[f] - 21) - 2.5 * np.log10(0.7 / lsstDefaults.FWHMeff(f))) # Calculate Cm_Infinity by setting readout noise to zero. m5inf = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams_infinity, FWHMeff=lsstDefaults.FWHMeff(f)) Cm_infinity = (m5inf - 0.5 * (skyMag[f] - 21) - 2.5 * np.log10(0.7 / lsstDefaults.FWHMeff(f))) dCm_infinity[f] = Cm_infinity - Cm[f] print title print 'Filter FWHMeff FWHMgeom SkyMag SkyCounts Tb Sb kAtm Gamma Cm dCm_infinity m5 SourceCounts' for f in ('u', 'g', 'r', 'i', 'z', 'y'): print '%s %.2f %.2f %.2f %.1f %.3f %.3f %.4f %.6f %.2f %.2f %.2f %.2f'\ %(f, lsstDefaults.FWHMeff(f), SignalToNoise.FWHMeff2FWHMgeom(lsstDefaults.FWHMeff(f)), skyMag[f], skyCounts[f], Tb[f], Sb[f], kAtm[f], gamma[f], Cm[f], dCm_infinity[f], m5[f], sourceCounts[f]) # Show what these look like individually (add sky & m5 limits on throughput curves) plt.figure() for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2, label=f) plt.plot(atmosphere.wavelen, atmosphere.sb, 'k:', label='X=1.0') plt.legend(loc='center right', fontsize='smaller') plt.xlim(300, 1100) plt.ylim(0, 1) plt.xlabel('Wavelength (nm)') plt.ylabel('Throughput') plt.title('System Throughputs') plt.grid(True) plt.figure() ax = plt.gca() # Add dark sky ax2 = ax.twinx() plt.sca(ax2) skyab = -2.5 * np.log10(darksky.fnu) - darksky.zp ax2.plot(darksky.wavelen, skyab, 'k-', linewidth=0.8, label='Dark sky mags') ax2.set_ylabel('AB mags') ax2.set_ylim(24, 14) plt.sca(ax) # end of dark sky handles = [] for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2) myline = mlines.Line2D([], [], color=filtercolors[f], linestyle='-', linewidth=2, label='%s: m5 %.1f (sky %.1f)' % (f, m5[f], skyMag[f])) handles.append(myline) plt.plot(atmos.wavelen, atmos.sb, 'k:', label='Atmosphere, X=1.0') # Add legend for dark sky. myline = mlines.Line2D([], [], color='k', linestyle='-', label='Dark sky AB mags/arcsec^2') handles.append(myline) # end of dark sky legend line plt.legend(loc=(0.01, 0.69), handles=handles, fancybox=True, numpoints=1, fontsize='small') plt.ylim(0, 1) plt.xlim(300, 1100) plt.xlabel('Wavelength (nm)') plt.ylabel('Fractional Throughput Response') plt.title('System total response curves %s' % (title)) return m5
def calc_adu(mag, bandpass): sed = Sed() sed.setFlatSED() fluxNorm = sed.calcFluxNorm(mag, bandpass) sed.multiplyFluxNorm(fluxNorm) return sed.calcADU(bandpass, fake_phot_params())
def test_object_extraction_galaxies(self): """ Test that method to get GalSimCelestialObjects from InstanceCatalogs works """ galaxy_phosim_file = os.path.join(self.data_dir, 'phosim_galaxies.txt') commands = desc.imsim.metadata_from_file(galaxy_phosim_file) obs_md = desc.imsim.phosim_obs_metadata(commands) phot_params = desc.imsim.photometricParameters(commands) (gs_object_arr, gs_object_dict) = desc.imsim.sources_from_file( galaxy_phosim_file, obs_md, phot_params) id_arr = np.zeros(len(gs_object_arr), dtype=int) for i_obj in range(len(gs_object_arr)): id_arr[i_obj] = gs_object_arr[i_obj].uniqueId truth_dtype = np.dtype([('uniqueId', int), ('x_pupil', float), ('y_pupil', float), ('sedFilename', str, 200), ('magNorm', float), ('raJ2000', float), ('decJ2000', float), ('redshift', float), ('gamma1', float), ('gamma2', float), ('kappa', float), ('galacticAv', float), ('galacticRv', float), ('internalAv', float), ('internalRv', float), ('minorAxis', float), ('majorAxis', float), ('positionAngle', float), ('sindex', float)]) truth_data = np.genfromtxt(os.path.join(self.data_dir, 'truth_galaxies.txt'), dtype=truth_dtype, delimiter=';') np.testing.assert_array_equal(truth_data['uniqueId'], id_arr) ######## test that galaxy parameters are correctly read in g1 = truth_data['gamma1'] / (1.0 - truth_data['kappa']) g2 = truth_data['gamma2'] / (1.0 - truth_data['kappa']) mu = 1.0 / ((1.0 - truth_data['kappa'])**2 - (truth_data['gamma1']**2 + truth_data['gamma2']**2)) for i_obj, gs_obj in enumerate(gs_object_arr): self.assertAlmostEqual(gs_obj.mu / mu[i_obj], 1.0, 6) self.assertAlmostEqual(gs_obj.g1 / g1[i_obj], 1.0, 6) self.assertAlmostEqual(gs_obj.g2 / g2[i_obj], 1.0, 6) self.assertGreater(np.abs(gs_obj.mu), 0.0) self.assertGreater(np.abs(gs_obj.g1), 0.0) self.assertGreater(np.abs(gs_obj.g2), 0.0) self.assertAlmostEqual(gs_obj.halfLightRadiusRadians, truth_data['majorAxis'][i_obj], 13) self.assertAlmostEqual(gs_obj.minorAxisRadians, truth_data['minorAxis'][i_obj], 13) self.assertAlmostEqual(gs_obj.majorAxisRadians, truth_data['majorAxis'][i_obj], 13) self.assertAlmostEqual(gs_obj.positionAngleRadians, truth_data['positionAngle'][i_obj], 7) self.assertAlmostEqual(gs_obj.sindex, truth_data['sindex'][i_obj], 10) ######## test that pupil coordinates are correct to within ######## half a milliarcsecond x_pup_test, y_pup_test = _pupilCoordsFromRaDec(truth_data['raJ2000'], truth_data['decJ2000'], obs_metadata=obs_md) for i_obj, gs_obj in enumerate(gs_object_arr): self.assertEqual(truth_data['uniqueId'][i_obj], gs_obj.uniqueId) dd = np.sqrt((x_pup_test[i_obj] - gs_obj.xPupilRadians)**2 + (y_pup_test[i_obj] - gs_obj.yPupilRadians)**2) dd = arcsecFromRadians(dd) self.assertLess(dd, 0.0005) ######## test that fluxes are correctly calculated bp_dict = BandpassDict.loadTotalBandpassesFromFiles() imsim_bp = Bandpass() imsim_bp.imsimBandpass() phot_params = PhotometricParameters(nexp=1, exptime=30.0) for i_obj, gs_obj in enumerate(gs_object_arr): sed = Sed() full_sed_name = os.path.join(os.environ['SIMS_SED_LIBRARY_DIR'], truth_data['sedFilename'][i_obj]) sed.readSED_flambda(full_sed_name) fnorm = sed.calcFluxNorm(truth_data['magNorm'][i_obj], imsim_bp) sed.multiplyFluxNorm(fnorm) a_x, b_x = sed.setupCCMab() sed.addCCMDust(a_x, b_x, A_v=truth_data['internalAv'][i_obj], R_v=truth_data['internalRv'][i_obj]) sed.redshiftSED(truth_data['redshift'][i_obj], dimming=True) sed.resampleSED(wavelen_match=bp_dict.wavelenMatch) a_x, b_x = sed.setupCCMab() sed.addCCMDust(a_x, b_x, A_v=truth_data['galacticAv'][i_obj], R_v=truth_data['galacticRv'][i_obj]) for bp in ('u', 'g', 'r', 'i', 'z', 'y'): flux = sed.calcADU(bp_dict[bp], phot_params) * phot_params.gain self.assertAlmostEqual(flux / gs_obj.flux(bp), 1.0, 6) ######## test that objects are assigned to the right chip in ######## gs_object_dict unique_id_dict = {} for chip_name in gs_object_dict: local_unique_id_list = [] for gs_object in gs_object_dict[chip_name]: local_unique_id_list.append(gs_object.uniqueId) local_unique_id_list = set(local_unique_id_list) unique_id_dict[chip_name] = local_unique_id_list valid = 0 valid_chip_names = set() for unq, xpup, ypup in zip(truth_data['uniqueId'], truth_data['x_pupil'], truth_data['y_pupil']): chip_name = chipNameFromPupilCoordsLSST(xpup, ypup)[0] if chip_name is not None: self.assertIn(unq, unique_id_dict[chip_name]) valid_chip_names.add(chip_name) valid += 1 self.assertGreater(valid, 10) self.assertGreater(len(valid_chip_names), 5)
def calcM5(hardware, system, atmos, title='m5'): effarea = np.pi * (6.423/2.0*100.)**2 photParams = PhotometricParameters(effarea = effarea) lsstDefaults = LSSTdefaults() darksky = Sed() darksky.readSED_flambda(os.path.join('../siteProperties', 'darksky.dat')) flatSed = Sed() flatSed.setFlatSED() m5 = {} sourceCounts = {} skyCounts = {} skyMag = {} gamma = {} for f in system: m5[f] = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams, FWHMeff=lsstDefaults.FWHMeff(f)) fNorm = flatSed.calcFluxNorm(m5[f], system[f]) flatSed.multiplyFluxNorm(fNorm) sourceCounts[f] = flatSed.calcADU(system[f], photParams=photParams) # Calculate the Skycounts expected in this bandpass. skyCounts[f] = darksky.calcADU(hardware[f], photParams=photParams) * photParams.platescale**2 # Calculate the sky surface brightness. skyMag[f] = darksky.calcMag(hardware[f]) # Calculate the gamma value. gamma[f] = SignalToNoise.calcGamma(system[f], m5[f], photParams) print title print 'Filter m5 SourceCounts SkyCounts SkyMag Gamma' for f in ('u', 'g' ,'r', 'i', 'z', 'y'): print '%s %.2f %.1f %.2f %.2f %.6f' %(f, m5[f], sourceCounts[f], skyCounts[f], skyMag[f], gamma[f]) # Show what these look like individually (add sky & m5 limits on throughput curves) plt.figure() ax = plt.gca() # Add dark sky ax2 = ax.twinx() plt.sca(ax2) skyab = -2.5*np.log10(darksky.fnu) - darksky.zp ax2.plot(darksky.wavelen, skyab, 'k-', linewidth=0.8, label='Dark sky mags') ax2.set_ylabel('AB mags') ax2.set_ylim(24, 14) plt.sca(ax) # end of dark sky handles = [] for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2) myline = mlines.Line2D([], [], color=filtercolors[f], linestyle='-', linewidth=2, label = '%s: m5 %.1f (sky %.1f)' %(f, m5[f], skyMag[f])) handles.append(myline) plt.plot(atmos.wavelen, atmos.sb, 'k:', label='Atmosphere, X=1.0 with aerosols') # Add legend for dark sky. myline = mlines.Line2D([], [], color='k', linestyle='-', label='Dark sky AB mags') handles.append(myline) # end of dark sky legend line plt.legend(loc=(0.01, 0.69), handles=handles, fancybox=True, numpoints=1, fontsize='small') plt.ylim(0, 1) plt.xlim(300, 1100) plt.xlabel('Wavelength (nm)') plt.ylabel('Fractional Throughput Response') if title == 'Vendor combo': title = '' plt.title('System total response curves %s' %(title)) plt.savefig('../plots/system+sky' + title + '.png', format='png', dpi=600) return m5
def __init__(self,logobs,parameters,model,version): self.mjd_name='mjd' self.FWHMeff='seeing' peakAbsMagBesselB=-19.0906 alpha=0.13 beta=3. mycosmology=FlatLambdaCDM(H0=70, Om0=0.25) self.astropy_cosmo=FlatLambdaCDM(H0= mycosmology.H0, Om0=mycosmology.Om0) instrument = instruments.InstrumentModel("STANDARD") B = instrument.EffectiveFilterByBand("B") magsys = instruments.MagSys('VEGA') zp = magsys.ZeroPoint(B) print 'zeropoint for b-band',zp flux_at_10pc = np.power(10., -0.4 * (peakAbsMagBesselB-zp)) fs = salt2.load_filters(['STANDARD::B']) mc = salt2.ModelComponents('salt2.npz') s = salt2.SALT2([0.], ['STANDARD::B'], mc, fs, z=0.) raw_model_norm = s()[0] # (10pc)^2 in kpc^2 self.X0_norm = flux_at_10pc * 1.E-4 / raw_model_norm table_obs=ascii.read(logobs,fast_reader=False) colnames=[] sfile=open(logobs,'r') for line in sfile.readlines(): if line.count('#'): colnames.append(line[1:].split(':')[0].strip()) for i,val in enumerate(table_obs.colnames): #if val.count('#') >= 1: table_obs.rename_column(val, colnames[i]) self.lc=[] print table_obs self.params=Table(names=('t0','c','x1','z','ra','dec','status','fit','sn_type','sn_model','sn_version','mbsim','x0','dL'),dtype=('f8','f8','f8','f8','f8','S8','S8','f8','S8','S8','S8','f8','f8','f8')) self.transmission=Throughputs() dust = sncosmo.OD94Dust() model=model version=version if model == 'salt2-extended': model_min=300. model_max=180000. wave_min=3000. wave_max=11501. if model=='salt2': model_min=2000. model_max=9200.0 wave_min=model_min wave_max=model_max wave= np.arange(wave_min,wave_max,1.) sn_type='Ia' source=sncosmo.get_source(model,version=version) ra_field=0. dec_field=0. table_obs.sort(self.mjd_name) for iv,param in enumerate(parameters): #mysn=Simul_Fit_SN(param['DayMax'],param['Color'],param['X1'],param['z'],table_obs,ra=param['ra'],dec=param['dec']) table_LC=Table(names=('idSN','filter','expMJD','visitExpTime','FWHMeff','moon_frac','filtSkyBrightness','kAtm','airmass','fiveSigmaDepth','Nexp','e_per_sec','e_per_sec_err'), dtype=('i8','S7','f8', 'f8','f8','f8', 'f8','f8','i8','f8','f8','f8','f8')) lumidist=self.astropy_cosmo.luminosity_distance(param['z']).value*1.e3 X0 = self.X0_norm / lumidist** 2 X0 *= np.power(10., 0.4*(alpha*param['X1'] -beta*param['Color'])) print 'X0 val',X0 SN=sncosmo.Model(source=source,effects=[dust, dust], effect_names=['host', 'mw'], effect_frames=['rest', 'obs']) SN.set(z=param['z']) SN.set(t0=param['DayMax']) SN.set(c=param['Color']) SN.set(x1=param['X1']) SN.set(x0=X0) #SN.set_source_peakabsmag(peakAbsMagBesselB, 'bessellB', 'vega',cosmo=mycosmology) fluxes=10.*SN.flux(table_obs[self.mjd_name],wave) wavelength=wave/10. wavelength=np.repeat(wavelength[np.newaxis,:], len(fluxes), 0) SED_time = Sed(wavelen=wavelength, flambda=fluxes) self.params.add_row((param['DayMax'],param['Color'],param['X1'],param['z'],ra_field,dec_field,'unkown',None,sn_type,model,version,SN._source.peakmag('bessellb','vega'),SN.get('x0'),lumidist)) for i in range(len(SED_time.wavelen)): obs=table_obs[i] sed=Sed(wavelen=SED_time.wavelen[i],flambda=SED_time.flambda[i]) visittime=obs['exptime'] filtre=obs['band'][-1] photParams = PhotometricParameters(nexp=visittime/15.) e_per_sec = sed.calcADU(bandpass=self.transmission.lsst_atmos_aerosol[filtre], photParams=photParams) #number of ADU counts for expTime e_per_sec/=visittime/photParams.gain flux_SN=sed.calcFlux(bandpass=self.transmission.lsst_atmos_aerosol[filtre]) FWHMeff=obs[self.FWHMeff] if flux_SN >0: #print 'hello flux',flux_SN,fluxes[i] mag_SN=-2.5 * np.log10(flux_SN / 3631.0) m5_calc,snr_m5_through=self.Get_m5(filtre,mag_SN,obs['sky'],photParams,FWHMeff) table_LC.add_row((iv,'LSST::'+filtre,obs[self.mjd_name],visittime,FWHMeff,obs['moon_frac'],obs['sky'],obs['kAtm'],obs['airmass'],obs['m5sigmadepth'],obs['Nexp'],e_per_sec,e_per_sec/snr_m5_through)) self.lc.append(table_LC)
def testObjectPlacement(self): """ Test that GalSim places objects on the correct pixel by drawing images, reading them in, and then comparing the flux contained in circles of 2 fwhm radii about the object's expected positions with the actual expected flux of the objects. """ scratchDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'scratchSpace') catName = os.path.join(scratchDir, 'placementCatalog.dat') imageRoot = os.path.join(scratchDir, 'placementImage') dbFileName = os.path.join(scratchDir, 'placementInputCatalog.dat') cameraDir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'cameraData') camera = ReturnCamera(cameraDir) detector = camera[0] imageName = '%s_%s_u.fits' % (imageRoot, detector.getName()) controlSed = Sed() controlSed.readSED_flambda( os.path.join(getPackageDir('sims_sed_library'), 'flatSED','sed_flat.txt.gz') ) uBandpass = Bandpass() uBandpass.readThroughput( os.path.join(getPackageDir('throughputs'), 'baseline','total_u.dat') ) controlBandpass = Bandpass() controlBandpass.imsimBandpass() ff = controlSed.calcFluxNorm(self.magNorm, uBandpass) controlSed.multiplyFluxNorm(ff) a_int, b_int = controlSed.setupCCMab() controlSed.addCCMDust(a_int, b_int, A_v=0.1, R_v=3.1) nSamples = 5 numpy.random.seed(42) pointingRaList = numpy.random.random_sample(nSamples)*360.0 pointingDecList = numpy.random.random_sample(nSamples)*180.0 - 90.0 rotSkyPosList = numpy.random.random_sample(nSamples)*360.0 fwhmList = numpy.random.random_sample(nSamples)*1.0 + 0.3 actualCounts = None for pointingRA, pointingDec, rotSkyPos, fwhm in \ zip(pointingRaList, pointingDecList, rotSkyPosList, fwhmList): obs = ObservationMetaData(unrefractedRA=pointingRA, unrefractedDec=pointingDec, boundType='circle', boundLength=4.0, mjd=49250.0, rotSkyPos=rotSkyPos) xDisplacementList = numpy.random.random_sample(nSamples)*60.0-30.0 yDisplacementList = numpy.random.random_sample(nSamples)*60.0-30.0 create_text_catalog(obs, dbFileName, xDisplacementList, yDisplacementList, mag_norm=[self.magNorm]*len(xDisplacementList)) db = placementFileDBObj(dbFileName, runtable='test') cat = placementCatalog(db, obs_metadata=obs) if actualCounts is None: actualCounts = controlSed.calcADU(uBandpass, cat.photParams) psf = SNRdocumentPSF(fwhm=fwhm) cat.setPSF(psf) cat.camera = camera cat.write_catalog(catName) cat.write_images(nameRoot=imageRoot) objRaList = [] objDecList = [] with open(catName, 'r') as inFile: for line in inFile: if line[0] != '#': words = line.split(';') objRaList.append(numpy.radians(numpy.float(words[2]))) objDecList.append(numpy.radians(numpy.float(words[3]))) objRaList = numpy.array(objRaList) objDecList = numpy.array(objDecList) self.check_placement(imageName, objRaList, objDecList, [fwhm]*len(objRaList), numpy.array([actualCounts]*len(objRaList)), cat.photParams.gain, detector, camera, obs, epoch=2000.0) if os.path.exists(dbFileName): os.unlink(dbFileName) if os.path.exists(catName): os.unlink(catName) if os.path.exists(imageName): os.unlink(imageName)
def calcM5(hardware, system, atmos, title="m5"): effarea = np.pi * (6.423 / 2.0 * 100.0) ** 2 photParams = PhotometricParameters(effarea=effarea) lsstDefaults = LSSTdefaults() darksky = Sed() darksky.readSED_flambda(os.path.join("../siteProperties", "darksky.dat")) flatSed = Sed() flatSed.setFlatSED() m5 = {} sourceCounts = {} skyCounts = {} skyMag = {} gamma = {} for f in system: m5[f] = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams, FWHMeff=lsstDefaults.FWHMeff(f)) fNorm = flatSed.calcFluxNorm(m5[f], system[f]) flatSed.multiplyFluxNorm(fNorm) sourceCounts[f] = flatSed.calcADU(system[f], photParams=photParams) # Calculate the Skycounts expected in this bandpass. skyCounts[f] = darksky.calcADU(hardware[f], photParams=photParams) * photParams.platescale ** 2 # Calculate the sky surface brightness. skyMag[f] = darksky.calcMag(hardware[f]) # Calculate the gamma value. gamma[f] = SignalToNoise.calcGamma(system[f], m5[f], photParams) print title print "Filter m5 SourceCounts SkyCounts SkyMag Gamma" for f in ("u", "g", "r", "i", "z", "y"): print "%s %.2f %.1f %.2f %.2f %.6f" % (f, m5[f], sourceCounts[f], skyCounts[f], skyMag[f], gamma[f]) # Show what these look like individually (add sky & m5 limits on throughput curves) plt.figure() ax = plt.gca() # Add dark sky ax2 = ax.twinx() plt.sca(ax2) skyab = -2.5 * np.log10(darksky.fnu) - darksky.zp ax2.plot(darksky.wavelen, skyab, "k-", linewidth=0.8, label="Dark sky mags") ax2.set_ylabel("AB mags") ax2.set_ylim(24, 14) plt.sca(ax) # end of dark sky handles = [] for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2) myline = mlines.Line2D( [], [], color=filtercolors[f], linestyle="-", linewidth=2, label="%s: m5 %.1f (sky %.1f)" % (f, m5[f], skyMag[f]), ) handles.append(myline) plt.plot(atmos.wavelen, atmos.sb, "k:", label="Atmosphere, X=1.0 with aerosols") # Add legend for dark sky. myline = mlines.Line2D([], [], color="k", linestyle="-", label="Dark sky AB mags") handles.append(myline) # end of dark sky legend line plt.legend(loc=(0.01, 0.69), handles=handles, fancybox=True, numpoints=1, fontsize="small") plt.ylim(0, 1) plt.xlim(300, 1100) plt.xlabel("Wavelength (nm)") plt.ylabel("Fractional Throughput Response") if title == "Vendor combo": title = "" plt.title("System total response curves %s" % (title)) plt.savefig("../plots/system+sky" + title + ".png", format="png", dpi=600) return m5
def X0_norm(self): name = 'STANDARD' band = 'B' thedir = '../Cosmo_Maf' #thedir='.' os.environ[name] = thedir + '/Instruments/Landolt' trans_standard = Throughputs(through_dir='STANDARD', telescope_files=[], filter_files=['sb_-41A.dat'], atmos=False, aerosol=False, filterlist=('A'), wave_min=3559, wave_max=5559) mag, spectrum_file = self.Get_Mag( thedir + '/MagSys/VegaBD17-2008-11-28.dat', name, band) #print 'alors mag',mag, spectrum_file sed = Sed() sed.readSED_fnu(filename=thedir + '/' + spectrum_file) CLIGHT_A_s = 2.99792458e18 # [A/s] HPLANCK = 6.62606896e-27 sedb = Sed(wavelen=sed.wavelen, flambda=sed.wavelen * sed.fnu / (CLIGHT_A_s * HPLANCK)) #print 'alors man',sed.wavelen*sed.fnu/(CLIGHT_A_s * HPLANCK) flux = self.calcInteg(bandpass=trans_standard.system['A'], signal=sedb.flambda, wavelen=sedb.wavelen) zp = 2.5 * np.log10(flux) + mag flux_at_10pc = np.power(10., -0.4 * (self.peakAbsMagBesselB - zp)) #print 'zp',zp,flux_at_10pc source = sncosmo.get_source(self.model, version=self.version) SN = sncosmo.Model(source=source) SN.set(z=0.) SN.set(t0=0) SN.set(c=self.param['Color']) SN.set(x1=self.param['X1']) SN.set(x0=1) fluxes = 10. * SN.flux(0., self.wave) wavelength = self.wave / 10. SED_time = Sed(wavelen=wavelength, flambda=fluxes) expTime = 30. photParams = PhotometricParameters(nexp=expTime / 15.) trans = Bandpass(wavelen=trans_standard.system['A'].wavelen / 10., sb=trans_standard.system['A'].sb) e_per_sec = SED_time.calcADU( bandpass=trans, photParams=photParams) #number of ADU counts for expTime #e_per_sec = sed.calcADU(bandpass=self.transmission.lsst_atmos[filtre], photParams=photParams) e_per_sec /= expTime / photParams.gain * photParams.effarea #print 'hello',e_per_sec """ SN.set(c=self.param['Color']) SN.set(x1=self.param['X1']) """ #print 'My zp',zp,flux return flux_at_10pc * 1.E-4 / e_per_sec
def calcM5(hardware, system, atmos, title='m5'): """ Calculate m5 values for all filters in hardware and system. Prints all values that go into "table 2" of the overview paper. Returns dictionary of m5 values. """ # photParams stores default values for the exposure time, nexp, size of the primary, # readnoise, gain, platescale, etc. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/PhotometricParameters.py photParams = PhotometricParameters(gain=1) photParams_infinity = PhotometricParameters(readnoise=0, darkcurrent=0, othernoise=0, gain=1) # lsstDefaults stores default values for the FWHMeff. # See https://github.com/lsst/sims_photUtils/blob/master/python/lsst/sims/photUtils/LSSTdefaults.py lsstDefaults = LSSTdefaults() darksky = Sed() darksky.readSED_flambda(os.path.join('../siteProperties', 'darksky.dat')) flatSed = Sed() flatSed.setFlatSED() m5 = {} Tb = {} Sb = {} kAtm = {} Cm = {} dCm_infinity = {} sourceCounts = {} skyCounts = {} skyMag = {} gamma = {} for f in system: m5[f] = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams, FWHMeff=lsstDefaults.FWHMeff(f)) fNorm = flatSed.calcFluxNorm(m5[f], system[f]) flatSed.multiplyFluxNorm(fNorm) sourceCounts[f] = flatSed.calcADU(system[f], photParams=photParams) # Calculate the Skycounts expected in this bandpass. skyCounts[f] = (darksky.calcADU(hardware[f], photParams=photParams) * photParams.platescale**2) # Calculate the sky surface brightness. skyMag[f] = darksky.calcMag(hardware[f]) # Calculate the gamma value. gamma[f] = SignalToNoise.calcGamma(system[f], m5[f], photParams) # Calculate the "Throughput Integral" (this is the hardware + atmosphere) dwavelen = np.mean(np.diff(system[f].wavelen)) Tb[f] = np.sum(system[f].sb / system[f].wavelen) * dwavelen # Calculate the "Sigma" 'system integral' (this is the hardware only) Sb[f] = np.sum(hardware[f].sb / hardware[f].wavelen) * dwavelen # Calculate km - atmospheric extinction in a particular bandpass kAtm[f] = -2.5*np.log10(Tb[f] / Sb[f]) # Calculate the Cm and Cm_Infinity values. # m5 = Cm + 0.5*(msky - 21) + 2.5log10(0.7/FWHMeff) + 1.25log10(t/30) - km(X-1.0) # Exptime should be 30 seconds and X=1.0 exptime = photParams.exptime * photParams.nexp if exptime != 30.0: print "Whoa, exposure time was not as expected - got %s not 30 seconds. Please edit Cm calculation." %(exptime) # Assumes atmosphere used in system throughput is X=1.0 X = 1.0 Cm[f] = (m5[f] - 0.5*(skyMag[f] - 21) - 2.5*np.log10(0.7/lsstDefaults.FWHMeff(f))) # Calculate Cm_Infinity by setting readout noise to zero. m5inf = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams_infinity, FWHMeff=lsstDefaults.FWHMeff(f)) Cm_infinity = (m5inf - 0.5*(skyMag[f] - 21) - 2.5*np.log10(0.7/lsstDefaults.FWHMeff(f))) dCm_infinity[f] = Cm_infinity - Cm[f] print title print 'Filter FWHMeff FWHMgeom SkyMag SkyCounts Tb Sb kAtm Gamma Cm dCm_infinity m5 SourceCounts' for f in ('u', 'g' ,'r', 'i', 'z', 'y'): print '%s %.2f %.2f %.2f %.1f %.3f %.3f %.4f %.6f %.2f %.2f %.2f %.2f'\ %(f, lsstDefaults.FWHMeff(f), SignalToNoise.FWHMeff2FWHMgeom(lsstDefaults.FWHMeff(f)), skyMag[f], skyCounts[f], Tb[f], Sb[f], kAtm[f], gamma[f], Cm[f], dCm_infinity[f], m5[f], sourceCounts[f]) # Show what these look like individually (add sky & m5 limits on throughput curves) plt.figure() for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2, label=f) plt.plot(atmosphere.wavelen, atmosphere.sb, 'k:', label='X=1.0') plt.legend(loc='center right', fontsize='smaller') plt.xlim(300, 1100) plt.ylim(0, 1) plt.xlabel('Wavelength (nm)') plt.ylabel('Throughput') plt.title('System Throughputs') plt.grid(True) plt.figure() ax = plt.gca() # Add dark sky ax2 = ax.twinx() plt.sca(ax2) skyab = -2.5*np.log10(darksky.fnu) - darksky.zp ax2.plot(darksky.wavelen, skyab, 'k-', linewidth=0.8, label='Dark sky mags') ax2.set_ylabel('AB mags') ax2.set_ylim(24, 14) plt.sca(ax) # end of dark sky handles = [] for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2) myline = mlines.Line2D([], [], color=filtercolors[f], linestyle='-', linewidth=2, label = '%s: m5 %.1f (sky %.1f)' %(f, m5[f], skyMag[f])) handles.append(myline) plt.plot(atmos.wavelen, atmos.sb, 'k:', label='Atmosphere, X=1.0') # Add legend for dark sky. myline = mlines.Line2D([], [], color='k', linestyle='-', label='Dark sky AB mags/arcsec^2') handles.append(myline) # end of dark sky legend line plt.legend(loc=(0.01, 0.69), handles=handles, fancybox=True, numpoints=1, fontsize='small') plt.ylim(0, 1) plt.xlim(300, 1100) plt.xlabel('Wavelength (nm)') plt.ylabel('Fractional Throughput Response') plt.title('System total response curves %s' %(title)) return m5
def calcM5s(hardware, system, atmos, title='m5'): photParams = PhotometricParameters() lsstDefaults = LSSTdefaults() darksky = Sed() darksky.readSED_flambda(os.path.join(os.getenv('SYSENG_THROUGHPUTS_DIR'), 'siteProperties', 'darksky.dat')) flatSed = Sed() flatSed.setFlatSED() m5 = {} sourceCounts = {} skyCounts = {} skyMag = {} gamma = {} for f in system: m5[f] = SignalToNoise.calcM5(darksky, system[f], hardware[f], photParams, seeing=lsstDefaults.seeing(f)) fNorm = flatSed.calcFluxNorm(m5[f], system[f]) flatSed.multiplyFluxNorm(fNorm) sourceCounts[f] = flatSed.calcADU(system[f], photParams=photParams) # Calculate the Skycounts expected in this bandpass. skyCounts[f] = darksky.calcADU(hardware[f], photParams=photParams) * photParams.platescale**2 # Calculate the sky surface brightness. skyMag[f] = darksky.calcMag(hardware[f]) # Calculate the gamma value. gamma[f] = SignalToNoise.calcGamma(system[f], m5[f], photParams) print title print 'Filter m5 SourceCounts SkyCounts SkyMag Gamma' for f in ('u', 'g' ,'r', 'i', 'z', 'y'): print '%s %.2f %.1f %.2f %.2f %.6f' %(f, m5[f], sourceCounts[f], skyCounts[f], skyMag[f], gamma[f]) # Show what these look like individually (add sky & m5 limits on throughput curves) plt.figure() ax = plt.gca() # Add dark sky ax2 = ax.twinx() plt.sca(ax2) skyab = -2.5*np.log10(darksky.fnu) - darksky.zp ax2.plot(darksky.wavelen, skyab, 'k-', linewidth=0.8, label='Dark sky mags') ax2.set_ylabel('AB mags') ax2.set_ylim(24, 10) plt.sca(ax) # end of dark sky handles = [] for f in filterlist: plt.plot(system[f].wavelen, system[f].sb, color=filtercolors[f], linewidth=2) myline = mlines.Line2D([], [], color=filtercolors[f], linestyle='-', linewidth=2, label = '%s: m5 %.1f (sky %.1f)' %(f, m5[f], skyMag[f])) handles.append(myline) plt.plot(atmos.wavelen, atmos.sb, 'k:', label='Atmosphere, X=1.2') # Add legend for dark sky. myline = mlines.Line2D([], [], color='k', linestyle='-', label='Dark sky AB mags') handles.append(myline) # end of dark sky legend line plt.legend(loc=(0.01, 0.69), handles=handles, fancybox=True, numpoints=1, fontsize='small') plt.ylim(0, 1) plt.xlim(300, 1100) plt.xlabel('Wavelength (nm)') plt.ylabel('Fractional Throughput Response') if title == 'Vendor combo': title = '' plt.title('System total response curves %s' %(title)) if title == '': plt.savefig('throughputs.pdf', format='pdf', dpi=600) return m5