def testStellarPhotometricUncertainties(self): """ Test in the case of a catalog of stars """ lsstDefaults = LSSTdefaults() starDB = testStarsDBObj(driver=self.driver, host=self.host, database=self.dbName) starCat = testStarCatalog(starDB, obs_metadata=self.obs_metadata) ct = 0 for line in starCat.iter_catalog(): starSed = Sed() starSed.readSED_flambda(os.path.join(lsst.utils.getPackageDir('sims_sed_library'), defaultSpecMap[line[14]])) imsimband = Bandpass() imsimband.imsimBandpass() fNorm = starSed.calcFluxNorm(line[15], imsimband) starSed.multiplyFluxNorm(fNorm) for i in range(len(self.bandpasses)): controlSigma = calcMagError_sed(starSed, self.totalBandpasses[i], self.skySeds[i], self.hardwareBandpasses[i], seeing=lsstDefaults.seeing(self.bandpasses[i]), photParams=PhotometricParameters()) testSigma = line[8+i] self.assertAlmostEqual(controlSigma, testSigma, 10) ct += 1 self.assertTrue(ct>0)
def testSystematicUncertainty(self): """ Test that systematic uncertainty is added correctly. """ sigmaSys = 0.002 m5_list = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7] photParams = PhotometricParameters(sigmaSys=sigmaSys) obs_metadata = ObservationMetaData(pointingRA=23.0, pointingDec=45.0, m5=m5_list, bandpassName=self.filterNameList) magnitude_list = [] for bp in self.bpList: mag = self.starSED.calcMag(bp) magnitude_list.append(mag) for bp, hardware, filterName, mm, m5 in \ zip(self.bpList, self.hardwareList, self.filterNameList, magnitude_list, m5_list): skyDummy = Sed() skyDummy.readSED_flambda( os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'darksky.dat')) normalizedSkyDummy = setM5( obs_metadata.m5[filterName], skyDummy, bp, hardware, FWHMeff=LSSTdefaults().FWHMeff(filterName), photParams=photParams) sigma, gamma = snr.calcMagError_m5(mm, bp, m5, photParams) snrat = snr.calcSNR_sed(self.starSED, bp, normalizedSkyDummy, hardware, FWHMeff=LSSTdefaults().FWHMeff(filterName), photParams=PhotometricParameters()) testSNR, gamma = snr.calcSNR_m5( mm, bp, m5, photParams=PhotometricParameters(sigmaSys=0.0)) self.assertAlmostEqual(snrat, testSNR, 10, msg='failed on calcSNR_m5 test %e != %e ' % (snrat, testSNR)) control = np.sqrt( np.power(snr.magErrorFromSNR(testSNR), 2) + np.power(sigmaSys, 2)) msg = '%e is not %e; failed' % (sigma, control) self.assertAlmostEqual(sigma, control, 10, msg=msg)
def testSignalToNoise(self): """ Test that calcSNR_m5 and calcSNR_sed give similar results """ defaults = LSSTdefaults() photParams = PhotometricParameters() m5 = [] for i in range(len(self.hardwareList)): m5.append( snr.calcM5( self.skySed, self.bpList[i], self.hardwareList[i], photParams, seeing=defaults.seeing(self.filterNameList[i]), ) ) sedDir = lsst.utils.getPackageDir("sims_sed_library") sedDir = os.path.join(sedDir, "starSED", "kurucz") fileNameList = os.listdir(sedDir) numpy.random.seed(42) offset = numpy.random.random_sample(len(fileNameList)) * 2.0 for ix, name in enumerate(fileNameList): if ix > 100: break spectrum = Sed() spectrum.readSED_flambda(os.path.join(sedDir, name)) ff = spectrum.calcFluxNorm(m5[2] - offset[ix], self.bpList[2]) spectrum.multiplyFluxNorm(ff) magList = [] controlList = [] magList = [] for i in range(len(self.bpList)): controlList.append( snr.calcSNR_sed( spectrum, self.bpList[i], self.skySed, self.hardwareList[i], photParams, defaults.seeing(self.filterNameList[i]), ) ) magList.append(spectrum.calcMag(self.bpList[i])) testList, gammaList = snr.calcSNR_m5( numpy.array(magList), numpy.array(self.bpList), numpy.array(m5), photParams ) for tt, cc in zip(controlList, testList): msg = "%e != %e " % (tt, cc) self.assertTrue(numpy.abs(tt / cc - 1.0) < 0.001, msg=msg)
def testSignalToNoise(self): """ Test that calcSNR_m5 and calcSNR_sed give similar results """ defaults = LSSTdefaults() photParams = PhotometricParameters() totalDict, hardwareDict = BandpassDict.loadBandpassesFromFiles() skySED = Sed() skySED.readSED_flambda( os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'darksky.dat')) m5 = [] for filt in totalDict: m5.append( calcM5(skySED, totalDict[filt], hardwareDict[filt], photParams, seeing=defaults.seeing(filt))) sedDir = lsst.utils.getPackageDir('sims_sed_library') sedDir = os.path.join(sedDir, 'starSED', 'kurucz') fileNameList = os.listdir(sedDir) numpy.random.seed(42) offset = numpy.random.random_sample(len(fileNameList)) * 2.0 for ix, name in enumerate(fileNameList): if ix > 100: break spectrum = Sed() spectrum.readSED_flambda(os.path.join(sedDir, name)) ff = spectrum.calcFluxNorm(m5[2] - offset[ix], totalDict.values()[2]) spectrum.multiplyFluxNorm(ff) magList = [] controlList = [] magList = [] for filt in totalDict: controlList.append( calcSNR_sed(spectrum, totalDict[filt], skySED, hardwareDict[filt], photParams, defaults.seeing(filt))) magList.append(spectrum.calcMag(totalDict[filt])) testList, gammaList = calcSNR_m5(numpy.array(magList), numpy.array(totalDict.values()), numpy.array(m5), photParams) for tt, cc in zip(controlList, testList): msg = '%e != %e ' % (tt, cc) self.assertTrue(numpy.abs(tt / cc - 1.0) < 0.001, msg=msg)
def testNoise(self): """ Test that ExampleCCDNoise puts the expected counts on an image by generating a flat image, adding noise and background to it, and calculating the variance of counts in the image. """ lsstDefaults = LSSTdefaults() gain = 2.5 readnoise = 6.0 photParams = PhotometricParameters(gain=gain, readnoise=readnoise) img = galsim.Image(100, 100) noise = ExampleCCDNoise(seed=42) m5 = 24.5 bandpass = Bandpass() bandpass.readThroughput( os.path.join(getPackageDir('throughputs'), 'baseline', 'total_r.dat')) background = calcSkyCountsPerPixelForM5( m5, bandpass, FWHMeff=lsstDefaults.FWHMeff('r'), photParams=photParams) noisyImage = noise.addNoiseAndBackground( img, bandpass, m5=m5, FWHMeff=lsstDefaults.FWHMeff('r'), photParams=photParams) mean = 0.0 var = 0.0 for ix in range(1, 101): for iy in range(1, 101): mean += noisyImage(ix, iy) mean = mean / 10000.0 for ix in range(1, 101): for iy in range(1, 101): var += (noisyImage(ix, iy) - mean) * (noisyImage(ix, iy) - mean) var = var / 9999.0 varElectrons = background * gain + readnoise varADU = varElectrons / (gain * gain) msg = 'background %e mean %e ' % (background, mean) self.assertLess(np.abs(background / mean - 1.0), 0.05, msg=msg) msg = 'var %e varADU %e ; ratio %e ; background %e' % ( var, varADU, var / varADU, background) self.assertLess(np.abs(var / varADU - 1.0), 0.05, msg=msg)
def setUpClass(cls): lsstDefaults=LSSTdefaults() cls.dbName = 'uncertaintyTestDB.db' if os.path.exists(cls.dbName): os.unlink(cls.dbName) default_obs_metadata = makePhoSimTestDB(filename=cls.dbName, size=10, radius = 5.0) bandpass = ['u', 'g', 'r', 'i', 'z', 'y'] m5 = lsstDefaults._m5.values() cls.obs_metadata = ObservationMetaData( unrefractedRA = default_obs_metadata.unrefractedRA, unrefractedDec = default_obs_metadata.unrefractedDec, rotSkyPos = default_obs_metadata.rotSkyPos, bandpassName = bandpass, m5 = m5 ) cls.obs_metadata.setBandpassM5andSeeing(bandpassName=bandpass, m5=m5) cls.driver = 'sqlite' cls.host = '' cls.skySeds = [] cls.hardwareBandpasses = [] cls.totalBandpasses = [] cls.bandpasses = ['u', 'g', 'r', 'i', 'z', 'y'] components = ['detector.dat', 'm1.dat', 'm2.dat', 'm3.dat', 'lens1.dat', 'lens2.dat', 'lens3.dat'] for b in cls.bandpasses: bandpassDummy = Bandpass() bandpassDummy.readThroughput(os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'total_%s.dat' % b)) cls.totalBandpasses.append(bandpassDummy) for b in cls.bandpasses: finalComponents = [] for c in components: finalComponents.append(os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', c)) finalComponents.append(os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'filter_%s.dat' %b)) bandpassDummy = Bandpass() bandpassDummy.readThroughputList(finalComponents) cls.hardwareBandpasses.append(bandpassDummy) for i in range(len(cls.bandpasses)): sedDummy = Sed() sedDummy.readSED_flambda(os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'darksky.dat')) normalizedSedDummy = setM5(cls.obs_metadata.m5[cls.bandpasses[i]], sedDummy, cls.totalBandpasses[i], cls.hardwareBandpasses[i], seeing=lsstDefaults.seeing(cls.bandpasses[i]), photParams=PhotometricParameters()) cls.skySeds.append(normalizedSedDummy)
def setUp(self): defaults = LSSTdefaults() bandpassName = ['u', 'g', 'r', 'i', 'z', 'y'] self.obs_metadata = ObservationMetaData(mjd=52000.7, bandpassName=bandpassName, m5=[defaults.m5(mm) for mm in bandpassName], boundType='circle', pointingRA=200.0, pointingDec=-30.0, boundLength=1.0) self.galaxy = myTestGals(database=self.testDB) self.star = myTestStars(database=self.testDB)
def testSystematicUncertainty(self): """ Test that systematic uncertainty is added correctly. """ sigmaSys = 0.002 m5 = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7] photParams = PhotometricParameters(sigmaSys=sigmaSys) bandpassDict = BandpassDict.loadTotalBandpassesFromFiles() obs_metadata = ObservationMetaData(unrefractedRA=23.0, unrefractedDec=45.0, m5=m5, bandpassName=self.bandpasses) magnitudes = bandpassDict.magListForSed(self.starSED) skySeds = [] for i in range(len(self.bandpasses)): skyDummy = Sed() skyDummy.readSED_flambda( os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'darksky.dat')) normalizedSkyDummy = setM5(obs_metadata.m5[self.bandpasses[i]], skyDummy, self.totalBandpasses[i], self.hardwareBandpasses[i], seeing=LSSTdefaults().seeing( self.bandpasses[i]), photParams=PhotometricParameters()) skySeds.append(normalizedSkyDummy) for i in range(len(self.bandpasses)): snr = calcSNR_sed(self.starSED, self.totalBandpasses[i], skySeds[i], self.hardwareBandpasses[i], seeing=LSSTdefaults().seeing(self.bandpasses[i]), photParams=PhotometricParameters()) testSNR, gamma = calcSNR_m5( numpy.array([magnitudes[i]]), [self.totalBandpasses[i]], numpy.array([m5[i]]), photParams=PhotometricParameters(sigmaSys=0.0)) self.assertAlmostEqual(snr, testSNR[0], 10, msg = 'failed on calcSNR_m5 test %e != %e ' \ % (snr, testSNR[0])) control = numpy.sqrt( numpy.power(magErrorFromSNR(testSNR), 2) + numpy.power(sigmaSys, 2))
def setUp(self): defaults = LSSTdefaults() bandpassName = ['u', 'g', 'r', 'i', 'z', 'y'] self.obs_metadata = ObservationMetaData( mjd=52000.7, bandpassName=bandpassName, m5=[defaults.m5(mm) for mm in bandpassName], boundType='circle', pointingRA=200.0, pointingDec=-30.0, boundLength=1.0) self.galaxy = myTestGals(database=self.testDB) self.star = myTestStars(database=self.testDB)
def phosim_obs_metadata(phosim_commands): """ Factory function to create an ObservationMetaData object based on the PhoSim commands extracted from an instance catalog. Parameters ---------- phosim_commands : dict Dictionary of PhoSim physics commands. Returns ------- lsst.sims.utils.ObservationMetaData """ bandpass = phosim_commands['bandpass'] fwhm_eff = FWHMeff(phosim_commands['seeing'], bandpass, phosim_commands['altitude']) fwhm_geom = FWHMgeom(phosim_commands['seeing'], bandpass, phosim_commands['altitude']) obs_md = ObservationMetaData(pointingRA=phosim_commands['rightascension'], pointingDec=phosim_commands['declination'], mjd=phosim_commands['mjd'], rotSkyPos=phosim_commands['rotskypos'], bandpassName=bandpass, m5=LSSTdefaults().m5(bandpass), seeing=fwhm_eff) # Set the OpsimMetaData attribute with the obshistID info. obs_md.OpsimMetaData = {'obshistID': phosim_commands['obshistid']} obs_md.OpsimMetaData['FWHMgeom'] = fwhm_geom obs_md.OpsimMetaData['FWHMeff'] = fwhm_eff obs_md.OpsimMetaData['rawSeeing'] = phosim_commands['seeing'] obs_md.OpsimMetaData['altitude'] = phosim_commands['altitude'] obs_md.OpsimMetaData['airmass'] = airmass(phosim_commands['altitude']) obs_md.OpsimMetaData['seed'] = phosim_commands['seed'] return obs_md
def calcEffWavelen(hardware, title, throughputDir=None): photParams = PhotometricParameters() lsstDefaults = LSSTdefaults() atmos = {} stdAtmoFile = os.path.join(os.getenv('SYSENG_THROUGHPUTS_DIR'), 'siteProperties/pachonModtranAtm_12.dat') atmos['std'] = Bandpass() atmos['std'].readThroughput(stdAtmoFile) multiAtmos = False if throughputDir is None: throughputDir = os.getenv('THROUGHPUTS_DIR') if throughputDir is not None: multiAtmos = True Xarr = np.arange(1.0, 2.55, 0.1) for X in Xarr: atmos['%.1f' % X] = Bandpass() atmos['%.1f' % X].readThroughput( os.path.join(throughputDir, 'atmos/atmos_%d.dat' % (int(X * 10)))) atmoskeys = sorted(atmos.keys()) print title print ' %s' % (' '.join(atmoskeys)) system = Bandpass() effsb = {} for f in ['u', 'g', 'r', 'i', 'z', 'y']: writestring = '%s ' % f for k in atmoskeys: system.wavelen, system.sb = hardware[f].multiplyThroughputs( atmos[k].wavelen, atmos[k].sb) effphi, effsb[k] = system.calcEffWavelen() writestring += '%.2f ' % (effsb[k]) print writestring
def phosim_obs_metadata(phosim_commands): """ Factory function to create an ObservationMetaData object based on the PhoSim commands extracted from an instance catalog. Parameters ---------- phosim_commands : dict Dictionary of PhoSim physics commands. Returns ------- lsst.sims.utils.ObservationMetaData Notes ----- The seeing from the instance catalog is the value at 500nm at zenith. Do we need to do a band-specific calculation? """ bandpass = phosim_commands['bandpass'] obs_md = ObservationMetaData(pointingRA=phosim_commands['rightascension'], pointingDec=phosim_commands['declination'], mjd=phosim_commands['mjd'], rotSkyPos=phosim_commands['rotskypos'], bandpassName=bandpass, m5=LSSTdefaults().m5(bandpass), seeing=phosim_commands['FWHMeff']) # Set the OpsimMetaData attribute with the obshistID info. obs_md.OpsimMetaData = {'obshistID': phosim_commands['obshistid']} obs_md.OpsimMetaData['FWHMgeom'] = phosim_commands['FWHMgeom'] obs_md.OpsimMetaData['FWHMeff'] = phosim_commands['FWHMeff'] obs_md.OpsimMetaData['rawSeeing'] = phosim_commands['rawSeeing'] obs_md.OpsimMetaData['altitude'] = phosim_commands['altitude'] return obs_md
def testSignalToNoise(self): """ Test that calcSNR_m5 and calcSNR_sed give similar results """ defaults = LSSTdefaults() photParams = PhotometricParameters() m5 = [] for i in range(len(self.hardwareList)): m5.append(snr.calcM5(self.skySed, self.bpList[i], self.hardwareList[i], photParams, seeing=defaults.seeing(self.filterNameList[i]))) sedDir = lsst.utils.getPackageDir('sims_sed_library') sedDir = os.path.join(sedDir, 'starSED', 'kurucz') fileNameList = os.listdir(sedDir) numpy.random.seed(42) offset = numpy.random.random_sample(len(fileNameList))*2.0 for ix, name in enumerate(fileNameList): if ix>100: break spectrum = Sed() spectrum.readSED_flambda(os.path.join(sedDir, name)) ff = spectrum.calcFluxNorm(m5[2]-offset[ix], self.bpList[2]) spectrum.multiplyFluxNorm(ff) magList = [] controlList = [] magList = [] for i in range(len(self.bpList)): controlList.append(snr.calcSNR_sed(spectrum, self.bpList[i], self.skySed, self.hardwareList[i], photParams, defaults.seeing(self.filterNameList[i]))) magList.append(spectrum.calcMag(self.bpList[i])) testList, gammaList = snr.calcSNR_m5(numpy.array(magList), numpy.array(self.bpList), numpy.array(m5), photParams) for tt, cc in zip(controlList, testList): msg = '%e != %e ' % (tt, cc) self.assertTrue(numpy.abs(tt/cc - 1.0) < 0.001, msg=msg)
def generate_percentiles(nbins=20): """ Make histograms of the 5-sigma limiting depths for each point and each filter. """ filters = ['u', 'g', 'r', 'i', 'z', 'y'] restore_file = 'healpix/59560_59772.npz' disk_data = np.load(restore_file) required_mjds = disk_data['header'][()]['required_mjds'].copy() dict_of_lists = disk_data['dict_of_lists'][()].copy() disk_data.close() sb_file = 'healpix/59560_59772.npy' sky_brightness = np.load(sb_file) npix = sky_brightness['r'].shape[-1] histograms = np.zeros((nbins, npix), dtype=list(zip(filters, [float] * 6))) histogram_npts = np.zeros(npix, dtype=list(zip(filters, [int] * 6))) # find the indices of all the evenly spaced mjd values even_mjd_indx = np.in1d(dict_of_lists['mjds'], required_mjds) # make an array to hold only the sky brightness values for evenly spaced mjds sky_brightness_reduced = np.ones((even_mjd_indx.sum(), npix), dtype=sky_brightness.dtype) for key in dict_of_lists: dict_of_lists[key] = dict_of_lists[key][even_mjd_indx] for key in filters: sky_brightness_reduced[key] = sky_brightness[key][even_mjd_indx, :] del sky_brightness for filtername in filters: # convert surface brightness to m5 FWHMeff = LSSTdefaults().FWHMeff(filtername) # increase as a function of airmass airmass_correction = np.power(dict_of_lists['airmass'], 0.6) FWHMeff *= airmass_correction m5_arr = m5_flat_sed(filtername, sky_brightness_reduced[filtername], FWHMeff, 30., dict_of_lists['airmass']) for indx in np.arange(npix): m5s = m5_arr[:, indx] m5s = m5s[np.isfinite(m5s)] m5s = np.sort(m5s) percentile_points = np.round(np.linspace(0, m5s.size - 1, nbins)) if m5s.size > percentile_points.size: histograms[filtername][:, indx] = m5s[percentile_points.astype( int)] histogram_npts[filtername][indx] = m5s.size # make the histogram for this point in the sky # histograms[filtername][:, indx] += np.histogram(m5s[np.isfinite(m5s)], # bins=bins[filtername])[0] np.savez('percentile_m5_maps.npz', histograms=histograms, histogram_npts=histogram_npts)
def testNoSystematicUncertainty(self): """ Test that systematic uncertainty is handled correctly when set to None. """ m5 = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7] photParams= PhotometricParameters(sigmaSys=0.0) obs_metadata = ObservationMetaData(unrefractedRA=23.0, unrefractedDec=45.0, m5=m5, bandpassName=self.filterNameList) magnitudes = [] for bp in self.bpList: mag = self.starSED.calcMag(bp) magnitudes.append(mag) skySedList = [] for bp, hardware, filterName in zip(self.bpList, self.hardwareList, self.filterNameList): skyDummy = Sed() skyDummy.readSED_flambda(os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline', 'darksky.dat')) normalizedSkyDummy = setM5(obs_metadata.m5[filterName], skyDummy, bp, hardware, seeing=LSSTdefaults().seeing(filterName), photParams=photParams) skySedList.append(normalizedSkyDummy) sigmaList = snr.calcMagError_m5(numpy.array(magnitudes), numpy.array(self.bpList), \ numpy.array(m5), photParams) for i in range(len(self.bpList)): snrat = snr.calcSNR_sed(self.starSED, self.bpList[i], skySedList[i], self.hardwareList[i], seeing=LSSTdefaults().seeing(self.filterNameList[i]), photParams=PhotometricParameters()) testSNR, gamma = snr.calcSNR_m5(numpy.array([magnitudes[i]]), [self.bpList[i]], numpy.array([m5[i]]), photParams=PhotometricParameters(sigmaSys=0.0)) self.assertAlmostEqual(snrat, testSNR[0], 10, msg = 'failed on calcSNR_m5 test %e != %e ' \ % (snrat, testSNR[0])) control = snr.magErrorFromSNR(testSNR) msg = '%e is not %e; failed' % (sigmaList[i], control) self.assertAlmostEqual(sigmaList[i], control, 10, msg=msg)
def testMagError(self): """ Make sure that calcMagError_sed and calcMagError_m5 agree to within 0.001 """ defaults = LSSTdefaults() photParams = PhotometricParameters() # create a cartoon spectrum to test on spectrum = Sed() spectrum.setFlatSED() spectrum.multiplyFluxNorm(1.0e-9) # find the magnitudes of that spectrum in our bandpasses magList = [] for total in self.bpList: magList.append(spectrum.calcMag(total)) magList = np.array(magList) # try for different normalizations of the skySED for fNorm in np.arange(1.0, 5.0, 1.0): self.skySed.multiplyFluxNorm(fNorm) for total, hardware, filterName, mm in \ zip(self.bpList, self.hardwareList, self.filterNameList, magList): FWHMeff = defaults.FWHMeff(filterName) m5 = snr.calcM5(self.skySed, total, hardware, photParams, FWHMeff=FWHMeff) sigma_sed = snr.calcMagError_sed(spectrum, total, self.skySed, hardware, photParams, FWHMeff=FWHMeff) sigma_m5, gamma = snr.calcMagError_m5(mm, total, m5, photParams) self.assertAlmostEqual(sigma_m5, sigma_sed, 3)
def testNoise(self): """ Test that ExampleCCDNoise puts the expected counts on an image by generating a flat image, adding noise and background to it, and calculating the variance of counts in the image. """ lsstDefaults = LSSTdefaults() gain = 2.5 readnoise = 6.0 photParams=PhotometricParameters(gain=gain, readnoise=readnoise) img = galsim.Image(100,100) noise = ExampleCCDNoise(seed=42) m5 = 24.5 bandpass = Bandpass() bandpass.readThroughput(os.path.join(lsst.utils.getPackageDir('throughputs'),'baseline','total_r.dat')) background = calcSkyCountsPerPixelForM5(m5, bandpass, seeing=lsstDefaults.seeing('r'), photParams=photParams) noisyImage = noise.addNoiseAndBackground(img, bandpass, m5=m5, seeing=lsstDefaults.seeing('r'), photParams=photParams) mean = 0.0 var = 0.0 for ix in range(1,101): for iy in range(1,101): mean += noisyImage(ix, iy) mean = mean/10000.0 for ix in range(1,101): for iy in range(1,101): var += (noisyImage(ix, iy) - mean)*(noisyImage(ix, iy) - mean) var = var/9999.0 varElectrons = background*gain + readnoise varADU = varElectrons/(gain*gain) msg = 'background %e mean %e ' % (background, mean) self.assertTrue(numpy.abs(background/mean - 1.0) < 0.05, msg=msg) msg = 'var %e varADU %e ; ratio %e ; background %e' % (var, varADU, var/varADU, background) self.assertTrue(numpy.abs(var/varADU - 1.0) < 0.05, msg=msg)
def testSignalToNoise(self): """ Test that calcSNR_m5 and calcSNR_sed give similar results """ defaults = LSSTdefaults() photParams = PhotometricParameters() m5 = [] for i in range(len(self.hardwareList)): m5.append( snr.calcM5(self.skySed, self.bpList[i], self.hardwareList[i], photParams, FWHMeff=defaults.FWHMeff(self.filterNameList[i]))) sedDir = os.path.join(lsst.utils.getPackageDir('sims_photUtils'), 'tests/cartoonSedTestData/starSed/') sedDir = os.path.join(sedDir, 'kurucz') fileNameList = os.listdir(sedDir) rng = np.random.RandomState(42) offset = rng.random_sample(len(fileNameList)) * 2.0 for ix, name in enumerate(fileNameList): if ix > 100: break spectrum = Sed() spectrum.readSED_flambda(os.path.join(sedDir, name)) ff = spectrum.calcFluxNorm(m5[2] - offset[ix], self.bpList[2]) spectrum.multiplyFluxNorm(ff) for i in range(len(self.bpList)): control_snr = snr.calcSNR_sed( spectrum, self.bpList[i], self.skySed, self.hardwareList[i], photParams, defaults.FWHMeff(self.filterNameList[i])) mag = spectrum.calcMag(self.bpList[i]) test_snr, gamma = snr.calcSNR_m5(mag, self.bpList[i], m5[i], photParams) self.assertLess((test_snr - control_snr) / control_snr, 0.001)
def testMagError(self): """ Make sure that calcMagError_sed and calcMagError_m5 agree to within 0.001 """ defaults = LSSTdefaults() photParams = PhotometricParameters() #create a cartoon spectrum to test on spectrum = Sed() spectrum.setFlatSED() spectrum.multiplyFluxNorm(1.0e-9) #find the magnitudes of that spectrum in our bandpasses magList = [] for total in self.bpList: magList.append(spectrum.calcMag(total)) magList = numpy.array(magList) #try for different normalizations of the skySED for fNorm in numpy.arange(1.0, 5.0, 1.0): self.skySed.multiplyFluxNorm(fNorm) m5List = [] magSed = [] for total, hardware, filterName in \ zip(self.bpList, self.hardwareList, self.filterNameList): seeing = defaults.seeing(filterName) m5List.append(snr.calcM5(self.skySed, total, hardware, photParams,seeing=seeing)) magSed.append(snr.calcMagError_sed(spectrum, total, self.skySed, hardware, photParams, seeing=seeing)) magSed = numpy.array(magSed) magM5 = snr.calcMagError_m5(magList, self.bpList, numpy.array(m5List), photParams) numpy.testing.assert_array_almost_equal(magM5, magSed, decimal=3)
def calcM5(skysed, totalBandpass, hardware, photParams, seeing=None): """ Calculate the AB magnitude of a 5-sigma above sky background source. 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 (calcM5) calculates the expected m5 value for an observation given a sky background Sed and hardware parameters. @param [in] skysed is an instantiation of the Sed class representing sky emission, normalized so that skysed.calcMag gives the sky brightness in magnitudes per square arcsecond. @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] seeing in arcseconds @param [out] returns the value of m5 for the given bandpass and sky SED """ # This comes from equation 45 of the SNR document (v1.2, May 2010) # https://docushare.lsstcorp.org/docushare/dsweb/ImageStoreViewer/LSE-40 if seeing is None: seeing = LSSTdefaults().seeing('r') # create a flat fnu source flatsource = Sed() flatsource.setFlatSED() snr = 5.0 v_n = calcTotalNonSourceNoiseSq(skysed, hardware, photParams, seeing) counts_5sigma = (snr**2)/2.0/photParams.gain + \ numpy.sqrt((snr**4)/4.0/photParams.gain + (snr**2)*v_n) # renormalize flatsource so that it has the required counts to be a 5-sigma detection # given the specified background counts_flat = flatsource.calcADU(totalBandpass, photParams=photParams) flatsource.multiplyFluxNorm(counts_5sigma/counts_flat) # Calculate the AB magnitude of this source. mag_5sigma = flatsource.calcMag(totalBandpass) return mag_5sigma
def testStellarPhotometricUncertainties(self): """ Test in the case of a catalog of stars """ lsstDefaults = LSSTdefaults() starDB = testStarsDBObj(driver=self.driver, host=self.host, database=self.dbName) starCat = testStarCatalog(starDB, obs_metadata=self.obs_metadata) ct = 0 for line in starCat.iter_catalog(): starSed = Sed() starSed.readSED_flambda( os.path.join(getPackageDir('sims_sed_library'), defaultSpecMap[line[14]])) imsimband = Bandpass() imsimband.imsimBandpass() fNorm = starSed.calcFluxNorm(line[15], imsimband) starSed.multiplyFluxNorm(fNorm) aV = np.float(line[16]) a_int, b_int = starSed.setupCCMab() starSed.addCCMDust(a_int, b_int, A_v=aV) for i in range(len(self.bandpasses)): controlSigma = calcMagError_sed( starSed, self.totalBandpasses[i], self.skySeds[i], self.hardwareBandpasses[i], FWHMeff=lsstDefaults.FWHMeff(self.bandpasses[i]), photParams=PhotometricParameters()) testSigma = line[8 + i] self.assertAlmostEqual(controlSigma, testSigma, 4) ct += 1 self.assertGreater(ct, 0)
def testVerboseSNR(self): """ Make sure that calcSNR_sed has everything it needs to run in verbose mode """ defaults = LSSTdefaults() photParams = PhotometricParameters() #create a cartoon spectrum to test on spectrum = Sed() spectrum.setFlatSED() spectrum.multiplyFluxNorm(1.0e-9) snr.calcSNR_sed(spectrum, self.bpList[0], self.skySed, self.hardwareList[0], photParams, seeing=0.7, verbose=True)
def testMagError(self): """ Make sure that calcMagError_sed and calcMagError_m5 agree to within 0.001 """ defaults = LSSTdefaults() photParams = PhotometricParameters() # create a cartoon spectrum to test on spectrum = Sed() spectrum.setFlatSED() spectrum.multiplyFluxNorm(1.0e-9) # find the magnitudes of that spectrum in our bandpasses magList = [] for total in self.bpList: magList.append(spectrum.calcMag(total)) magList = numpy.array(magList) # try for different normalizations of the skySED for fNorm in numpy.arange(1.0, 5.0, 1.0): self.skySed.multiplyFluxNorm(fNorm) m5List = [] magSed = [] for total, hardware, filterName in zip(self.bpList, self.hardwareList, self.filterNameList): seeing = defaults.seeing(filterName) m5List.append(snr.calcM5(self.skySed, total, hardware, photParams, seeing=seeing)) magSed.append(snr.calcMagError_sed(spectrum, total, self.skySed, hardware, photParams, seeing=seeing)) magSed = numpy.array(magSed) magM5 = snr.calcMagError_m5(magList, self.bpList, numpy.array(m5List), photParams) numpy.testing.assert_array_almost_equal(magM5, magSed, decimal=3)
def testSignalToNoise(self): """ Test that calcSNR_m5 and calcSNR_sed give similar results """ defaults = LSSTdefaults() photParams = PhotometricParameters() totalDict, hardwareDict = BandpassDict.loadBandpassesFromFiles() skySED = Sed() skySED.readSED_flambda(os.path.join(lsst.utils.getPackageDir("throughputs"), "baseline", "darksky.dat")) m5 = [] for filt in totalDict: m5.append(calcM5(skySED, totalDict[filt], hardwareDict[filt], photParams, seeing=defaults.seeing(filt))) sedDir = lsst.utils.getPackageDir("sims_sed_library") sedDir = os.path.join(sedDir, "starSED", "kurucz") fileNameList = os.listdir(sedDir) numpy.random.seed(42) offset = numpy.random.random_sample(len(fileNameList)) * 2.0 for ix, name in enumerate(fileNameList): if ix > 100: break spectrum = Sed() spectrum.readSED_flambda(os.path.join(sedDir, name)) ff = spectrum.calcFluxNorm(m5[2] - offset[ix], totalDict.values()[2]) spectrum.multiplyFluxNorm(ff) magList = [] controlList = [] magList = [] for filt in totalDict: controlList.append( calcSNR_sed( spectrum, totalDict[filt], skySED, hardwareDict[filt], photParams, defaults.seeing(filt) ) ) magList.append(spectrum.calcMag(totalDict[filt])) testList, gammaList = calcSNR_m5( numpy.array(magList), numpy.array(totalDict.values()), numpy.array(m5), photParams ) for tt, cc in zip(controlList, testList): msg = "%e != %e " % (tt, cc) self.assertTrue(numpy.abs(tt / cc - 1.0) < 0.001, msg=msg)
def obs_metadata(commands): """ Create an ObservationMetaData instance from phosim commands. Parameters ---------- commands : dict Dictionary of phosim instance catalog commands. Returns: lsst.sims.utils.ObservationMetaData """ return ObservationMetaData(pointingRA=commands['rightascension'], pointingDec=commands['declination'], mjd=commands['mjd'], rotSkyPos=commands['rotskypos'], bandpassName=commands['bandpass'], m5=LSSTdefaults().m5(commands['bandpass']), seeing=commands['seeing'])
def compare_to_imsim(phosim_commands): bandpass = bandpass_all[int(phosim_commands['filter'].values[0])] obs_md = ObservationMetaData( pointingRA=float(phosim_commands['rightascension'].values[0]), pointingDec=float(phosim_commands['declination'].values[0]), mjd=float(phosim_commands['mjd'].values[0]), rotSkyPos=float(phosim_commands['rotskypos'].values[0]), bandpassName=bandpass, m5=LSSTdefaults().m5(bandpass), seeing=float(phosim_commands['seeing'].values[0])) noise_and_background = ESOSkyModel(obs_md, addNoise=True, addBackground=True) phot_params = PhotometricParameters( exptime=float(phosim_commands['vistime'].values[0]), nexp=int(phosim_commands['nsnap'].values[0]), gain=1, readnoise=0, darkcurrent=0, bandpass=bandpass) # We are going to check one sensor only detector_list = [ make_galsim_detector(camera_wrapper, "R:2,2 S:1,1", phot_params, obs_md) ] bp_dict = BandpassDict.loadTotalBandpassesFromFiles( bandpassNames=obs_md.bandpass) gs_interpreter = GalSimInterpreter(obs_metadata=obs_md, epoch=2000.0, detectors=detector_list, bandpassDict=bp_dict, noiseWrapper=noise_and_background, seed=1234) image = gs_interpreter.blankImage(detector=detector_list[0]) image_2 = noise_and_background.addNoiseAndBackground( image, bandpass=obs_md.bandpass, m5=obs_md.m5, FWHMeff=obs_md.seeing, photParams=phot_params, chipName=detector_list[0].name) return compute_bkg(image_2.array)
def setUpClass(cls): cls.camera = camTestUtils.CameraWrapper().camera cls.scratch_dir = tempfile.mkdtemp(dir=ROOT, prefix='GalSimInterfaceTest-') cls.dbName = os.path.join(cls.scratch_dir, 'galSimTestDB.db') deltaRA = np.array([72.0/3600.0]) deltaDec = np.array([0.0]) defaults = LSSTdefaults() cls.bandpassNameList = ['u', 'g', 'r', 'i', 'z', 'y'] cls.m5 = [16.0+ix for ix in range(len(cls.bandpassNameList))] cls.seeing = [defaults._FWHMeff[bb] for bb in cls.bandpassNameList] cls.obs_metadata = makePhoSimTestDB(filename=cls.dbName, size=1, deltaRA=deltaRA, deltaDec=deltaDec, bandpass=cls.bandpassNameList, m5=cls.m5, seeing=cls.seeing, seedVal=65) cls.driver = 'sqlite'
def setUpClass(cls): cls.scratch_dir = os.path.join(getPackageDir('sims_GalSimInterface'), 'tests', 'scratchSpace') cls.dbName = os.path.join(cls.scratch_dir, 'galSimTestDB.db') if os.path.exists(cls.dbName): os.unlink(cls.dbName) deltaRA = np.array([72.0 / 3600.0]) deltaDec = np.array([0.0]) defaults = LSSTdefaults() cls.bandpassNameList = ['u', 'g', 'r', 'i', 'z', 'y'] cls.m5 = [16.0 + ix for ix in range(len(cls.bandpassNameList))] cls.seeing = [defaults._FWHMeff[bb] for bb in cls.bandpassNameList] cls.obs_metadata = makePhoSimTestDB(filename=cls.dbName, size=1, deltaRA=deltaRA, deltaDec=deltaDec, bandpass=cls.bandpassNameList, m5=cls.m5, seeing=cls.seeing, seedVal=65) cls.driver = 'sqlite'
def testGalaxyPhotometricUncertainties(self): """ Test in the case of a catalog of galaxies """ lsstDefaults = LSSTdefaults() phot = PhotometryGalaxies() phot.loadTotalBandpassesFromFiles() galDB = testGalaxyTileDBObj(driver=self.driver, host=self.host, database=self.dbName) galCat = testGalaxyCatalog(galDB, obs_metadata=self.obs_metadata) imsimband = Bandpass() imsimband.imsimBandpass() ct = 0 for line in galCat.iter_catalog(): bulgeSedName = line[50] diskSedName = line[51] agnSedName = line[52] magNormBulge = line[53] magNormDisk = line[54] magNormAgn = line[55] avBulge = line[56] avDisk = line[57] redshift = line[58] bulgeSed = Sed() bulgeSed.readSED_flambda(os.path.join(lsst.utils.getPackageDir('sims_sed_library'), defaultSpecMap[bulgeSedName])) fNorm=bulgeSed.calcFluxNorm(magNormBulge, imsimband) bulgeSed.multiplyFluxNorm(fNorm) diskSed = Sed() diskSed.readSED_flambda(os.path.join(lsst.utils.getPackageDir('sims_sed_library'), defaultSpecMap[diskSedName])) fNorm = diskSed.calcFluxNorm(magNormDisk, imsimband) diskSed.multiplyFluxNorm(fNorm) agnSed = Sed() agnSed.readSED_flambda(os.path.join(lsst.utils.getPackageDir('sims_sed_library'), defaultSpecMap[agnSedName])) fNorm = agnSed.calcFluxNorm(magNormAgn, imsimband) agnSed.multiplyFluxNorm(fNorm) phot.applyAv([bulgeSed, diskSed], [avBulge, avDisk]) phot.applyRedshift([bulgeSed, diskSed, agnSed], [redshift, redshift, redshift]) numpy.testing.assert_almost_equal(bulgeSed.wavelen, diskSed.wavelen) numpy.testing.assert_almost_equal(bulgeSed.wavelen, agnSed.wavelen) fl = bulgeSed.flambda + diskSed.flambda + agnSed.flambda totalSed = Sed(wavelen=bulgeSed.wavelen, flambda=fl) sedList = [totalSed, bulgeSed, diskSed, agnSed] for i, spectrum in enumerate(sedList): if i==0: msgroot = 'failed on total' elif i==1: msgroot = 'failed on bulge' elif i==2: msgroot = 'failed on disk' elif i==3: msgroot = 'failed on agn' for j, b in enumerate(self.bandpasses): controlSigma = calcMagError_sed(spectrum, self.totalBandpasses[j], self.skySeds[j], self.hardwareBandpasses[j], seeing=lsstDefaults.seeing(b), photParams=PhotometricParameters()) testSigma = line[26+(i*6)+j] msg = '%e neq %e; ' % (testSigma, controlSigma) + msgroot self.assertAlmostEqual(testSigma, controlSigma, 10, msg=msg) ct += 1 self.assertTrue(ct>0)
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
def testGalaxyPhotometricUncertainties(self): """ Test in the case of a catalog of galaxies """ lsstDefaults = LSSTdefaults() galDB = testGalaxyTileDBObj(driver=self.driver, host=self.host, database=self.dbName) galCat = testGalaxyCatalog(galDB, obs_metadata=self.obs_metadata) imsimband = Bandpass() imsimband.imsimBandpass() ct = 0 for line in galCat.iter_catalog(): bulgeSedName = line[50] diskSedName = line[51] agnSedName = line[52] magNormBulge = line[53] magNormDisk = line[54] magNormAgn = line[55] avBulge = line[56] avDisk = line[57] redshift = line[58] bulgeSed = Sed() bulgeSed.readSED_flambda( os.path.join(getPackageDir('sims_sed_library'), defaultSpecMap[bulgeSedName])) fNorm = bulgeSed.calcFluxNorm(magNormBulge, imsimband) bulgeSed.multiplyFluxNorm(fNorm) diskSed = Sed() diskSed.readSED_flambda( os.path.join(getPackageDir('sims_sed_library'), defaultSpecMap[diskSedName])) fNorm = diskSed.calcFluxNorm(magNormDisk, imsimband) diskSed.multiplyFluxNorm(fNorm) agnSed = Sed() agnSed.readSED_flambda( os.path.join(getPackageDir('sims_sed_library'), defaultSpecMap[agnSedName])) fNorm = agnSed.calcFluxNorm(magNormAgn, imsimband) agnSed.multiplyFluxNorm(fNorm) a_int, b_int = bulgeSed.setupCCMab() bulgeSed.addCCMDust(a_int, b_int, A_v=avBulge) a_int, b_int = diskSed.setupCCMab() diskSed.addCCMDust(a_int, b_int, A_v=avDisk) bulgeSed.redshiftSED(redshift, dimming=True) diskSed.redshiftSED(redshift, dimming=True) agnSed.redshiftSED(redshift, dimming=True) bulgeSed.resampleSED(wavelen_match=self.totalBandpasses[0].wavelen) diskSed.resampleSED(wavelen_match=bulgeSed.wavelen) agnSed.resampleSED(wavelen_match=bulgeSed.wavelen) np.testing.assert_almost_equal(bulgeSed.wavelen, diskSed.wavelen) np.testing.assert_almost_equal(bulgeSed.wavelen, agnSed.wavelen) fl = bulgeSed.flambda + diskSed.flambda + agnSed.flambda totalSed = Sed(wavelen=bulgeSed.wavelen, flambda=fl) sedList = [totalSed, bulgeSed, diskSed, agnSed] for i, spectrum in enumerate(sedList): if i == 0: msgroot = 'failed on total' elif i == 1: msgroot = 'failed on bulge' elif i == 2: msgroot = 'failed on disk' elif i == 3: msgroot = 'failed on agn' for j, b in enumerate(self.bandpasses): controlSigma = calcMagError_sed( spectrum, self.totalBandpasses[j], self.skySeds[j], self.hardwareBandpasses[j], FWHMeff=lsstDefaults.FWHMeff(b), photParams=PhotometricParameters()) testSigma = line[26 + (i * 6) + j] msg = '%e neq %e; ' % (testSigma, controlSigma) + msgroot self.assertAlmostEqual(testSigma, controlSigma, 10, msg=msg) ct += 1 self.assertGreater(ct, 0)
def setUpClass(cls): lsstDefaults = LSSTdefaults() cls.dbName = 'uncertaintyTestDB.db' if os.path.exists(cls.dbName): os.unlink(cls.dbName) default_obs_metadata = makePhoSimTestDB(filename=cls.dbName, size=10, radius=5.0) bandpass = ['u', 'g', 'r', 'i', 'z', 'y'] m5 = list(lsstDefaults._m5.values()) cls.obs_metadata = ObservationMetaData( pointingRA=default_obs_metadata.pointingRA, pointingDec=default_obs_metadata.pointingDec, rotSkyPos=default_obs_metadata.rotSkyPos, bandpassName=bandpass, m5=m5) cls.obs_metadata.setBandpassM5andSeeing(bandpassName=bandpass, m5=m5) cls.driver = 'sqlite' cls.host = '' cls.skySeds = [] cls.hardwareBandpasses = [] cls.totalBandpasses = [] cls.bandpasses = ['u', 'g', 'r', 'i', 'z', 'y'] components = [ 'detector.dat', 'm1.dat', 'm2.dat', 'm3.dat', 'lens1.dat', 'lens2.dat', 'lens3.dat' ] for b in cls.bandpasses: bandpassDummy = Bandpass() bandpassDummy.readThroughput( os.path.join(getPackageDir('throughputs'), 'baseline', 'total_%s.dat' % b)) cls.totalBandpasses.append(bandpassDummy) for b in cls.bandpasses: finalComponents = [] for c in components: finalComponents.append( os.path.join(getPackageDir('throughputs'), 'baseline', c)) finalComponents.append( os.path.join(getPackageDir('throughputs'), 'baseline', 'filter_%s.dat' % b)) bandpassDummy = Bandpass() bandpassDummy.readThroughputList(finalComponents) cls.hardwareBandpasses.append(bandpassDummy) for i in range(len(cls.bandpasses)): sedDummy = Sed() sedDummy.readSED_flambda( os.path.join(getPackageDir('throughputs'), 'baseline', 'darksky.dat')) normalizedSedDummy = setM5(cls.obs_metadata.m5[cls.bandpasses[i]], sedDummy, cls.totalBandpasses[i], cls.hardwareBandpasses[i], FWHMeff=lsstDefaults.FWHMeff( cls.bandpasses[i]), photParams=PhotometricParameters()) cls.skySeds.append(normalizedSedDummy)
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
#If you want to use the LSST camera, uncomment the line below. #You can similarly assign any camera object you want here #camera = LsstSimMapper().camera PSF = SNRdocumentPSF() class testGalSimGalaxiesNoisy(testGalSimGalaxiesNoiseless): #defined in galSimInterface/galSimUtilities.py noise_and_background = ExampleCCDNoise(99) #select an OpSim pointing obsMD = OpSim3_61DBObject() raw_obs_metadata = obsMD.getObservationMetaData(88625744, 0.05, makeCircBounds = True) defaults = LSSTdefaults() obs_metadata = ObservationMetaData(pointingRA=raw_obs_metadata.pointingRA, pointingDec=raw_obs_metadata.pointingDec, boundType='circle', boundLength=0.05, mjd=raw_obs_metadata.mjd, rotSkyPos=raw_obs_metadata.rotSkyPos, bandpassName=['u','g'], m5=[defaults.m5('u'), defaults.m5('g')], seeing=[defaults.seeing('u'), defaults.seeing('g')]) #grab a database of galaxies (in this case, galaxy bulges) gals = CatalogDBObject.from_objid('galaxyBulge') #now append a bunch of objects with 2D sersic profiles to our output file gal_noiseless = testGalSimGalaxiesNoiseless(gals, obs_metadata=obs_metadata)
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 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
dd = pd.read_csv('../raftInstall.csv',index_col=0) rnames = [] for i in dd.index: try: if np.isnan(dd.rtm[i]): print(i) except TypeError: #when dd.rtm[i] is a str rnames.append(i) exptime=15 nexp=2 othernoise=0 darkcurrent=0.2 X=1.0 lsstDefaults = LSSTdefaults() addLosses = True defaultDirs = st.setDefaultDirs() atmos = st.readAtmosphere(defaultDirs['atmosphere'], atmosFile='atmos_10_aerosol.dat') mirror1 = st.buildMirror(defaultDirs['mirror1'], addLosses) mirror2 = st.buildMirror(defaultDirs['mirror2'], addLosses) mirror3 = st.buildMirror(defaultDirs['mirror3'], addLosses) lens1 = st.buildLens(defaultDirs['lens1'], addLosses) lens2 = st.buildLens(defaultDirs['lens2'], addLosses) lens3 = st.buildLens(defaultDirs['lens3'], addLosses) filters = st.buildFilters(defaultDirs['filters'], addLosses) for rname in rnames: vendor = dd.vendor[rname] vendorDir = defaultDirs['detector']+'/../'+vendor.lower()
class testGalSimGalaxiesNoisy(testGalSimGalaxiesNoiseless): #defined in galSimInterface/galSimUtilities.py noise_and_background = ExampleCCDNoise(99) #select an OpSim pointing opsimdb = os.path.join(getPackageDir('sims_data'), 'OpSimData', 'opsimblitz1_1133_sqlite.db') obs_gen = ObservationMetaDataGenerator(database=opsimdb, driver='sqlite') obs_list = obs_gen.getObservationMetaData(obsHistID=10, boundLength=0.05) raw_obs_metadata = obs_list[0] defaults = LSSTdefaults() obs_metadata = ObservationMetaData( pointingRA=raw_obs_metadata.pointingRA, pointingDec=raw_obs_metadata.pointingDec, boundType='circle', boundLength=0.05, mjd=raw_obs_metadata.mjd, rotSkyPos=raw_obs_metadata.rotSkyPos, bandpassName=['u', 'g'], m5=[defaults.m5('u'), defaults.m5('g')], seeing=[defaults.FWHMeff('u'), defaults.FWHMeff('g')]) #grab a database of galaxies (in this case, galaxy bulges) gals = CatalogDBObject.from_objid('galaxyBulge')
def calcSkyCountsPerPixelForM5(m5target, totalBandpass, photParams, seeing=None): """ Calculate the number of sky counts per pixel expected for a given value of the 5-sigma limiting magnitude (m5) 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. @param [in] the desired value of m5 @param [in] totalBandpass is an instantiation of the Bandpass class representing the total throughput of the telescope (instrumentation plus atmosphere) @param [in] photParams is an instantiation of the PhotometricParameters class that carries details about the photometric response of the telescope. @param [in] seeing in arcseconds @param [out] returns the expected number of sky counts per pixel """ if seeing is None: seeing = LSSTdefaults().seeing('r') # instantiate a flat SED flatSed = Sed() flatSed.setFlatSED() # normalize the SED so that it has a magnitude equal to the desired m5 fNorm = flatSed.calcFluxNorm(m5target, totalBandpass) flatSed.multiplyFluxNorm(fNorm) sourceCounts = flatSed.calcADU(totalBandpass, photParams=photParams) # calculate the effective number of pixels for a double-Gaussian PSF neff = calcNeff(seeing, photParams.platescale) # calculate the square of the noise due to the instrument noise_instr_sq = calcInstrNoiseSq(photParams=photParams) # now solve equation 41 of the SNR document for the neff * sigma_total^2 term # given snr=5 and counts as calculated above # SNR document can be found at # https://docushare.lsstcorp.org/docushare/dsweb/ImageStoreViewer/LSE-40 nSigmaSq = (sourceCounts*sourceCounts)/25.0 - sourceCounts/photParams.gain skyNoiseTarget = nSigmaSq/neff - noise_instr_sq skyCountsTarget = skyNoiseTarget*photParams.gain # TODO: # This method should throw an error if skyCountsTarget is negative # unfortunately, that currently happens for default values of # m5 as taken from arXiv:0805.2366, table 2. Adding the error # should probably wait for a later issue in which we hash out what # the units are for all of the parameters stored in PhotometricDefaults. return skyCountsTarget