def __init__(self, m5Col='fiveSigmaDepth', metricName='ExgalM5', units='mag', lsstFilter='r', wavelen_min=None , wavelen_max=None , **kwargs): # Set the name for the dust map to use. This is gathered into the MetricBundle. maps = ['DustMap'] # Set the default wavelength limits for the lsst filters. These are approximately correct. waveMins = {'u':330.,'g':403.,'r':552.,'i':691.,'z':818.,'y':950.} waveMaxes = {'u':403.,'g':552.,'r':691.,'i':818.,'z':922.,'y':1070.} if lsstFilter is not None: wavelen_min = waveMins[lsstFilter] wavelen_max = waveMaxes[lsstFilter] self.m5Col = m5Col super().__init__(col=[self.m5Col], maps=maps, metricName=metricName, units=units, **kwargs) # Set up internal values for the dust extinction. testsed = Sed() testsed.setFlatSED(wavelen_min=wavelen_min, wavelen_max=wavelen_max, wavelen_step=1.0) testbandpass = Bandpass(wavelen_min=wavelen_min, wavelen_max=wavelen_max, wavelen_step=1.0) testbandpass.setBandpass(wavelen=testsed.wavelen, sb=np.ones(len(testsed.wavelen))) self.R_v = 3.1 self.ref_ebv = 1.0 # Calculate non-dust-extincted magnitude flatmag = testsed.calcMag(testbandpass) # Add dust self.a, self.b = testsed.setupCCM_ab() testsed.addDust(self.a, self.b, ebv=self.ref_ebv, R_v=self.R_v) # Calculate difference due to dust when EBV=1.0 (m_dust = m_nodust - Ax, Ax > 0) self.Ax1 = testsed.calcMag(testbandpass) - flatmag # We will call Coaddm5Metric to calculate the coadded depth. Set it up here. self.Coaddm5Metric = Coaddm5Metric(m5Col=m5Col)
def _calcColors(self, sedname='C.dat'): """ Calculate the colors for a moving object with sed 'sedname'. """ # Do we need to read in the LSST bandpasses? try: self.lsst except AttributeError: filterdir = os.getenv('LSST_THROUGHPUTS_BASELINE') filterlist = ('u', 'g', 'r', 'i', 'z', 'y') self.lsst ={} for f in filterlist: self.lsst[f] = Bandpass() self.lsst[f].readThroughput(os.path.join(filterdir, 'total_'+f+'.dat')) self.vband = Bandpass() self.vband.readThroughput('harris_V.dat') self.colors = {} # See if the sed's colors are in memory already. if sedname not in self.colors: moSed = Sed() moSed.readSED_flambda(sedname) vmag = moSed.calcMag(self.vband) self.colors[sedname] = {} for f in filterlist: self.colors[sedname][f] = moSed.calcMag(self.lsst[f]) - vmag return self.colors[sedname]
def calcColors(self, sedname='C.dat', sedDir=None): """Calculate the colors for a given SED. If the sedname is not already in the dictionary self.colors, this reads the SED from disk and calculates all V-[filter] colors for all filters in self.filterlist. The result is stored in self.colors[sedname][filter]. Parameters ---------- sedname : str (opt) Name of the SED. Default 'C.dat'. sedDir : str (opt) Directory containing the SEDs of the moving objects. Default None = $SIMS_MOVINGOBJECTS_DIR/data. Returns ------- dict Dictionary of the colors in self.filterlist for this particular Sed. """ if sedname not in self.colors: if sedDir is None: sedDir = os.path.join(getPackageDir('SIMS_MOVINGOBJECTS'), 'data') moSed = Sed() moSed.readSED_flambda(os.path.join(sedDir, sedname)) vmag = moSed.calcMag(self.vband) self.colors[sedname] = {} for f in self.filterlist: self.colors[sedname][f] = moSed.calcMag(self.lsst[f]) - vmag return self.colors[sedname]
def testMagListForSedList(self): """ Test that magListForSedList calculates the correct magnitude """ nBandpasses = 7 bpNameList, bpList = self.getListOfBandpasses(nBandpasses) testBpDict = BandpassDict(bpList, bpNameList) nSed = 20 sedNameList = self.getListOfSedNames(nSed) magNormList = self.rng.random_sample(nSed)*5.0 + 15.0 internalAvList = self.rng.random_sample(nSed)*0.3 + 0.1 redshiftList = self.rng.random_sample(nSed)*5.0 galacticAvList = self.rng.random_sample(nSed)*0.3 + 0.1 # first, test on an SedList without a wavelenMatch testSedList = SedList(sedNameList, magNormList, fileDir=self.sedDir, internalAvList=internalAvList, redshiftList=redshiftList, galacticAvList=galacticAvList) magList = testBpDict.magListForSedList(testSedList) self.assertEqual(magList.shape[0], nSed) self.assertEqual(magList.shape[1], nBandpasses) for ix, sedObj in enumerate(testSedList): dummySed = Sed(wavelen=copy.deepcopy(sedObj.wavelen), flambda=copy.deepcopy(sedObj.flambda)) for iy, bp in enumerate(testBpDict): mag = dummySed.calcMag(bpList[iy]) self.assertAlmostEqual(mag, magList[ix][iy], 2) # now use wavelenMatch testSedList = SedList(sedNameList, magNormList, fileDir=self.sedDir, internalAvList=internalAvList, redshiftList=redshiftList, galacticAvList=galacticAvList, wavelenMatch=testBpDict.wavelenMatch) magList = testBpDict.magListForSedList(testSedList) self.assertEqual(magList.shape[0], nSed) self.assertEqual(magList.shape[1], nBandpasses) for ix, sedObj in enumerate(testSedList): dummySed = Sed(wavelen=copy.deepcopy(sedObj.wavelen), flambda=copy.deepcopy(sedObj.flambda)) for iy, bp in enumerate(testBpDict): mag = dummySed.calcMag(bpList[iy]) self.assertAlmostEqual(mag, magList[ix][iy], 2)
def get_sed(name, magnorm, redshift, av, rv): if not hasattr(get_sed, '_rest_dict'): get_sed._rest_dict = {} get_sed._imsim_bp = Bandpass() get_sed._imsim_bp.imsimBandpass() get_sed._sed_dir = os.environ['SIMS_SED_LIBRARY_DIR'] get_sed._ccm_w = None tag = '%s_%.2f_%.2f' % (name, av, rv) if tag not in get_sed._rest_dict: ss = Sed() ss.readSED_flambda(os.path.join(get_sed._sed_dir, name)) if get_sed._ccm_w is None or not np.array_equal( ss.wavelen, get_sed._ccm_w): get_sed._ccm_w = np.copy(ss.wavelen) get_sed._ax, get_sed._bx = ss.setupCCM_ab() mn = ss.calcMag(get_sed._imsim_bp) ss.addDust(get_sed._ax, get_sed._bx, A_v=av, R_v=rv) get_sed._rest_dict[tag] = (ss, mn) base_sed = get_sed._rest_dict[tag][0] ss = Sed(wavelen=base_sed.wavelen, flambda=base_sed.flambda) dmag = magnorm - get_sed._rest_dict[tag][1] fnorm = np.power(10.0, -0.4 * dmag) ss.multiplyFluxNorm(fnorm) ss.redshiftSED(redshift, dimming=True) return ss
def returnMags(self, bandpass=None): """ Convert the computed spectra to magnitudes using the supplied bandpasses, or, if self.mags=True, just return the mags in the LSST filters If mags=True when initialized, return mags returns an structured array with dtype names u,g,r,i,z,y. """ if self.mags: if bandpass: warnings.warn('Ignoring set bandpasses and returning LSST ugrizy.') mags = -2.5*np.log10(self.spec)+np.log10(3631.) # Mask out high airmass mags[self.mask] *= np.nan # Convert to a structured array mags = np.core.records.fromarrays(mags.transpose(), names='u,g,r,i,z,y', formats='float,'*6) else: mags = np.zeros(self.npts, dtype=float)-666 tempSed = Sed() isThrough = np.where(bandpass.sb > 0) minWave = bandpass.wavelen[isThrough].min() maxWave = bandpass.wavelen[isThrough].max() inBand = np.where((self.wave >= minWave) & (self.wave <= maxWave)) for i, ra in enumerate(self.ra): # Check that there is flux in the band, otherwise calcMag fails if np.max(self.spec[i, inBand]) > 0: tempSed.setSED(self.wave, flambda=self.spec[i, :]) mags[i] = tempSed.calcMag(bandpass) # Mask out high airmass mags[self.mask] *= np.nan return mags
def _create_library_one_sed(_galaxy_sed_dir, sed_file_name_list, av_grid, rv_grid, bandpass_dict, out_dict, out_lock): n_obj = 0 for i_av, av in enumerate(av_grid): for i_rv, rv in enumerate(rv_grid): if av < 0.01 and i_rv > 0: continue n_obj += 1 imsim_bp = Bandpass() imsim_bp.imsimBandpass() t_start = time.time() sed_names_out = [] rv_out_list_out = [] av_out_list_out = [] sed_mag_norm_out = [] sed_mag_list_out = [] for i_sed, sed_file_name in enumerate(sed_file_name_list): base_spec = Sed() base_spec.readSED_flambda(os.path.join(_galaxy_sed_dir, sed_file_name)) ax, bx = base_spec.setupCCM_ab() mag_norm = base_spec.calcMag(imsim_bp) sed_names = np.array([defaultSpecMap[sed_file_name]] * n_obj) rv_out_list = np.zeros(n_obj, dtype=float) av_out_list = np.zeros(n_obj, dtype=float) sed_mag_norm = mag_norm * np.ones(n_obj, dtype=float) sed_mag_list = np.zeros((n_obj, len(bandpass_dict)), dtype=float) i_obj = 0 for i_av, av in enumerate(av_grid): for i_rv, rv in enumerate(rv_grid): if av < 0.01 and i_rv > 0: continue spec = Sed(wavelen=base_spec.wavelen, flambda=base_spec.flambda) spec.addDust(ax, bx, A_v=av, R_v=rv) av_out_list[i_obj] = av rv_out_list[i_obj] = rv sed_mag_list[i_obj][:] = bandpass_dict.magListForSed(spec) i_obj += 1 sed_names_out.append(sed_names) sed_mag_norm_out.append(sed_mag_norm) sed_mag_list_out.append(sed_mag_list) av_out_list_out.append(av_out_list) rv_out_list_out.append(rv_out_list) with out_lock: out_dict['sed_names'] += sed_names_out out_dict['sed_mag_norm'] += sed_mag_norm_out out_dict['sed_mag_list'] += sed_mag_list_out out_dict['av_out_list'] += av_out_list_out out_dict['rv_out_list'] += rv_out_list_out
def calcColors(sedname='C.dat'): # Calculate SSO colors. filterdir = os.getenv('LSST_THROUGHPUTS_BASELINE') filterlist = ('u', 'g', 'r', 'i', 'z', 'y') lsst ={} for f in filterlist: lsst[f] = Bandpass() lsst[f].readThroughput(os.path.join(filterdir, 'total_'+f+'.dat')) vband = Bandpass() vband.readThroughput('harris_V.dat') csed = Sed() csed.readSED_flambda(sedname) vmag = csed.calcMag(vband) dmags = {} for f in filterlist: dmags[f] = csed.calcMag(lsst[f]) - vmag return dmags
def test_stars(self): obs = ObservationMetaData(bandpassName=['c_u', 'c_g'], m5=[25.0, 26.0]) db_dtype = np.dtype([('id', np.int), ('raJ2000', np.float), ('decJ2000', np.float), ('sedFilename', str, 100), ('magNorm', np.float), ('galacticAv', np.float)]) inputDir = os.path.join(getPackageDir('sims_catUtils'), 'tests', 'testData') inputFile = os.path.join(inputDir, 'IndicesTestCatalogStars.txt') db = fileDBObject(inputFile, dtype=db_dtype, runtable='test', idColKey='id') cat = CartoonStars(db, obs_metadata=obs) with lsst.utils.tests.getTempFilePath('.txt') as catName: cat.write_catalog(catName) dtype = np.dtype([(name, np.float) for name in cat.column_outputs]) controlData = np.genfromtxt(catName, dtype=dtype, delimiter=',') db_columns = db.query_columns([ 'id', 'raJ2000', 'decJ2000', 'sedFilename', 'magNorm', 'galacticAv' ]) sedDir = os.path.join(getPackageDir('sims_sed_library'), 'starSED', 'kurucz') for ix, line in enumerate(next(db_columns)): spectrum = Sed() spectrum.readSED_flambda(os.path.join(sedDir, line[3])) fnorm = spectrum.calcFluxNorm(line[4], self.normband) spectrum.multiplyFluxNorm(fnorm) a_x, b_x = spectrum.setupCCM_ab() spectrum.addDust(a_x, b_x, A_v=line[5]) umag = spectrum.calcMag(self.uband) self.assertAlmostEqual(umag, controlData['cartoon_u'][ix], 3) gmag = spectrum.calcMag(self.gband) self.assertAlmostEqual(gmag, controlData['cartoon_g'][ix], 3) umagError, gamma = calcMagError_m5(umag, self.uband, obs.m5['c_u'], PhotometricParameters()) gmagError, gamma = calcMagError_m5(gmag, self.gband, obs.m5['c_g'], PhotometricParameters()) self.assertAlmostEqual(umagError, controlData['sigma_cartoon_u'][ix], 3) self.assertAlmostEqual(gmagError, controlData['sigma_cartoon_g'][ix], 3)
def get_mags(self,source, phase ): sed = Sed() print "===========================================" print phase print "===========================================" if phase > -20 and phase < 50 : sourceflux = source.flux(phase=phase, wave=self.rband.wavelen*10.) sed.setSED(wavelen=self.rband.wavelen, flambda=sourceflux/10.) else: sed.setSED(wavelen=self.rband.wavelen, flambda=flambda) #sed.redshiftSED(redshift=_z[i], dimming=True) return [sed.calcMag(bandpass=self.uband), sed.calcMag(bandpass=self.gband), sed.calcMag(bandpass=self.rband), sed.calcMag(bandpass=self.iband), sed.calcMag(bandpass=self.zband)]
def _get_sed_mags_and_cosmology(catalog_name): """ Returns 3 numpy arrays: sed_names, sed_mag_list, sed_mag_norm and a dictionary for cosmology sed_names is 1d str array, with length = number of SED files in the library sed_mag_list is MxN float array, with M = number of SED files in the library, and N = number of top hat filters in the catalog sed_mag_norm is 1d float array, with length = number of SED files in the library cosmology = {'H0': H0, 'Om0': Om0} """ gc = GCRCatalogs.load_catalog(catalog_name, config_overwrite=dict(md5=False)) cosmo = dict(H0=gc.cosmology.H0.value, Om0=gc.cosmology.Om0) bp_params_raw = {'disk': set(), 'bulge': set()} for q in gc.list_all_quantities(): m = _gcr_sed_re.match(q) if m: wav0, width, tag = m.groups() bp_params_raw[tag].add((int(wav0), int(width))) assert bp_params_raw['disk'] == bp_params_raw[ 'bulge'], 'SEDs for disk and bulge do not match' assert bp_params_raw['disk'], 'No SED found' bp_params_sorted = sorted(bp_params_raw['disk'], key=lambda p: p[0]) # SED labels in GCR specify the band pass in angstrom, but CatSim uses nm # Hence the conversion factor 0.1 in the code below wav_min = bp_params_sorted[0][0] * 0.1 wav_max = max((0.1 * (wav0 + width) for wav0, width in bp_params_sorted)) wav_grid = np.arange(wav_min, wav_max, 0.1) bp_name_list = list() bp_list = list() for wav0, width in bp_params_sorted: sb_grid = ((wav_grid >= wav0 * 0.1) & (wav_grid <= (wav0 + width) * 0.1)).astype(float) bp_list.append(Bandpass(wavelen=wav_grid, sb=sb_grid)) bp_name_list.append('%d_%d' % (wav0, width)) bandpass_dict = BandpassDict(bp_list, bp_name_list) sed_names = list() sed_mag_list = list() sed_mag_norm = list() imsim_bp = Bandpass() imsim_bp.imsimBandpass() for sed_file_name in os.listdir(_galaxy_sed_dir): spec = Sed() spec.readSED_flambda(os.path.join(_galaxy_sed_dir, sed_file_name)) sed_names.append(sed_file_name) sed_mag_list.append(tuple(bandpass_dict.magListForSed(spec))) sed_mag_norm.append(spec.calcMag(imsim_bp)) return np.array(sed_names), np.array(sed_mag_list), np.array( sed_mag_norm), cosmo
def calcMagNorm(self, objectMags, sedObj, bandpassDict, mag_error=None, redshift=None, filtRange=None): """ This will find the magNorm value that gives the closest match to the magnitudes of the object using the matched SED. Uses scipy.optimize.leastsq to find the values of fluxNorm that minimizes the function: ((flux_obs - (fluxNorm*flux_model))/flux_error)**2. @param [in] objectMags are the magnitude values for the object with extinction matching that of the SED object. In the normal case using the selectSED routines above it will be dereddened mags. @param [in] sedObj is an Sed class instance that is set with the wavelength and flux of the matched SED @param [in] bandpassDict is a BandpassDict class instance with the Bandpasses set to those for the magnitudes given for the catalog object @param [in] mag_error are provided error values for magnitudes in objectMags. If none provided then this defaults to 1.0. This should be an array of the same length as objectMags. @param [in] redshift is the redshift of the object if the magnitude is observed @param [in] filtRange is a selected range of filters specified by their indices in the bandpassList to match up against. Used when missing data in some magnitude bands. @param [out] bestMagNorm is the magnitude normalization for the given magnitudes and SED """ import scipy.optimize as opt sedTest = Sed() sedTest.setSED(sedObj.wavelen, flambda=sedObj.flambda) if redshift is not None: sedTest.redshiftSED(redshift) imSimBand = Bandpass() imSimBand.imsimBandpass() zp = -2.5 * np.log10(3631) #Note using default AB zeropoint flux_obs = np.power(10, (objectMags + zp) / (-2.5)) sedTest.resampleSED(wavelen_match=bandpassDict.wavelenMatch) sedTest.flambdaTofnu() flux_model = sedTest.manyFluxCalc(bandpassDict.phiArray, bandpassDict.wavelenStep) if filtRange is not None: flux_obs = flux_obs[filtRange] flux_model = flux_model[filtRange] if mag_error is None: flux_error = np.ones(len(flux_obs)) else: flux_error = np.abs(flux_obs * (np.log(10) / (-2.5)) * mag_error) bestFluxNorm = opt.leastsq( lambda x: ((flux_obs - (x * flux_model)) / flux_error), 1.0)[0][0] sedTest.multiplyFluxNorm(bestFluxNorm) bestMagNorm = sedTest.calcMag(imSimBand) return bestMagNorm
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 quasarMag(z, M1450, survey, f): if (z, M1450, survey, f) in magCache: return magCache[(z, M1450, survey, f)] # for files containing $\lambda$ / F$_\lambda$, we use the Sed method # readSED_flambda. For files containing $\lambda$ / F$_\nu$, # we would use the readSED_fnu method instead. # get the path to the SED file for this z sedFilename = config.sedFilenameFormat.format(config.reddening, z) spectrumFilename = os.path.join(config.sedDir, sedFilename) # Read the spectrum. agn = Sed() agn.readSED_flambda(spectrumFilename) # Suppose you had a spectrum, but it didn't have an absolute scale. Or you # wanted to scale it to have a given magnitude in a particular bandpass. # For example, say we wanted to make our 'agn' spectrum have an r band # magnitude of 20, then calculate the magnitudes in all bandpasses. We # just use the calcFluxNorm and multiplyFluxNorm methods. # Scale spectrum and recalculate magnitudes. # given an absolute M1450, the observed magnitude m corresponding # to rest-frame 145nm radiation is # m = M1450+5log(d_L/10pc) - 2.5log(1+z) # so let's calculate m and then normalize our spectrum to that # first we need d_L = (1+z) * comoving distance # comoving distance is D_hubble * int_0^z dz'/sqrt(omegaM(1+z)^3+omegaLambda) def E(zp): return np.sqrt(config.omegaM * (1 + zp)**3 + config.omegaLambda) DC = config.DH * integrate.quad(lambda zp: 1 / E(zp), 0, z)[0] DL = (1 + z) * DC DL = DL * config.m2pc m = M1450 + 5 * np.log10(DL / 10) - 2.5 * np.log10(1 + z) # make a square bandpass at 145nm (in the quasar rest frame) # with a width of 1nm wavelen = np.arange(300, 2000, 0.1) sb = np.zeros(wavelen.shape) id1450 = int(((145 * (1 + z)) - 300) / 0.1) sb[id1450 - 5:id1450 + 5] = 1 band1450 = Bandpass(wavelen=wavelen, sb=sb) # normalize the sed to m at the (rest-frame) 1450A bandpass fluxNorm = agn.calcFluxNorm(m, band1450) agn.multiplyFluxNorm(fluxNorm) # Calculate expected AB magnitudes in the requested lsst band bandpass = f2Throughput(survey, f) mag = agn.calcMag(bandpass) magCache[(z, M1450, survey, f)] = mag return mag
def _parallel_fitting(mag_array, redshift, redshift_true, H0, Om0, wav_min, wav_width, lsst_mag_array, out_dict, tag): pid = os.getpid() (sed_names, mag_norms, av_arr, rv_arr) = sed_from_galacticus_mags(mag_array, redshift, redshift_true, H0, Om0, wav_min, wav_width, lsst_mag_array) tot_bp_dict = BandpassDict.loadTotalBandpassesFromFiles() sed_dir = getPackageDir('sims_sed_library') lsst_fit_fluxes = np.zeros((6, len(sed_names)), dtype=float) t_start = time.time() ccm_w = None restframe_seds = {} imsim_bp = Bandpass() imsim_bp.imsimBandpass() n04_ln10 = -0.4 * np.log(10) for ii in range(len(sed_names)): av_val = av_arr[ii] rv_val = rv_arr[ii] sed_tag = '%s_%.3f_%.3f' % (sed_names[ii], av_val, rv_val) if sed_tag not in restframe_seds: rest_sed = Sed() rest_sed.readSED_flambda(os.path.join(sed_dir, sed_names[ii])) mag = rest_sed.calcMag(imsim_bp) if ccm_w is None or not np.array_equal(rest_sed.wavelen, ccm_w): ccm_w = np.copy(rest_sed.wavelen) ax, bx = rest_sed.setupCCM_ab() rest_sed.addDust(ax, bx, A_v=av_val, R_v=rv_val) restframe_seds[sed_tag] = (rest_sed, mag) for i_bp, bp in enumerate('ugrizy'): m_norm = mag_norms[i_bp][ii] if m_norm > 0.0 and not np.isfinite(m_norm): continue spec = Sed(wavelen=restframe_seds[sed_tag][0].wavelen, flambda=restframe_seds[sed_tag][0].flambda) fnorm = np.exp(n04_ln10 * (m_norm - restframe_seds[sed_tag][1])) try: assert np.isfinite(fnorm) assert fnorm > 0.0 except AssertionError: print('\n\nmagnorm %e\n\n' % (m_norm)) raise spec.multiplyFluxNorm(fnorm) spec.redshiftSED(redshift[ii], dimming=True) ff = spec.calcFlux(tot_bp_dict[bp]) lsst_fit_fluxes[i_bp][ii] = ff out_dict[tag] = (sed_names, mag_norms, av_arr, rv_arr, lsst_fit_fluxes)
def calcMagNorm(self, objectMags, sedObj, bandpassDict, mag_error = None, redshift = None, filtRange = None): """ This will find the magNorm value that gives the closest match to the magnitudes of the object using the matched SED. Uses scipy.optimize.leastsq to find the values of fluxNorm that minimizes the function: ((flux_obs - (fluxNorm*flux_model))/flux_error)**2. @param [in] objectMags are the magnitude values for the object with extinction matching that of the SED object. In the normal case using the selectSED routines above it will be dereddened mags. @param [in] sedObj is an Sed class instance that is set with the wavelength and flux of the matched SED @param [in] bandpassDict is a BandpassDict class instance with the Bandpasses set to those for the magnitudes given for the catalog object @param [in] mag_error are provided error values for magnitudes in objectMags. If none provided then this defaults to 1.0. This should be an array of the same length as objectMags. @param [in] redshift is the redshift of the object if the magnitude is observed @param [in] filtRange is a selected range of filters specified by their indices in the bandpassList to match up against. Used when missing data in some magnitude bands. @param [out] bestMagNorm is the magnitude normalization for the given magnitudes and SED """ import scipy.optimize as opt sedTest = Sed() sedTest.setSED(sedObj.wavelen, flambda = sedObj.flambda) if redshift is not None: sedTest.redshiftSED(redshift) imSimBand = Bandpass() imSimBand.imsimBandpass() zp = -2.5*np.log10(3631) #Note using default AB zeropoint flux_obs = np.power(10,(objectMags + zp)/(-2.5)) sedTest.resampleSED(wavelen_match=bandpassDict.wavelenMatch) sedTest.flambdaTofnu() flux_model = sedTest.manyFluxCalc(bandpassDict.phiArray, bandpassDict.wavelenStep) if filtRange is not None: flux_obs = flux_obs[filtRange] flux_model = flux_model[filtRange] if mag_error is None: flux_error = np.ones(len(flux_obs)) else: flux_error = np.abs(flux_obs*(np.log(10)/(-2.5))*mag_error) bestFluxNorm = opt.leastsq(lambda x: ((flux_obs - (x*flux_model))/flux_error), 1.0)[0][0] sedTest.multiplyFluxNorm(bestFluxNorm) bestMagNorm = sedTest.calcMag(imSimBand) return bestMagNorm
def test_stars(self): obs = ObservationMetaData(bandpassName=['c_u', 'c_g'], m5=[25.0, 26.0]) db_dtype = np.dtype([('id', np.int), ('raJ2000', np.float), ('decJ2000', np.float), ('sedFilename', str, 100), ('magNorm', np.float), ('galacticAv', np.float)]) inputDir = os.path.join(getPackageDir('sims_catUtils'), 'tests', 'testData') inputFile = os.path.join(inputDir, 'IndicesTestCatalogStars.txt') db = fileDBObject(inputFile, dtype=db_dtype, runtable='test', idColKey='id') cat = CartoonStars(db, obs_metadata=obs) with lsst.utils.tests.getTempFilePath('.txt') as catName: cat.write_catalog(catName) dtype = np.dtype([(name, np.float) for name in cat.column_outputs]) controlData = np.genfromtxt(catName, dtype=dtype, delimiter=',') db_columns = db.query_columns(['id', 'raJ2000', 'decJ2000', 'sedFilename', 'magNorm', 'galacticAv']) sedDir = os.path.join(getPackageDir('sims_sed_library'), 'starSED', 'kurucz') for ix, line in enumerate(next(db_columns)): spectrum = Sed() spectrum.readSED_flambda(os.path.join(sedDir, line[3])) fnorm = spectrum.calcFluxNorm(line[4], self.normband) spectrum.multiplyFluxNorm(fnorm) a_x, b_x = spectrum.setupCCM_ab() spectrum.addDust(a_x, b_x, A_v=line[5]) umag = spectrum.calcMag(self.uband) self.assertAlmostEqual(umag, controlData['cartoon_u'][ix], 3) gmag = spectrum.calcMag(self.gband) self.assertAlmostEqual(gmag, controlData['cartoon_g'][ix], 3) umagError, gamma = calcMagError_m5(umag, self.uband, obs.m5['c_u'], PhotometricParameters()) gmagError, gamma = calcMagError_m5(gmag, self.gband, obs.m5['c_g'], PhotometricParameters()) self.assertAlmostEqual(umagError, controlData['sigma_cartoon_u'][ix], 3) self.assertAlmostEqual(gmagError, controlData['sigma_cartoon_g'][ix], 3)
def __init__(self, R_v=3.1, bandpassDict=None, ref_ebv=1.): # Calculate dust extinction values self.Ax1 = {} if bandpassDict is None: bandpassDict = BandpassDict.loadTotalBandpassesFromFiles( ['u', 'g', 'r', 'i', 'z', 'y']) for filtername in bandpassDict: wavelen_min = bandpassDict[filtername].wavelen.min() wavelen_max = bandpassDict[filtername].wavelen.max() testsed = Sed() testsed.setFlatSED(wavelen_min=wavelen_min, wavelen_max=wavelen_max, wavelen_step=1.0) self.ref_ebv = ref_ebv # Calculate non-dust-extincted magnitude flatmag = testsed.calcMag(bandpassDict[filtername]) # Add dust a, b = testsed.setupCCM_ab() testsed.addDust(a, b, ebv=self.ref_ebv, R_v=R_v) # Calculate difference due to dust when EBV=1.0 (m_dust = m_nodust - Ax, Ax > 0) self.Ax1[filtername] = testsed.calcMag( bandpassDict[filtername]) - flatmag
def test_k_correction(self): """ Test that the K correction correctly converts absolute magnitude to observed magnitude. """ bp_dict = BandpassDict.loadTotalBandpassesFromFiles() rng = np.random.RandomState(41321) sed_dir = os.path.join(getPackageDir('sims_sed_library'), 'galaxySED') list_of_sed_files = os.listdir(sed_dir) list_of_sed_files.sort() sed_to_check = rng.choice(list_of_sed_files, size=10) redshift_arr = rng.random_sample(len(sed_to_check)) * 2.0 + 0.1 bp = bp_dict['g'] for sed_name, zz in zip(sed_to_check, redshift_arr): full_name = os.path.join(sed_dir, sed_name) ss = Sed() ss.readSED_flambda(full_name) true_rest_mag = ss.calcMag(bp) ss.redshiftSED(zz, dimming=True) obs_mag = ss.calcMag(bp) k_corr = k_correction(ss, bp, zz) self.assertLess(np.abs(true_rest_mag - obs_mag + k_corr), 0.001)
def _create_sed_library_mags(wav_min, wav_width): """ Calculate the magnitudes of the SEDs in sims_sed_library dir in the tophat filters specified by wav_min, wav_width Parameters ---------- wav_min is a numpy array of the minimum wavelengths of the tophat filters (in nm) wav_width is a numpy array of the widths of the tophat filters (in nm) Returns ------- sed_names is an array containing the names of the SED files sed_mag_list is MxN float array, with M = number of SED files in the library, and N = number of top hat filters in the catalog sed_mag_norm is 1d float array, with length = number of SED files in the library """ wav_max = max((wav0 + width for wav0, width in zip(wav_min, wav_width))) wav_grid = np.arange(wav_min.min(), wav_max, 0.1) bp_name_list = list() bp_list = list() for wav0, width in zip(wav_min, wav_width): sb_grid = ((wav_grid >= wav0) & (wav_grid <= (wav0 + width))).astype(float) bp_list.append(Bandpass(wavelen=wav_grid, sb=sb_grid)) bp_name_list.append('%d_%d' % (wav0, width)) bandpass_dict = BandpassDict(bp_list, bp_name_list) sed_names = list() sed_mag_list = list() sed_mag_norm = list() imsim_bp = Bandpass() imsim_bp.imsimBandpass() for sed_file_name in os.listdir(_galaxy_sed_dir): spec = Sed() spec.readSED_flambda(os.path.join(_galaxy_sed_dir, sed_file_name)) sed_names.append(defaultSpecMap[sed_file_name]) sed_mag_list.append(tuple(bandpass_dict.magListForSed(spec))) sed_mag_norm.append(spec.calcMag(imsim_bp)) return np.array(sed_names), np.array(sed_mag_list), np.array(sed_mag_norm)
def _calcColors(self, sedname='C.dat', sedDir=None): """ Calculate the colors for a moving object with sed 'sedname'. """ # Do we need to read in the LSST bandpasses? try: self.lsst except AttributeError: envvar = 'LSST_THROUGHPUTS_BASELINE' filterdir = os.getenv(envvar) if filterdir is None: raise RuntimeError( 'Cannot find directory for throughput curves. Set env var %s' % (envvar)) self.filterlist = ('u', 'g', 'r', 'i', 'z', 'y') self.lsst = {} for f in self.filterlist: self.lsst[f] = Bandpass() self.lsst[f].readThroughput( os.path.join(filterdir, 'total_' + f + '.dat')) self.seddir = sedDir if self.seddir is None: self.seddir = os.path.join(getPackageDir('SIMS_MOVINGOBJECTS'), 'data') self.vband = Bandpass() self.vband.readThroughput(os.path.join(self.seddir, 'harris_V.dat')) self.colors = {} # See if the sed's colors are in memory already. if sedname not in self.colors: moSed = Sed() moSed.readSED_flambda(os.path.join(self.seddir, sedname)) vmag = moSed.calcMag(self.vband) self.colors[sedname] = {} for f in self.filterlist: self.colors[sedname][f] = moSed.calcMag(self.lsst[f]) - vmag return self.colors[sedname]
def calcColors(self, sedname='C.dat', sedDir=None): """ Calculate the colors for a given SED, store the result. Parameters ---------- sedname : str (opt) Name of the SED. Default 'C.dat'. sedDir : str (opt) Directory containing the SEDs of the moving objects. Default None = $SIMS_MOVINGOBJECTS_DIR/data. """ # See if the sed's colors are in memory already. if sedname not in self.colors: if sedDir is None: sedDir = os.path.join(getPackageDir('SIMS_MOVINGOBJECTS'), 'data') moSed = Sed() moSed.readSED_flambda(os.path.join(sedDir, sedname)) vmag = moSed.calcMag(self.vband) self.colors[sedname] = {} for f in self.filterlist: self.colors[sedname][f] = moSed.calcMag(self.lsst[f]) - vmag return
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 returnMags(self, bandpasses=None): """ Convert the computed spectra to a magnitude using the supplied bandpass, or, if self.mags=True, return the mags in the LSST filters If mags=True when initialized, return mags returns an structured array with dtype names u,g,r,i,z,y. bandpasses: optional dictionary with bandpass name keys and bandpass object values. """ if self.azs is None: raise ValueError( 'No coordinates set. Use setRaDecMjd, setRaDecAltAzMjd, or setParams methods before calling returnMags.' ) if self.mags: if bandpasses: warnings.warn( 'Ignoring set bandpasses and returning LSST ugrizy.') mags = -2.5 * np.log10(self.spec) + np.log10(3631.) # Mask out high airmass mags[self.mask] *= np.nan mags = mags.swapaxes(0, 1) magsBack = {} for i, f in enumerate(self.filterNames): magsBack[f] = mags[i] else: magsBack = {} for key in bandpasses: mags = np.zeros(self.npts, dtype=float) - 666 tempSed = Sed() isThrough = np.where(bandpasses[key].sb > 0) minWave = bandpasses[key].wavelen[isThrough].min() maxWave = bandpasses[key].wavelen[isThrough].max() inBand = np.where((self.wave >= minWave) & (self.wave <= maxWave)) for i, ra in enumerate(self.ra): # Check that there is flux in the band, otherwise calcMag fails if np.max(self.spec[i, inBand]) > 0: tempSed.setSED(self.wave, flambda=self.spec[i, :]) mags[i] = tempSed.calcMag(bandpasses[key]) # Mask out high airmass mags[self.mask] *= np.nan magsBack[key] = mags return magsBack
def test_mags_vs_flux(self): """ Verify that the relationship between Sed.calcMag() and Sed.calcFlux() is as expected """ wavelen = np.arange(100.0, 1500.0, 1.0) flambda = np.exp(-0.5*np.power((wavelen-500.0)/100.0,2)) sb = (wavelen-100.0)/1400.0 ss = Sed(wavelen=wavelen, flambda=flambda) bp = Bandpass(wavelen=wavelen, sb=sb) mag = ss.calcMag(bp) flux = ss.calcFlux(bp) self.assertAlmostEqual(ss.magFromFlux(flux)/mag, 1.0, 10) self.assertAlmostEqual(ss.fluxFromMag(mag)/flux, 1.0, 10)
def test_mags_vs_flux(self): """ Verify that the relationship between Sed.calcMag() and Sed.calcFlux() is as expected """ wavelen = np.arange(100.0, 1500.0, 1.0) flambda = np.exp(-0.5 * np.power((wavelen - 500.0) / 100.0, 2)) sb = (wavelen - 100.0) / 1400.0 ss = Sed(wavelen=wavelen, flambda=flambda) bp = Bandpass(wavelen=wavelen, sb=sb) mag = ss.calcMag(bp) flux = ss.calcFlux(bp) self.assertAlmostEqual(ss.magFromFlux(flux) / mag, 1.0, 10) self.assertAlmostEqual(ss.fluxFromMag(mag) / flux, 1.0, 10)
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 testMagDictForSed(self): """ Test that magDictForSed calculates the correct magnitude """ wavelen = numpy.arange(10.0,2000.0,1.0) flux = (wavelen*2.0-5.0)*1.0e-6 spectrum = Sed(wavelen=wavelen, flambda=flux) for nBp in range(3, 10, 1): nameList, bpList = self.getListOfBandpasses(nBp) testDict = BandpassDict(bpList, nameList) self.assertFalse(len(testDict.values()[0].wavelen)==len(spectrum.wavelen)) magDict = testDict.magDictForSed(spectrum) for ix, (name, bp) in enumerate(zip(nameList, bpList)): magControl = spectrum.calcMag(bp) self.assertAlmostEqual(magDict[name], magControl, 5)
def calcWDColors(): """ Calculate a few example WD colors. Values to go in stellarMags(). Here in case values need to be regenerated (different stars, bandpasses change, etc.) """ try: from lsst.utils import getPackageDir import os from lsst.sims.photUtils import Bandpass, Sed except: 'Need to setup sims_photUtils to generate WD magnitudes.' names = ['HeWD_25200_80', 'WD_11000_85', 'WD_3000_85'] fns = [ 'bergeron_He_24000_80.dat_25200.gz', 'bergeron_10500_85.dat_11000.gz', 'bergeron_2750_85.dat_3000.gz' ] wdDir = os.path.join(getPackageDir('sims_sed_library'), 'starSED/wDs/') files = [os.path.join(wdDir, filename) for filename in fns] # Read in the LSST bandpasses bpNames = ['u', 'g', 'r', 'i', 'z', 'y'] bps = [] throughPath = os.path.join(getPackageDir('throughputs'), 'baseline') for key in bpNames: bp = np.loadtxt(os.path.join(throughPath, 'filter_' + key + '.dat'), dtype=list(zip(['wave', 'trans'], [float] * 2))) tempB = Bandpass() tempB.setBandpass(bp['wave'], bp['trans']) bps.append(tempB) # Read in the SEDs and compute mags mags = [] for filename in files: star = Sed() star.readSED_flambda(filename) singleMags = [star.calcMag(band) for band in bps] mags.append([singleMags[i - 1] - singleMags[i] for i in range(1, 6)]) for maglist, fn, name in zip(mags, fns, names): format = (name, fn) + tuple(maglist) print("['%s', '%s', %f, %f, %f, %f, %f]" % format)
def computeMags(self, bandpass=None): """After the spectra have been computed, optionally convert to mags""" if self.mags: mags = -2.5*np.log10(self.spec)+np.log10(3631.) else: mags = np.zeros(self.npts, dtype=float)-666 tempSed = Sed() isThrough = np.where(bandpass.sb > 0) minWave = bandpass.wavelen[isThrough].min() maxWave = bandpass.wavelen[isThrough].max() inBand = np.where( (self.wave >= minWave) & (self.wave <= maxWave)) for i, ra in enumerate(self.ra): if np.max(self.spec[i,inBand]) > 0: tempSed.setSED(self.wave, flambda=self.spec[i,:]) # Need to try/except because the spectra might be zero in the filter # XXX-upgrade this to check if it's zero mags[i] = tempSed.calcMag(bandpass) return mags
def computeMags(self, bandpass=None): """After the spectra have been computed, optionally convert to mags""" if self.mags: mags = -2.5 * np.log10(self.spec) + np.log10(3631.) else: mags = np.zeros(self.npts, dtype=float) - 666 tempSed = Sed() isThrough = np.where(bandpass.sb > 0) minWave = bandpass.wavelen[isThrough].min() maxWave = bandpass.wavelen[isThrough].max() inBand = np.where((self.wave >= minWave) & (self.wave <= maxWave)) for i, ra in enumerate(self.ra): if np.max(self.spec[i, inBand]) > 0: tempSed.setSED(self.wave, flambda=self.spec[i, :]) # Need to try/except because the spectra might be zero in the filter # XXX-upgrade this to check if it's zero mags[i] = tempSed.calcMag(bandpass) return mags
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 returnMags(self, bandpasses=None): """ Convert the computed spectra to a magnitude using the supplied bandpass, or, if self.mags=True, return the mags in the LSST filters If mags=True when initialized, return mags returns an structured array with dtype names u,g,r,i,z,y. bandpasses: optional dictionary with bandpass name keys and bandpass object values. """ if self.azs is None: raise ValueError('No coordinates set. Use setRaDecMjd, setRaDecAltAzMjd, or setParams methods before calling returnMags.') if self.mags: if bandpasses: warnings.warn('Ignoring set bandpasses and returning LSST ugrizy.') mags = -2.5*np.log10(self.spec)+np.log10(3631.) # Mask out high airmass mags[self.mask] *= np.nan mags = mags.swapaxes(0, 1) magsBack = {} for i, f in enumerate(self.filterNames): magsBack[f] = mags[i] else: magsBack = {} for key in bandpasses: mags = np.zeros(self.npts, dtype=float)-666 tempSed = Sed() isThrough = np.where(bandpasses[key].sb > 0) minWave = bandpasses[key].wavelen[isThrough].min() maxWave = bandpasses[key].wavelen[isThrough].max() inBand = np.where((self.wave >= minWave) & (self.wave <= maxWave)) for i, ra in enumerate(self.ra): # Check that there is flux in the band, otherwise calcMag fails if np.max(self.spec[i, inBand]) > 0: tempSed.setSED(self.wave, flambda=self.spec[i, :]) mags[i] = tempSed.calcMag(bandpasses[key]) # Mask out high airmass mags[self.mask] *= np.nan magsBack[key] = mags return magsBack
def _create_library_one_sed(_galaxy_sed_dir, sed_file_name_list, av_grid, rv_grid, bandpass_dict, out_dict): n_obj = len(av_grid) * len(rv_grid) imsim_bp = Bandpass() imsim_bp.imsimBandpass() t_start = time.time() for i_sed, sed_file_name in enumerate(sed_file_name_list): if i_sed > 0 and i_sed % 10 == 0: duration = (time.time() - t_start) / 3600.0 pred = len(sed_file_name_list) * duration / i_sed print('%d of %d; dur %.2e pred %.2e' % (i_sed, len(sed_file_name_list), duration, pred)) base_spec = Sed() base_spec.readSED_flambda(os.path.join(_galaxy_sed_dir, sed_file_name)) ax, bx = base_spec.setupCCMab() mag_norm = base_spec.calcMag(imsim_bp) sed_names = np.array([defaultSpecMap[sed_file_name]] * n_obj) rv_out_list = np.zeros(n_obj, dtype=float) av_out_list = np.zeros(n_obj, dtype=float) sed_mag_norm = mag_norm * np.ones(n_obj, dtype=float) sed_mag_list = [] i_obj = 0 for av in av_grid: for rv in rv_grid: spec = Sed(wavelen=base_spec.wavelen, flambda=base_spec.flambda) spec.addCCMDust(ax, bx, A_v=av, R_v=rv) av_out_list[i_obj] = av rv_out_list[i_obj] = rv sed_mag_list.append(tuple(bandpass_dict.magListForSed(spec))) i_obj += 1 out_dict[sed_file_name] = (sed_names, sed_mag_norm, sed_mag_list, av_out_list, rv_out_list)
def calcWDColors(): """ Calculate a few example WD colors. Values to go in stellarMags(). Here in case values need to be regenerated (different stars, bandpasses change, etc.) """ try: from lsst.utils import getPackageDir import os from lsst.sims.photUtils import Bandpass, Sed except: 'Need to setup sims_photUtils to generate WD magnitudes.' names = ['HeWD_25200_80', 'WD_11000_85', 'WD_3000_85'] fns = ['bergeron_He_24000_80.dat_25200.gz', 'bergeron_10500_85.dat_11000.gz', 'bergeron_2750_85.dat_3000.gz'] wdDir = os.path.join(getPackageDir('sims_sed_library'), 'starSED/wDs/') files = [os.path.join(wdDir, filename) for filename in fns] # Read in the LSST bandpasses bpNames = ['u', 'g', 'r', 'i', 'z', 'y'] bps = [] throughPath = os.path.join(getPackageDir('throughputs'), 'baseline') for key in bpNames: bp = np.loadtxt(os.path.join(throughPath, 'filter_' + key + '.dat'), dtype=list(zip(['wave', 'trans'], [float] * 2))) tempB = Bandpass() tempB.setBandpass(bp['wave'], bp['trans']) bps.append(tempB) # Read in the SEDs and compute mags mags = [] for filename in files: star = Sed() star.readSED_flambda(filename) singleMags = [star.calcMag(band) for band in bps] mags.append([singleMags[i - 1] - singleMags[i] for i in range(1, 6)]) for maglist, fn, name in zip(mags, fns, names): format = (name, fn) + tuple(maglist) print("['%s', '%s', %f, %f, %f, %f, %f]" % format)
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() 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 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)
def packageMoon(): dataDir = getPackageDir('SIMS_SKYBRIGHTNESS_DATA') outDir = os.path.join(dataDir, 'ESO_Spectra/Moon') # Read in all the spectra from ESO call and package into a single npz file files = glob.glob('Moon/skytable*.fits') temp = pyfits.open(files[0]) moonWave = temp[1].data['lam'].copy()*1e3 moonSpec = [] moonAM = [] # Actually target airmass moonAlt=[] # altitude of the moon moonSunSep=[] # moon Phase moonTargetSep=[] hpid=[] for i,filename in enumerate(files): fits = pyfits.open(filename) try: if np.max(fits[1].data['flux']) > 0: moonSpec.append(fits[1].data['flux'].copy()) header = fits[0].header['comment'] for card in header: if 'SKYMODEL.MOON.SUN.SEP' in card: moonSunSep.append(float(card.split('=')[-1])) elif 'SKYMODEL.TARGET.AIRMASS' in card: #moonAM.append( 1./np.cos(np.radians(90.-float(card.split('=')[-1]))) ) moonAM.append( float(card.split('=')[-1]) ) elif 'SKYMODEL.MOON.TARGET.SEP' in card: moonTargetSep.append(float(card.split('=')[-1])) elif 'SKYMODEL.MOON.ALT' in card: moonAlt.append(float(card.split('=')[-1])) except: print filename, ' Failed' import healpy as hp from lsst.sims.utils import haversine nside = 4 lat, az = hp.pix2ang(nside, np.arange(hp.nside2npix(nside))) alt = np.pi/2.-lat airmass = 1./np.cos(np.pi/2.-alt) # Only need low airmass and then 1/2 to sky good = np.where( (az >= 0) & (az <= np.pi) & (airmass <=2.6) & (airmass >= 1.) ) airmass = airmass[good] alt=alt[good] az = az[good] moonAM = np.array(moonAM) moonAlt = np.array(moonAlt) moonSunSep = np.array(moonSunSep) moonTargetSep = np.array(moonTargetSep) moonAzDiff = moonTargetSep*0 targetAlt = np.pi/2.-np.arccos(1./moonAM) # Compute the azimuth difference given the moon-target-seperation # Let's just do a stupid loop: for i in np.arange(targetAlt.size): possibleDistances = haversine(0., np.radians(moonAlt[i]), az, az*0+targetAlt[i]) diff = np.abs(possibleDistances - np.radians(moonTargetSep[i])) good = np.where(diff == diff.min()) moonAzDiff[i] = az[good][0] # ok, now I have an alt and az, I can convert that back to a healpix id. hpid.append(hp.ang2pix(nside, np.pi/2.-targetAlt[i], moonAzDiff[i])) nrec = moonAM.size nwave = moonWave.size dtype = [('hpid', 'int'), ('moonAltitude', 'float'), ('moonSunSep', 'float'), ('spectra', 'float', (nwave)), ('mags', 'float', (6))] moonSpectra = np.zeros(nrec, dtype=dtype) moonSpectra['hpid'] = hpid moonSpectra['moonAltitude'] = moonAlt moonSpectra['moonSunSep'] = moonSunSep moonSpectra['spectra'] = moonSpec hPlank = 6.626068e-27 # erg s cLight = 2.99792458e10 # cm/s # Convert spectra from ph/s/m2/micron/arcsec2 to erg/s/cm2/nm/arcsec2 moonSpectra['spectra'] = moonSpectra['spectra']/(100.**2)*hPlank*cLight/(moonWave*1e-7)/1e3 # Sort things since this might be helpful later moonSpectra.sort(order=['moonSunSep','moonAltitude', 'hpid']) # Crop off the incomplete ones good =np.where((moonSpectra['moonAltitude'] >= 0) & (moonSpectra['moonAltitude'] < 89.) ) moonSpectra = moonSpectra[good] # Load LSST filters throughPath = os.path.join(getPackageDir('throughputs'),'baseline') keys = ['u','g','r','i','z','y'] nfilt = len(keys) filters = {} for filtername in keys: bp = np.loadtxt(os.path.join(throughPath, 'filter_'+filtername+'.dat'), dtype=zip(['wave','trans'],[float]*2 )) tempB = Bandpass() tempB.setBandpass(bp['wave'],bp['trans']) filters[filtername] = tempB filterWave = np.array([filters[f].calcEffWavelen()[0] for f in keys ]) for i,spectrum in enumerate(moonSpectra['spectra']): tempSed = Sed() tempSed.setSED(moonWave,flambda=spectrum) for j,filtName in enumerate(keys): try: moonSpectra['mags'][i][j] = tempSed.calcMag(filters[filtName]) except: pass nbreak=5 nrec = np.size(moonSpectra) for i in np.arange(nbreak): np.savez(os.path.join(outDir,'moonSpectra_'+str(i)+'.npz'), wave = moonWave, spec=moonSpectra[i*nrec/nbreak:(i+1)*nrec/nbreak], filterWave=filterWave)
class TestSNRmethods(unittest.TestCase): def setUp(self): starFileName = os.path.join(lsst.utils.getPackageDir("sims_sed_library"), "starSED") starFileName = os.path.join(starFileName, "kurucz", "km20_5750.fits_g40_5790.gz") starName = os.path.join(lsst.utils.getPackageDir("sims_sed_library"), starFileName) self.starSED = Sed() self.starSED.readSED_flambda(starName) imsimband = Bandpass() imsimband.imsimBandpass() fNorm = self.starSED.calcFluxNorm(22.0, imsimband) self.starSED.multiplyFluxNorm(fNorm) hardwareDir = os.path.join(lsst.utils.getPackageDir("throughputs"), "baseline") componentList = ["detector.dat", "m1.dat", "m2.dat", "m3.dat", "lens1.dat", "lens2.dat", "lens3.dat"] self.skySed = Sed() self.skySed.readSED_flambda(os.path.join(hardwareDir, "darksky.dat")) totalNameList = ["total_u.dat", "total_g.dat", "total_r.dat", "total_i.dat", "total_z.dat", "total_y.dat"] self.bpList = [] self.hardwareList = [] for name in totalNameList: dummy = Bandpass() dummy.readThroughput(os.path.join(hardwareDir, name)) self.bpList.append(dummy) dummy = Bandpass() hardwareNameList = [os.path.join(hardwareDir, name)] for component in componentList: hardwareNameList.append(os.path.join(hardwareDir, component)) dummy.readThroughputList(hardwareNameList) self.hardwareList.append(dummy) self.filterNameList = ["u", "g", "r", "i", "z", "y"] 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 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 testSNRexceptions(self): """ test that calcSNR_m5 raises an exception when arguments are not of the right shape. """ photParams = PhotometricParameters() shortGamma = numpy.array([1.0, 1.0]) shortMagnitudes = numpy.array([22.0, 23.0]) magnitudes = 22.0 * numpy.ones(6) self.assertRaises(RuntimeError, snr.calcSNR_m5, magnitudes, self.bpList, shortMagnitudes, photParams) self.assertRaises(RuntimeError, snr.calcSNR_m5, shortMagnitudes, self.bpList, magnitudes, photParams) self.assertRaises( RuntimeError, snr.calcSNR_m5, magnitudes, self.bpList, magnitudes, photParams, gamma=shortGamma ) signalToNoise, gg = snr.calcSNR_m5(magnitudes, self.bpList, magnitudes, photParams) 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 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) 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 = numpy.sqrt(numpy.power(snr.magErrorFromSNR(testSNR), 2) + numpy.power(sigmaSys, 2)) msg = "%e is not %e; failed" % (sigmaList[i], control) self.assertAlmostEqual(sigmaList[i], control, 10, msg=msg) 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)
class TestSNRmethods(unittest.TestCase): def setUp(self): starName = os.path.join(lsst.utils.getPackageDir('sims_photUtils'), 'tests/cartoonSedTestData/starSed/') starName = os.path.join(starName, 'kurucz', 'km20_5750.fits_g40_5790.gz') self.starSED = Sed() self.starSED.readSED_flambda(starName) imsimband = Bandpass() imsimband.imsimBandpass() fNorm = self.starSED.calcFluxNorm(22.0, imsimband) self.starSED.multiplyFluxNorm(fNorm) hardwareDir = os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline') componentList = [ 'detector.dat', 'm1.dat', 'm2.dat', 'm3.dat', 'lens1.dat', 'lens2.dat', 'lens3.dat' ] self.skySed = Sed() self.skySed.readSED_flambda(os.path.join(hardwareDir, 'darksky.dat')) totalNameList = [ 'total_u.dat', 'total_g.dat', 'total_r.dat', 'total_i.dat', 'total_z.dat', 'total_y.dat' ] self.bpList = [] self.hardwareList = [] for name in totalNameList: dummy = Bandpass() dummy.readThroughput(os.path.join(hardwareDir, name)) self.bpList.append(dummy) dummy = Bandpass() hardwareNameList = [os.path.join(hardwareDir, name)] for component in componentList: hardwareNameList.append(os.path.join(hardwareDir, component)) dummy.readThroughputList(hardwareNameList) self.hardwareList.append(dummy) self.filterNameList = ['u', 'g', 'r', 'i', 'z', 'y'] 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 testVerboseSNR(self): """ Make sure that calcSNR_sed has everything it needs to run in verbose mode """ 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, FWHMeff=0.7, verbose=True) 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 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 testNoSystematicUncertainty(self): """ Test that systematic uncertainty is handled correctly when set to None. """ m5_list = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7] photParams = PhotometricParameters(sigmaSys=0.0) 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 = snr.magErrorFromSNR(testSNR) msg = '%e is not %e; failed' % (sigma, control) self.assertAlmostEqual(sigma, control, 10, msg=msg) def testFWHMconversions(self): FWHMeff = 0.8 FWHMgeom = snr.FWHMeff2FWHMgeom(FWHMeff) self.assertEqual(FWHMgeom, (0.822 * FWHMeff + 0.052)) FWHMgeom = 0.8 FWHMeff = snr.FWHMgeom2FWHMeff(FWHMgeom) self.assertEqual(FWHMeff, (FWHMgeom - 0.052) / 0.822) def testSNR_arr(self): """ Test that calcSNR_m5 works on numpy arrays of magnitudes """ rng = np.random.RandomState(17) mag_list = rng.random_sample(100) * 5.0 + 15.0 photParams = PhotometricParameters() bp = self.bpList[0] m5 = 24.0 control_list = [] for mm in mag_list: ratio, gamma = snr.calcSNR_m5(mm, bp, m5, photParams) control_list.append(ratio) control_list = np.array(control_list) test_list, gamma = snr.calcSNR_m5(mag_list, bp, m5, photParams) np.testing.assert_array_equal(control_list, test_list) def testError_arr(self): """ Test that calcMagError_m5 works on numpy arrays of magnitudes """ rng = np.random.RandomState(17) mag_list = rng.random_sample(100) * 5.0 + 15.0 photParams = PhotometricParameters() bp = self.bpList[0] m5 = 24.0 control_list = [] for mm in mag_list: sig, gamma = snr.calcMagError_m5(mm, bp, m5, photParams) control_list.append(sig) control_list = np.array(control_list) test_list, gamma = snr.calcMagError_m5(mag_list, bp, m5, photParams) np.testing.assert_array_equal(control_list, test_list)
# create the a,b arrays for all the gals (because we resampled the gals onto the # same wavelength range we can just calculate a/b once, and this is slow) a_gal, b_gal = gals[galaxykeys[0]].setupCCMab() # pretend we want to read mags into an array .. you could just as easily put it into a # dictionary or list, with small variations in the code mags = n.empty(len(galaxykeys), dtype='float') for i in range(len(galaxykeys)): # make a copy of the original SED if you want to 'reuse' the SED for multiple magnitude # calculations with various fluxnorms, redshifts and dusts tmpgal = Sed(wavelen=gals[galaxykeys[i]].wavelen, flambda=gals[galaxykeys[i]].flambda) # add the dust internal to the distant galaxy tmpgal.addCCMDust(a_gal, b_gal, ebv=ebv_gal[i]) # redshift the galaxy tmpgal.redshiftSED(redshifts[i], dimming=False) # add the dust from our milky way - have to recalculate a/b because now wavelenghts # for each galaxy are *different* a_mw, b_mw = tmpgal.setupCCMab() tmpgal.addCCMDust(a_mw, b_mw, ebv=ebv_mw[i]) tmpgal.multiplyFluxNorm(fluxnorm[i]) mags[i] = tmpgal.calcMag(rband) # show results print "#sedname fluxnorm redshift ebv_gal ebv_mw magnitude " for i in range(len(galaxykeys)): print "%s %.5g %.3f %.5f %.5f %.5f" %(galaxykeys[i], fluxnorm[i], redshifts[i], ebv_gal[i], ebv_mw[i], mags[i])
if wavelen[0]>9.0: coeffs = numpy.polyfit(numpy.log10(wavelen[:100]), numpy.log10(flux[:100]), deg=1) redWavelen = numpy.arange(9.0, wavelen[0]-0.5, 0.4*(wavelen[0]-0.5-9.0)) redFlux = numpy.ones(len(redWavelen))*10e-5 wavelen = numpy.append(redWavelen, wavelen) flux = numpy.append(redFlux, flux) with gzip.open(outName,'wb') as spectralFile: for w,f in zip(wavelen, flux): spectralFile.write('%e %e\n' % (w,f)) dummySed = Sed(wavelen=wavelen, flambda=flux) sdssMags = sdssPhotometry.manyMagCalc_list(dummySed) dummySed = Sed(wavelen=wavelen, flambda=flux) magNorm = dummySed.calcMag(controlBandpass) output.write('%s is %s -- norm %e -- %e %e %e %e %e %e\n' % (name, _fitNames[dex], norm, sdssMags[0], sdssMags[1], sdssMags[2], sdssMags[3], sdssMags[4], magNorm)) if 'BD1000' in outName: outName = outName.replace('BD1000','BD1000e') for wavelenStr in linesDict: dex = numpy.argmin(numpy.abs(wavelen-0.1*numpy.float(wavelenStr))) flux[dex] = linesDict[wavelenStr] with gzip.open(outName,'wb') as spectralFile: for w, f in zip(wavelen, flux): spectralFile.write('%e %e\n' % (w,f))
class TwilightInterp(object): def __init__(self, mags=False, darkSkyMags=None, fitResults=None): """ Read the Solar spectrum into a handy object and compute mags in different filters mags: If true, only return the LSST filter magnitudes, otherwise return the full spectrum darkSkyMags = dict of the zenith dark sky values to be assumed. The twilight fits are done relative to the dark sky level. fitResults = dict of twilight parameters based on twilightFunc. Keys should be filter names. """ if darkSkyMags is None: darkSkyMags = {'u': 22.8, 'g': 22.3, 'r': 21.2, 'i': 20.3, 'z': 19.3, 'y': 18.0, 'B': 22.35, 'G': 21.71, 'R': 21.3} self.mags = mags dataDir = getPackageDir('sims_skybrightness_data') solarSaved = np.load(os.path.join(dataDir, 'solarSpec/solarSpec.npz')) self.solarSpec = Sed(wavelen=solarSaved['wave'], flambda=solarSaved['spec']) solarSaved.close() canonFilters = {} fnames = ['blue_canon.csv', 'green_canon.csv', 'red_canon.csv'] # Filter names, from bluest to reddest. self.filterNames = ['B', 'G', 'R'] for fname, filterName in zip(fnames, self.filterNames): bpdata = np.genfromtxt(os.path.join(dataDir, 'Canon/', fname), delimiter=', ', dtype=list(zip(['wave', 'through'], [float]*2))) bpTemp = Bandpass() bpTemp.setBandpass(bpdata['wave'], bpdata['through']) canonFilters[filterName] = bpTemp # Tack on the LSST filters throughPath = os.path.join(getPackageDir('throughputs'), 'baseline') lsstKeys = ['u', 'g', 'r', 'i', 'z', 'y'] for key in lsstKeys: bp = np.loadtxt(os.path.join(throughPath, 'filter_'+key+'.dat'), dtype=list(zip(['wave', 'trans'], [float]*2))) tempB = Bandpass() tempB.setBandpass(bp['wave'], bp['trans']) canonFilters[key] = tempB self.filterNames.append(key) # MAGIC NUMBERS from fitting the all-sky camera: # Code to generate values in sims_skybrightness/examples/fitTwiSlopesSimul.py # Which in turn uses twilight maps from sims_skybrightness/examples/buildTwilMaps.py # values are of the form: # 0: ratio of f^z_12 to f_dark^z # 1: slope of curve wrt sun alt # 2: airmass term (10^(arg[2]*(X-1))) # 3: azimuth term. # 4: zenith dark sky flux (erg/s/cm^2) # For z and y, just assuming the shape parameter fits are similar to the other bands. # Looks like the diode is not sensitive enough to detect faint sky. # Using the Patat et al 2006 I-band values for z and modeified a little for y as a temp fix. if fitResults is None: self.fitResults = {'B': [7.56765633e+00, 2.29798055e+01, 2.86879956e-01, 3.01162143e-01, 2.58462036e-04], 'G': [2.38561156e+00, 2.29310648e+01, 2.97733083e-01, 3.16403197e-01, 7.29660095e-04], 'R': [1.75498017e+00, 2.22011802e+01, 2.98619033e-01, 3.28880254e-01, 3.24411056e-04], 'z': [2.29, 24.08, 0.3, 0.3, -666], 'y': [2.0, 24.08, 0.3, 0.3, -666]} # XXX-completely arbitrary fudge factor to make things brighter in the blue # Just copy the blue and say it's brighter. self.fitResults['u'] = [16., 2.29622121e+01, 2.85862729e-01, 2.99902574e-01, 2.32325117e-04] else: self.fitResults = fitResults # Take out any filters that don't have fit results self.filterNames = [key for key in self.filterNames if key in self.fitResults] self.effWave = [] self.solarMag = [] for filterName in self.filterNames: self.effWave.append(canonFilters[filterName].calcEffWavelen()[0]) self.solarMag.append(self.solarSpec.calcMag(canonFilters[filterName])) ord = np.argsort(self.effWave) self.filterNames = np.array(self.filterNames)[ord] self.effWave = np.array(self.effWave)[ord] self.solarMag = np.array(self.solarMag)[ord] # update the fit results to be zeropointed properly for key in self.fitResults: f0 = 10.**(-0.4*(darkSkyMags[key]-np.log10(3631.))) self.fitResults[key][-1] = f0 self.solarWave = self.solarSpec.wavelen self.solarFlux = self.solarSpec.flambda # This one isn't as bad as the model grids, maybe we could get away with computing the magnitudes # in the __call__ each time. if mags: # Load up the LSST filters and convert the solarSpec.flabda and solarSpec.wavelen to fluxes throughPath = os.path.join(getPackageDir('throughputs'), 'baseline') self.lsstFilterNames = ['u', 'g', 'r', 'i', 'z', 'y'] self.lsstEquations = np.zeros((np.size(self.lsstFilterNames), np.size(self.fitResults['B'])), dtype=float) self.lsstEffWave = [] fits = np.empty((np.size(self.effWave), np.size(self.fitResults['B'])), dtype=float) for i, fn in enumerate(self.filterNames): fits[i, :] = self.fitResults[fn] for filtername in self.lsstFilterNames: bp = np.loadtxt(os.path.join(throughPath, 'filter_'+filtername+'.dat'), dtype=list(zip(['wave', 'trans'], [float]*2))) tempB = Bandpass() tempB.setBandpass(bp['wave'], bp['trans']) self.lsstEffWave.append(tempB.calcEffWavelen()[0]) # Loop through the parameters and interpolate to new eff wavelengths for i in np.arange(self.lsstEquations[0, :].size): interp = InterpolatedUnivariateSpline(self.effWave, fits[:, i]) self.lsstEquations[:, i] = interp(self.lsstEffWave) # Set the dark sky flux for i, filterName in enumerate(self.lsstFilterNames): self.lsstEquations[i, -1] = 10.**(-0.4*(darkSkyMags[filterName]-np.log10(3631.))) self.filterNameDict = {'u': 0, 'g': 1, 'r': 2, 'i': 3, 'z': 4, 'y': 5} def printFitsUsed(self): """ Print out the fit parameters being used """ print('\\tablehead{\colhead{Filter} & \colhead{$r_{12/z}$} & \colhead{$a$ (1/radians)} & \colhead{$b$ (1/airmass)} & \colhead{$c$ (az term/airmass)} & \colhead{$f_z_dark$ (erg/s/cm$^2$)$\\times 10^8$} & \colhead{m$_z_dark$}}') for key in self.fitResults: numbers = '' for num in self.fitResults[key]: if num > .001: numbers += ' & %.2f' % num else: numbers += ' & %.2f' % (num*1e8) print(key, numbers, ' & ', '%.2f' % (-2.5*np.log10(self.fitResults[key][-1])+np.log10(3631.))) def __call__(self, intepPoints, filterNames=['u', 'g', 'r', 'i', 'z', 'y']): if self.mags: return self.interpMag(intepPoints, filterNames=filterNames) else: return self.interpSpec(intepPoints) def interpMag(self, interpPoints, maxAM=2.5, limits=[np.radians(-5.), np.radians(-20.)], filterNames=['u', 'g', 'r', 'i', 'z', 'y']): """ Originally fit the twilight with a cutoff of sun altitude of -11 degrees. I think it can be safely extrapolated farther, but be warned you may be entering a regime where it breaks down. """ npts = len(filterNames) result = np.zeros((np.size(interpPoints), npts), dtype=float) good = np.where((interpPoints['sunAlt'] >= np.min(limits)) & (interpPoints['sunAlt'] <= np.max(limits)) & (interpPoints['airmass'] <= maxAM) & (interpPoints['airmass'] >= 1.))[0] for i, filterName in enumerate(filterNames): result[good, i] = twilightFunc(interpPoints[good], *self.lsstEquations[self.filterNameDict[filterName], :].tolist()) return {'spec': result, 'wave': self.lsstEffWave} def interpSpec(self, interpPoints, maxAM=2.5, limits=[np.radians(-5.), np.radians(-20.)]): """ interpPoints should have airmass, azRelSun, and sunAlt. """ npts = np.size(self.solarWave) result = np.zeros((np.size(interpPoints), npts), dtype=float) good = np.where((interpPoints['sunAlt'] >= np.min(limits)) & (interpPoints['sunAlt'] <= np.max(limits)) & (interpPoints['airmass'] <= maxAM) & (interpPoints['airmass'] >= 1.))[0] # Compute the expected flux in each of the filters that we have fits for fluxes = [] for filterName in self.filterNames: fluxes.append(twilightFunc(interpPoints[good], *self.fitResults[filterName])) fluxes = np.array(fluxes) # ratio of model flux to raw solar flux: yvals = fluxes.T/(10.**(-0.4*(self.solarMag-np.log10(3631.)))) # Find wavelengths bluer than cutoff blueRegion = np.where(self.solarWave < np.min(self.effWave)) for i, yval in enumerate(yvals): interpF = interp1d(self.effWave, yval, bounds_error=False, fill_value=yval[-1]) ratio = interpF(self.solarWave) interpBlue = InterpolatedUnivariateSpline(self.effWave, yval, k=1) ratio[blueRegion] = interpBlue(self.solarWave[blueRegion]) result[good[i]] = self.solarFlux*ratio return {'spec': result, 'wave': self.solarWave}
filters = {} for filtername in keys: bp = np.loadtxt(os.path.join(throughPath, 'filter_'+filtername+'.dat'), dtype=list(zip(['wave', 'trans'], [float]*2))) tempB = Bandpass() tempB.setBandpass(bp['wave'], bp['trans']) filters[filtername] = tempB filterWave = np.array([filters[f].calcEffWavelen()[0] for f in keys]) for i, spectrum in enumerate(moonSpectra['spectra']): tempSed = Sed() tempSed.setSED(moonWave, flambda=spectrum) for j, filtName in enumerate(keys): try: moonSpectra['mags'][i][j] = tempSed.calcMag(filters[filtName]) except: pass nbreak = 5 nrec = np.size(moonSpectra) for i in np.arange(nbreak): np.savez(os.path.join(outDir, 'moonSpectra_'+str(i)+'.npz'), wave=moonWave, spec=moonSpectra[i*nrec/nbreak:(i+1)*nrec/nbreak], filterWave=filterWave) # Skip this stuff, fixed it later all_lat, all_az = hp.pix2ang(nside, np.arange(hp.nside2npix(nside)))
# calculate colors temperatures = numpy.arange(3000, 30000, 1000, dtype='float') for temperature in temperatures: # blackbody: B_lambda dl = (2*h*c^2)/(wavelen^5)*(e^(h*c/(wavelen*k*T))-1)^-1 dl # blackbody: B_nu dnu = (2*h/c^2)*nu^3 * (e^(h*nu/k*T)-1)^-1 dnu # Set up SED object with blackbody spectrum. fnu = ((2.0*PLANCK/LIGHTSPEED**2)*(nu**3) / (numpy.e**(PLANCK*nu/BOLTZMAN/temperature)-1)) blackbody = Sed(wavelen, fnu=fnu) # wien's law: wavelen_max(m) = 0.0029/T #max = 0.0029/temperature/NM2M writestring = "%d " %(temperature) # Calculate magnitudes. sdssmag = {} for f in sdssflist: sdssmag[f] = blackbody.calcMag(sdss[f]) lsstmag = {} for f in lsstflist: lsstmag[f] = blackbody.calcMag(lsst[f]) # Calculate colors. for i in range(len(sdssflist)-1): col = sdssmag[sdssflist[i]] - sdssmag[sdssflist[i+1]] writestring = writestring + "%.3f " %(col) for i in range(len(lsstflist)-1): col = lsstmag[lsstflist[i]] - lsstmag[lsstflist[i+1]] writestring = writestring + "%.3f " %(col) print writestring
class TwilightInterp(object): def __init__(self, mags=False, darkSkyMags=None, fitResults=None): """ Read the Solar spectrum into a handy object and compute mags in different filters mags: If true, only return the LSST filter magnitudes, otherwise return the full spectrum darkSkyMags = dict of the zenith dark sky values to be assumed. The twilight fits are done relative to the dark sky level. fitResults = dict of twilight parameters based on twilightFunc. Keys should be filter names. """ if darkSkyMags is None: darkSkyMags = { 'u': 22.8, 'g': 22.3, 'r': 21.2, 'i': 20.3, 'z': 19.3, 'y': 18.0, 'B': 22.35, 'G': 21.71, 'R': 21.3 } self.mags = mags dataDir = getPackageDir('sims_skybrightness_data') solarSaved = np.load(os.path.join(dataDir, 'solarSpec/solarSpec.npz')) self.solarSpec = Sed(wavelen=solarSaved['wave'], flambda=solarSaved['spec']) solarSaved.close() canonFilters = {} fnames = ['blue_canon.csv', 'green_canon.csv', 'red_canon.csv'] # Filter names, from bluest to reddest. self.filterNames = ['B', 'G', 'R'] for fname, filterName in zip(fnames, self.filterNames): bpdata = np.genfromtxt(os.path.join(dataDir, 'Canon/', fname), delimiter=', ', dtype=list( zip(['wave', 'through'], [float] * 2))) bpTemp = Bandpass() bpTemp.setBandpass(bpdata['wave'], bpdata['through']) canonFilters[filterName] = bpTemp # Tack on the LSST filters throughPath = os.path.join(getPackageDir('throughputs'), 'baseline') lsstKeys = ['u', 'g', 'r', 'i', 'z', 'y'] for key in lsstKeys: bp = np.loadtxt(os.path.join(throughPath, 'filter_' + key + '.dat'), dtype=list(zip(['wave', 'trans'], [float] * 2))) tempB = Bandpass() tempB.setBandpass(bp['wave'], bp['trans']) canonFilters[key] = tempB self.filterNames.append(key) # MAGIC NUMBERS from fitting the all-sky camera: # Code to generate values in sims_skybrightness/examples/fitTwiSlopesSimul.py # Which in turn uses twilight maps from sims_skybrightness/examples/buildTwilMaps.py # values are of the form: # 0: ratio of f^z_12 to f_dark^z # 1: slope of curve wrt sun alt # 2: airmass term (10^(arg[2]*(X-1))) # 3: azimuth term. # 4: zenith dark sky flux (erg/s/cm^2) # For z and y, just assuming the shape parameter fits are similar to the other bands. # Looks like the diode is not sensitive enough to detect faint sky. # Using the Patat et al 2006 I-band values for z and modeified a little for y as a temp fix. if fitResults is None: self.fitResults = { 'B': [ 7.56765633e+00, 2.29798055e+01, 2.86879956e-01, 3.01162143e-01, 2.58462036e-04 ], 'G': [ 2.38561156e+00, 2.29310648e+01, 2.97733083e-01, 3.16403197e-01, 7.29660095e-04 ], 'R': [ 1.75498017e+00, 2.22011802e+01, 2.98619033e-01, 3.28880254e-01, 3.24411056e-04 ], 'z': [2.29, 24.08, 0.3, 0.3, -666], 'y': [2.0, 24.08, 0.3, 0.3, -666] } # XXX-completely arbitrary fudge factor to make things brighter in the blue # Just copy the blue and say it's brighter. self.fitResults['u'] = [ 16., 2.29622121e+01, 2.85862729e-01, 2.99902574e-01, 2.32325117e-04 ] else: self.fitResults = fitResults # Take out any filters that don't have fit results self.filterNames = [ key for key in self.filterNames if key in self.fitResults ] self.effWave = [] self.solarMag = [] for filterName in self.filterNames: self.effWave.append(canonFilters[filterName].calcEffWavelen()[0]) self.solarMag.append( self.solarSpec.calcMag(canonFilters[filterName])) ord = np.argsort(self.effWave) self.filterNames = np.array(self.filterNames)[ord] self.effWave = np.array(self.effWave)[ord] self.solarMag = np.array(self.solarMag)[ord] # update the fit results to be zeropointed properly for key in self.fitResults: f0 = 10.**(-0.4 * (darkSkyMags[key] - np.log10(3631.))) self.fitResults[key][-1] = f0 self.solarWave = self.solarSpec.wavelen self.solarFlux = self.solarSpec.flambda # This one isn't as bad as the model grids, maybe we could get away with computing the magnitudes # in the __call__ each time. if mags: # Load up the LSST filters and convert the solarSpec.flabda and solarSpec.wavelen to fluxes throughPath = os.path.join(getPackageDir('throughputs'), 'baseline') self.lsstFilterNames = ['u', 'g', 'r', 'i', 'z', 'y'] self.lsstEquations = np.zeros( (np.size(self.lsstFilterNames), np.size(self.fitResults['B'])), dtype=float) self.lsstEffWave = [] fits = np.empty( (np.size(self.effWave), np.size(self.fitResults['B'])), dtype=float) for i, fn in enumerate(self.filterNames): fits[i, :] = self.fitResults[fn] for filtername in self.lsstFilterNames: bp = np.loadtxt(os.path.join(throughPath, 'filter_' + filtername + '.dat'), dtype=list(zip(['wave', 'trans'], [float] * 2))) tempB = Bandpass() tempB.setBandpass(bp['wave'], bp['trans']) self.lsstEffWave.append(tempB.calcEffWavelen()[0]) # Loop through the parameters and interpolate to new eff wavelengths for i in np.arange(self.lsstEquations[0, :].size): interp = InterpolatedUnivariateSpline(self.effWave, fits[:, i]) self.lsstEquations[:, i] = interp(self.lsstEffWave) # Set the dark sky flux for i, filterName in enumerate(self.lsstFilterNames): self.lsstEquations[i, -1] = 10.**( -0.4 * (darkSkyMags[filterName] - np.log10(3631.))) self.filterNameDict = {'u': 0, 'g': 1, 'r': 2, 'i': 3, 'z': 4, 'y': 5} def printFitsUsed(self): """ Print out the fit parameters being used """ print( '\\tablehead{\colhead{Filter} & \colhead{$r_{12/z}$} & \colhead{$a$ (1/radians)} & \colhead{$b$ (1/airmass)} & \colhead{$c$ (az term/airmass)} & \colhead{$f_z_dark$ (erg/s/cm$^2$)$\\times 10^8$} & \colhead{m$_z_dark$}}' ) for key in self.fitResults: numbers = '' for num in self.fitResults[key]: if num > .001: numbers += ' & %.2f' % num else: numbers += ' & %.2f' % (num * 1e8) print( key, numbers, ' & ', '%.2f' % (-2.5 * np.log10(self.fitResults[key][-1]) + np.log10(3631.))) def __call__(self, intepPoints, filterNames=['u', 'g', 'r', 'i', 'z', 'y']): if self.mags: return self.interpMag(intepPoints, filterNames=filterNames) else: return self.interpSpec(intepPoints) def interpMag(self, interpPoints, maxAM=2.5, limits=[np.radians(-5.), np.radians(-20.)], filterNames=['u', 'g', 'r', 'i', 'z', 'y']): """ Originally fit the twilight with a cutoff of sun altitude of -11 degrees. I think it can be safely extrapolated farther, but be warned you may be entering a regime where it breaks down. """ npts = len(filterNames) result = np.zeros((np.size(interpPoints), npts), dtype=float) good = np.where((interpPoints['sunAlt'] >= np.min(limits)) & (interpPoints['sunAlt'] <= np.max(limits)) & (interpPoints['airmass'] <= maxAM) & (interpPoints['airmass'] >= 1.))[0] for i, filterName in enumerate(filterNames): result[good, i] = twilightFunc( interpPoints[good], *self.lsstEquations[ self.filterNameDict[filterName], :].tolist()) return {'spec': result, 'wave': self.lsstEffWave} def interpSpec(self, interpPoints, maxAM=2.5, limits=[np.radians(-5.), np.radians(-20.)]): """ interpPoints should have airmass, azRelSun, and sunAlt. """ npts = np.size(self.solarWave) result = np.zeros((np.size(interpPoints), npts), dtype=float) good = np.where((interpPoints['sunAlt'] >= np.min(limits)) & (interpPoints['sunAlt'] <= np.max(limits)) & (interpPoints['airmass'] <= maxAM) & (interpPoints['airmass'] >= 1.))[0] # Compute the expected flux in each of the filters that we have fits for fluxes = [] for filterName in self.filterNames: fluxes.append( twilightFunc(interpPoints[good], *self.fitResults[filterName])) fluxes = np.array(fluxes) # ratio of model flux to raw solar flux: yvals = fluxes.T / (10.**(-0.4 * (self.solarMag - np.log10(3631.)))) # Find wavelengths bluer than cutoff blueRegion = np.where(self.solarWave < np.min(self.effWave)) for i, yval in enumerate(yvals): interpF = interp1d(self.effWave, yval, bounds_error=False, fill_value=yval[-1]) ratio = interpF(self.solarWave) interpBlue = InterpolatedUnivariateSpline(self.effWave, yval, k=1) ratio[blueRegion] = interpBlue(self.solarWave[blueRegion]) result[good[i]] = self.solarFlux * ratio return {'spec': result, 'wave': self.solarWave}
bpfile = 'exampleBandpass.dat' rband.readThroughput(bpfile) # Instantiate a Sed object to hold the spectral energy distribution information star = Sed() # Read the Sed data file into that object - # (note that exampleSED.dat contains wavelength/F_lambda .. but is possible to also # read in wavelength/F_nu data using readSED_fnu) sedfile = 'exampleSED.dat' star.readSED_flambda(sedfile) print "" print "Read %s into Bandpass and %s into Sed." %(bpfile, sedfile) # Simply calculate the magnitude of this source in the bandpass. mag = star.calcMag(rband) print "" print "Without any scaling of the SED, the magnitude is %.4f" %(mag) # That was probably pretty small, right? Maybe we actually know what # magnitude we expect this source to have in this bandpass, and then want to scale # the SED to that appropriate magnitude (and then calculate the magnitudes once it's # 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.
def packageZodiacal(): dataDir = getPackageDir('SIMS_SKYBRIGHTNESS_DATA') outDir = os.path.join(dataDir, 'ESO_Spectra/Zodiacal') nside = 4 # Read in all the spectra from ESO call and package into a single npz file files = glob.glob('Zodiacal/skytable*.fits') temp = pyfits.open(files[0]) wave = temp[1].data['lam'].copy()*1e3 airmasses = [] eclLon = [] eclLat = [] specs = [] for i,filename in enumerate(files): fits = pyfits.open(filename) if np.max(fits[1].data['flux']) > 0: specs.append(fits[1].data['flux'].copy()) header = fits[0].header['comment'] for card in header: if 'SKYMODEL.TARGET.AIRMASS' in card: airmasses.append(float(card.split('=')[-1])) elif 'SKYMODEL.ECL.LON' in card: eclLon.append(float(card.split('=')[-1])) elif 'SKYMODEL.ECL.LAT' in card: eclLat.append(float(card.split('=')[-1])) airmasses = np.array(airmasses) eclLon = np.array(eclLon) eclLat = np.array(eclLat) wrapA = np.where(eclLon < 0.) eclLon[wrapA] = eclLon[wrapA]+360. uAM = np.unique(airmasses) nAM = uAM.size nwave = wave.size dtype = [('airmass', 'float'), ('hpid', 'int' ), ('spectra', 'float', (nwave)), ('mags', 'float', (6))] npix = hp.nside2npix(nside) Spectra = np.zeros(nAM*npix, dtype=dtype) for i,am in enumerate(uAM): Spectra['airmass'][i*npix:i*npix+npix] = am Spectra['hpid'][i*npix:i*npix+npix] = np.arange(npix) for am, lat, lon, spec in zip(airmasses,eclLat, eclLon, specs): hpid = hp.ang2pix(nside, np.radians(lat+90.), np.radians(lon) ) good = np.where( (Spectra['airmass'] == am) & (Spectra['hpid'] == hpid)) Spectra['spectra'][good] = spec.copy() hPlank = 6.626068e-27 # erg s cLight = 2.99792458e10 # cm/s # Convert spectra from ph/s/m2/micron/arcsec2 to erg/s/cm2/nm/arcsec2 Spectra['spectra'] = Spectra['spectra']/(100.**2)*hPlank*cLight/(wave*1e-7)/1e3 # Sort things since this might be helpful later Spectra.sort(order=['airmass', 'hpid']) # Load LSST filters throughPath = os.path.join(getPackageDir('throughputs'),'baseline') keys = ['u','g','r','i','z','y'] nfilt = len(keys) filters = {} for filtername in keys: bp = np.loadtxt(os.path.join(throughPath, 'filter_'+filtername+'.dat'), dtype=zip(['wave','trans'],[float]*2 )) tempB = Bandpass() tempB.setBandpass(bp['wave'],bp['trans']) filters[filtername] = tempB filterWave = np.array([filters[f].calcEffWavelen()[0] for f in keys ]) for i,spectrum in enumerate(Spectra['spectra']): tempSed = Sed() tempSed.setSED(wave,flambda=spectrum) for j,filtName in enumerate(keys): try: Spectra['mags'][i][j] = tempSed.calcMag(filters[filtName]) except: pass #span this over multiple files to store in github nbreak = 3 nrec = np.size(Spectra) for i in np.arange(nbreak): np.savez(os.path.join(outDir,'zodiacalSpectra_'+str(i)+'.npz'), wave = wave, spec=Spectra[i*nrec/nbreak:(i+1)*nrec/nbreak], filterWave=filterWave)
query += 'galaxy WHERE varParamStr IS NOT NULL ' query += 'AND dec BETWEEN -2.5 AND 2.5 ' query += 'AND (ra<2.5 OR ra>357.5)' dtype = np.dtype([('magnorm', float), ('redshift', float), ('varParamStr', str, 400)]) data_iter = db.get_arbitrary_chunk_iterator(query, dtype=dtype, chunk_size=10000) with open('data/dc1_agn_params.txt', 'w') as out_file: out_file.write('# z m_i M_i tau sfu sfg sfr sfi sfz sfy\n') for chunk in data_iter: DM = cosmo.distanceModulus(redshift=chunk['redshift']) k_corr = np.interp(chunk['redshift'], z_grid, k_grid) for i_row, agn in enumerate(chunk): ss = Sed(wavelen=base_sed.wavelen, flambda=base_sed.flambda) fnorm = getImsimFluxNorm(ss, agn['magnorm']) ss.multiplyFluxNorm(fnorm) ss.redshiftSED(agn['redshift'], dimming=True) mag = ss.calcMag(bp) abs_m_i = mag - DM[i_row] - k_corr[i_row] params = json.loads(agn['varParamStr'])['pars'] out_file.write( '%e %e %e %e %e %e %e %e %e %e\n' % (agn['redshift'], mag, abs_m_i, params['agn_tau'], params['agn_sfu'], params['agn_sfg'], params['agn_sfr'], params['agn_sfi'], params['agn_sfz'], params['agn_sfy']))
def packageLowerAtm(): dataDir = getPackageDir('SIMS_SKYBRIGHTNESS_DATA') outDir = os.path.join(dataDir, 'ESO_Spectra/LowerAtm') # Read in all the spectra from ESO call and package into a single npz file files = glob.glob('LowerAtm/skytable*.fits') temp = pyfits.open(files[0]) wave = temp[1].data['lam'].copy()*1e3 airmasses = [] nightTimes = [] specs = [] for i,filename in enumerate(files): fits = pyfits.open(filename) if np.max(fits[1].data['flux']) > 0: specs.append(fits[1].data['flux'].copy()) header = fits[0].header['comment'] for card in header: if 'SKYMODEL.TARGET.AIRMASS' in card: airmasses.append(float(card.split('=')[-1])) elif 'SKYMODEL.TIME' in card: nightTimes.append(float(card.split('=')[-1])) airmasses = np.array(airmasses) nigtTimes = np.array(nightTimes) nrec = airmasses.size nwave = wave.size dtype = [('airmass', 'float'), ('nightTimes', 'float'), ('spectra', 'float', (nwave)), ('mags', 'float', (6))] Spectra = np.zeros(nrec, dtype=dtype) Spectra['airmass'] = airmasses Spectra['nightTimes'] = nightTimes Spectra['spectra'] = specs hPlank = 6.626068e-27 # erg s cLight = 2.99792458e10 # cm/s # Convert spectra from ph/s/m2/micron/arcsec2 to erg/s/cm2/nm/arcsec2 Spectra['spectra'] = Spectra['spectra']/(100.**2)*hPlank*cLight/(wave*1e-7)/1e3 # Sort things since this might be helpful later Spectra.sort(order=['airmass','nightTimes']) # Load LSST filters throughPath = os.path.join(getPackageDir('throughputs'),'baseline') keys = ['u','g','r','i','z','y'] nfilt = len(keys) filters = {} for filtername in keys: bp = np.loadtxt(os.path.join(throughPath, 'filter_'+filtername+'.dat'), dtype=zip(['wave','trans'],[float]*2 )) tempB = Bandpass() tempB.setBandpass(bp['wave'],bp['trans']) filters[filtername] = tempB filterWave = np.array([filters[f].calcEffWavelen()[0] for f in keys ]) for i,spectrum in enumerate(Spectra['spectra']): tempSed = Sed() tempSed.setSED(wave,flambda=spectrum) for j,filtName in enumerate(keys): try: Spectra['mags'][i][j] = tempSed.calcMag(filters[filtName]) except: pass np.savez(os.path.join(outDir,'Spectra.npz'), wave = wave, spec=Spectra, filterWave=filterWave)
seds.remove('harris_V.dat') print 'Calculating colors for seds: \n', seds writestring = 'Sed ' for f in filterlist: writestring += 'V-%s ' %(f) print writestring fig = plt.figure() for s in seds: sed = Sed() sed.readSED_flambda(s) sname = s.replace('.dat', '') vmag = sed.calcMag(harrisV) colors = {} writestring = '%s ' %(sname) for f in filterlist: mag = sed.calcMag(lsst[f]) colors[f] = vmag - mag writestring += '%.3f ' %(colors[f]) print writestring plotPointColor = np.random.rand(3) plt.plot(colors['g'], colors['r'], linestyle='', marker='o', color=plotPointColor, label='%s' %(sname)) pylab.annotate(sname, colors['g']+0.005, colors['r']+0.005, color=plotPointColor) plt.xlabel('V-g') plt.ylabel('V-r') #plt.legend(fancybox=True, numpoints=1, fontsize='smaller') plt.show()
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
class TestSNRmethods(unittest.TestCase): def setUp(self): starName = os.path.join(lsst.utils.getPackageDir('sims_photUtils'), 'tests/cartoonSedTestData/starSed/') starName = os.path.join(starName, 'kurucz', 'km20_5750.fits_g40_5790.gz') self.starSED = Sed() self.starSED.readSED_flambda(starName) imsimband = Bandpass() imsimband.imsimBandpass() fNorm = self.starSED.calcFluxNorm(22.0, imsimband) self.starSED.multiplyFluxNorm(fNorm) hardwareDir = os.path.join(lsst.utils.getPackageDir('throughputs'), 'baseline') componentList = ['detector.dat', 'm1.dat', 'm2.dat', 'm3.dat', 'lens1.dat', 'lens2.dat', 'lens3.dat'] self.skySed = Sed() self.skySed.readSED_flambda(os.path.join(hardwareDir, 'darksky.dat')) totalNameList = ['total_u.dat', 'total_g.dat', 'total_r.dat', 'total_i.dat', 'total_z.dat', 'total_y.dat'] self.bpList = [] self.hardwareList = [] for name in totalNameList: dummy = Bandpass() dummy.readThroughput(os.path.join(hardwareDir, name)) self.bpList.append(dummy) dummy = Bandpass() hardwareNameList = [os.path.join(hardwareDir, name)] for component in componentList: hardwareNameList.append(os.path.join(hardwareDir, component)) dummy.readThroughputList(hardwareNameList) self.hardwareList.append(dummy) self.filterNameList = ['u', 'g', 'r', 'i', 'z', 'y'] 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 testVerboseSNR(self): """ Make sure that calcSNR_sed has everything it needs to run in verbose mode """ 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, FWHMeff=0.7, verbose=True) 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 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 testNoSystematicUncertainty(self): """ Test that systematic uncertainty is handled correctly when set to None. """ m5_list = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7] photParams = PhotometricParameters(sigmaSys=0.0) 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 = snr.magErrorFromSNR(testSNR) msg = '%e is not %e; failed' % (sigma, control) self.assertAlmostEqual(sigma, control, 10, msg=msg) def testFWHMconversions(self): FWHMeff = 0.8 FWHMgeom = snr.FWHMeff2FWHMgeom(FWHMeff) self.assertEqual(FWHMgeom, (0.822*FWHMeff+0.052)) FWHMgeom = 0.8 FWHMeff = snr.FWHMgeom2FWHMeff(FWHMgeom) self.assertEqual(FWHMeff, (FWHMgeom-0.052)/0.822) def testSNR_arr(self): """ Test that calcSNR_m5 works on numpy arrays of magnitudes """ rng = np.random.RandomState(17) mag_list = rng.random_sample(100)*5.0 + 15.0 photParams = PhotometricParameters() bp = self.bpList[0] m5 = 24.0 control_list = [] for mm in mag_list: ratio, gamma = snr.calcSNR_m5(mm, bp, m5, photParams) control_list.append(ratio) control_list = np.array(control_list) test_list, gamma = snr.calcSNR_m5(mag_list, bp, m5, photParams) np.testing.assert_array_equal(control_list, test_list) def testError_arr(self): """ Test that calcMagError_m5 works on numpy arrays of magnitudes """ rng = np.random.RandomState(17) mag_list = rng.random_sample(100)*5.0 + 15.0 photParams = PhotometricParameters() bp = self.bpList[0] m5 = 24.0 control_list = [] for mm in mag_list: sig, gamma = snr.calcMagError_m5(mm, bp, m5, photParams) control_list.append(sig) control_list = np.array(control_list) test_list, gamma = snr.calcMagError_m5(mag_list, bp, m5, photParams) np.testing.assert_array_equal(control_list, test_list)