Coverage for python/lsst/sims/catUtils/mixins/PhotometryMixin.py : 83%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" photUtils -
ljones@astro.washington.edu (and ajc@astro.washington.edu)
and now (2014 March 28): scott.f.daniel@gmail.com
Collection of utilities to aid usage of Sed and Bandpass with dictionaries.
"""
calcMagError_m5, calcSNR_m5, PhotometricParameters, magErrorFromSNR, \ BandpassDict
""" This class provides an InstanceCatalog with a member variable photParams, which is an instance of the class PhotometricParameters.
It also provides the method calculateMagnitudeUncertainty, which takes magnitudes, a BandpassDict, and an ObservationMetaData as inputs and returns the uncertainties on those magnitudes. """
#an object carrying around photometric parameters like readnoise, effective area, plate scale, etc. #defaults to LSST values
""" Generate or populate the cache of gamma values used by this InstanceCatalog to calculate photometric uncertainties (gamma is defined in equation 5 of the LSST overview paper arXiv:0805.2366)
@param [in] m5_names is a list of the names of keys by which m5 values are referred to in the dict self.obs_metadata.m5
@param [in] bandpassDict is the bandpassDict containing the bandpasses corresponding to those m5 values. """
""" Generic getter for magnitude uncertainty columns.
Columns must be named 'sigma_xx' where 'xx' is the column name of the associated magnitude
@param [in] column_name_list is the list of magnitude column names associated with the uncertainties calculated by this getter (the 'xx' in the 'sigma_xx' above)
@param [in] m5_name_list are the keys to the self.obs_metadata.m5 dict corresponding to the bandpasses in column_names. For example: in the case of galaxies, the magnitude columns
column_names = ['uBulge', 'gBulge', 'rBulge', 'iBulge', 'zBulge', 'yBulge']
may correspond to m5 values keyed to
m5_name_list = ['u', 'g', 'r', 'i', 'z', 'y']
@param [in] bandpassDict_name is a string indicating the name of the InstanceCatalog member variable containing the BandpassDict to be used when calculating these magnitude uncertainties. The BandpassDict itself will be accessed using getattr(self, bandpassDict_name)
@param [out] returns a 2-D numpy array in which the first index is the uncertainty column and the second index is the catalog row (i.e. output suitable for a getter in an InstanceCatalog) """
# make sure that the magnitudes associated with any requested # uncertainties actually are calculated
# These lines must come after the preceding lines; # the bandpassDict will not be loaded until the magnitude # getters are called
else:
+ 'Is it possible your ObservationMetaData does not have the proper\n' 'm5 values defined?')
'sigma_lsst_z','sigma_lsst_y') def get_lsst_photometric_uncertainties(self): """ Getter for photometric uncertainties associated with lsst bandpasses """
'lsst_i', 'lsst_z', 'lsst_y'], ['u', 'g', 'r', 'i', 'z', 'y'], 'lsstBandpassDict')
""" Determine (probabilistically) whether a source was detected or not.
The 'completeness' of source detection at any magnitude is calculated by completeness = (1 + e^^(magFilter-m5)/sigma)^(-1) For each source with a magnitude magFilter, if a uniform random number [0-1) is less than or equal to 'completeness', then it is counted as "detected". See equation 24, figure 8 and table 5 from SDSS completeness analysis in http://iopscience.iop.org/0004-637X/794/2/120/pdf/apj_794_2_120.pdf "THE SLOAN DIGITAL SKY SURVEY COADD: 275 deg2 OF DEEP SLOAN DIGITAL SKY SURVEY IMAGING ON STRIPE 82"
@ param [in] magFilter is the magnitude of the object in the observed filter.
@ param [in] sigma is the FWHM of the distribution (default = 0.1)
@ param [in] randomSeed is an option to set a random seed (default None) @ param [in] pre_generate_randoms is an option (default False) to pre-generate a series of 12,000,000 random numbers for use throughout the visibility calculation [the random numbers used are randoms[objId]].
@ param [out] visibility (None/1). """ if len(magFilter) == 0: return numpy.array([]) # Calculate the completeness at the magnitude of each object. completeness = 1.0 / (1 + numpy.exp((magFilter - self.obs_metadata.m5[self.obs_metadata.bandpass])/sigma)) # Seed numpy if desired and not previously done. if (randomSeed is not None) and (not hasattr(self, 'ssm_random_seeded')): numpy.random.seed(randomSeed) self.ssm_random_seeded = True # Pre-generate random numbers, if desired and not previously done. if pre_generate_randoms and not hasattr(self, 'ssm_randoms'): self.ssm_randoms = numpy.random.rand(14000000) # Calculate probability values to compare to completeness. if hasattr(self, 'ssm_randoms'): # Grab the random numbers from self.randoms. probability = self.ssm_randoms[self.column_by_name('objId')] else: probability = numpy.random.random_sample(len(magFilter)) # Compare the random number to the completeness. visibility = numpy.where(probability <= completeness, 1, None) return visibility
""" Find columns named 'delta_*' and return them to be added to '*' magnitude columns (i.e. look for delta_lsst_u so that it can be added to lsst_u)
Parameters ---------- columnNames is a list of the quiescent columns (lsst_u in the example above) whose deltas we are looking for
Returns ------- A numpy array in which each row is a delta magnitude and each column is an astrophysical object/database row """
# figure out which of these columns we are actually calculating if name in self._actually_calculated_columns]
else: else:
""" This mixin provides the code necessary for calculating the component magnitudes associated with galaxies. It assumes that we want LSST filters. """
""" Determine whether or not this InstanceCatalog has a column specifically devoted to the cosmological distance modulus. """
""" Load a SedList of galaxy bulge Seds. The list will be stored in the variable self._bulgeSedList.
@param [in] wavelen_match is the wavelength grid (in nm) on which the Seds are to be sampled. """
internalAvList=internalAvList, redshiftList=redshiftList, cosmologicalDimming=cosmologicalDimming, wavelenMatch=wavelen_match, fileDir=getPackageDir('sims_sed_library'), specMap=defaultSpecMap) else: self._bulgeSedList.flush() self._bulgeSedList.loadSedsFromList(sedNameList, magNormList, internalAvList=internalAvList, redshiftList=redshiftList)
""" Load a SedList of galaxy disk Seds. The list will be stored in the variable self._bulgeSedList.
@param [in] wavelen_match is the wavelength grid (in nm) on which the Seds are to be sampled. """
internalAvList=internalAvList, redshiftList=redshiftList, cosmologicalDimming=cosmologicalDimming, wavelenMatch=wavelen_match, fileDir=getPackageDir('sims_sed_library'), specMap=defaultSpecMap) else: self._diskSedList.flush() self._diskSedList.loadSedsFromList(sedNameList, magNormList, internalAvList=internalAvList, redshiftList=redshiftList)
""" Load a SedList of galaxy AGN Seds. The list will be stored in the variable self._bulgeSedList.
@param [in] wavelen_match is the wavelength grid (in nm) on which the Seds are to be sampled. """
redshiftList=redshiftList, cosmologicalDimming=cosmologicalDimming, wavelenMatch=wavelen_match, fileDir=getPackageDir('sims_sed_library'), specMap=defaultSpecMap) else: redshiftList=redshiftList)
""" Sum the component magnitudes of a galaxy and return the answer
@param [in] disk is the disk magnitude must be a numpy array or a float
@param [in] bulge is the bulge magnitude must be a numpy array or a float
@param [in] agn is the agn magnitude must be a numpy array or a float
@param [out] outMag is the total magnitude of the galaxy """
baselineType = type(bulge) if baselineType == numpy.ndarray: elements = len(bulge) raise RuntimeError("All non-None arguments of sum_magnitudes need to be " + "of the same type (float or numpy array)")
elif not isinstance(agn, type(None)): if baseLineType == type(None): baselineType = type(agn) if baselineType == numpy.ndarray: elements = len(agn) elif not isinstance(agn, baselineType): raise RuntimeError("All non-None arguments of sum_magnitudes need to be " + "of the same type (float or numpy array)")
baselineType is not numpy.ndarray and \ baselineType is not numpy.float and \ baselineType is not numpy.float64:
raise RuntimeError("Arguments of sum_magnitudes need to be " + "either floats or numpy arrays; you appear to have passed %s " % baselineType)
else:
# according to this link # http://stackoverflow.com/questions/25087769/runtimewarning-divide-by-zero-error-how-to-avoid-python-numpy # we will still get a divide by zero error from log10, but numpy.where will be # circumventing the offending value, so it is probably okay else: else:
""" A generic getter for quiescent magnitudes of galaxy components.
@param [in] componentName is either 'bulge', 'disk', or 'agn'
@param [in] bandpassDict is a BandpassDict of the bandpasses in which to calculate the magnitudes
@param [in] columnNameList is a list of the columns corresponding to these magnitudes (for purposes of applying variability).
@param [out] magnitudes is a 2-D numpy array of magnitudes in which rows correspond to bandpasses and columns correspond to astronomical objects. """
# figure out which of these columns we are actually calculating if name in self._actually_calculated_columns]
else: else: else: else: raise RuntimeError('_quiescentMagnitudeGetter does not understand component %s ' \ % componentName)
else:
'sigma_iBulge', 'sigma_zBulge', 'sigma_yBulge') def get_photometric_uncertainties_bulge(self): """ Getter for photometric uncertainties associated with galaxy bulges """
'iBulge', 'zBulge', 'yBulge'], ['u', 'g', 'r', 'i', 'z', 'y'], 'lsstBandpassDict')
'sigma_iDisk', 'sigma_zDisk', 'sigma_yDisk') def get_photometric_uncertainties_disk(self): """ Getter for photometeric uncertainties associated with galaxy disks """
'iDisk', 'zDisk', 'yDisk'], ['u', 'g', 'r', 'i', 'z', 'y'], 'lsstBandpassDict')
'sigma_iAgn', 'sigma_zAgn', 'sigma_yAgn') def get_photometric_uncertainties_agn(self): """ Getter for photometric uncertainties associated with Agn """
'iAgn', 'zAgn', 'yAgn'], ['u', 'g', 'r', 'i', 'z', 'y'], 'lsstBandpassDict')
def get_lsst_bulge_mags(self): """ Getter for bulge magnitudes in LSST bandpasses """
# load a BandpassDict of LSST bandpasses, if not done already
# actually calculate the magnitudes self.get_lsst_bulge_mags._colnames)
def get_lsst_disk_mags(self): """ Getter for galaxy disk magnitudes in the LSST bandpasses """
# load a BandpassDict of LSST bandpasses, if not done already self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()
# actually calculate the magnitudes self.get_lsst_disk_mags._colnames)
def get_lsst_agn_mags(self): """ Getter for AGN magnitudes in the LSST bandpasses """
# load a BandpassDict of LSST bandpasses, if not done already
# actually calculate the magnitudes self.get_lsst_agn_mags._colnames)
def get_lsst_total_mags(self): """ Getter for total galaxy magnitudes in the LSST bandpasses """
# Loop over the columns calculated by this getter. For each # column, calculate the bluge, disk, and agn magnitude in the # corresponding bandpass, then sum them using the # sum_magnitudes method. else:
""" This mixin provides the infrastructure for doing photometry on stars
It assumes that we want LSST filters. """
""" Method to load the member variable self._sedList, which is a SedList. If self._sedList does not already exist, this method sets it up. If it does already exist, this method flushes its contents and loads a new chunk of Seds. """
galacticAvList=galacticAvList, wavelenMatch=wavelen_match, fileDir=getPackageDir('sims_sed_library'), specMap=defaultSpecMap) else: galacticAvList=galacticAvList)
""" This method gets the magnitudes for an InstanceCatalog, returning them in a 2-D numpy array in which rows correspond to bandpasses and columns correspond to astronomical objects.
@param [in] bandpassDict is a BandpassDict containing the bandpasses whose magnitudes are to be calculated
@param [in] columnNameList is a list of the names of the magnitude columns being calculated
@param [out] magnitudes is a 2-D numpy array of magnitudes in which rows correspond to bandpasses in bandpassDict and columns correspond to astronomical objects. """
# figure out which of these columns we are actually calculating if name in self._actually_calculated_columns]
else:
'quiescent_lsst_i', 'quiescent_lsst_z', 'quiescent_lsst_y') def get_quiescent_lsst_magnitudes(self):
self.get_quiescent_lsst_magnitudes._colnames)
def get_lsst_magnitudes(self): """ getter for LSST stellar magnitudes """
self.column_by_name('quiescent_lsst_g'), self.column_by_name('quiescent_lsst_r'), self.column_by_name('quiescent_lsst_i'), self.column_by_name('quiescent_lsst_z'), self.column_by_name('quiescent_lsst_y')])
""" A mixin to calculate photometry for solar system objects. """ # Because solar system objects will not have dust extinctions, we should be able to read in every # SED exactly once, calculate the colors and magnitudes, and then get actual magnitudes by adding # an offset based on magNorm.
""" Method that actually does the work calculating magnitudes for solar system objects.
Because solar system objects have no dust extinction, this method works by loading each unique Sed once, normalizing it, calculating its magnitudes in the desired bandpasses, and then storing the normalizing magnitudes and the bandpass magnitudes in a dict. Magnitudes for subsequent objects with identical Seds will be calculated by adding an offset to the magnitudes. The offset is determined by comparing normalizing magnitues.
@param [in] bandpassDict is an instantiation of BandpassDict representing the bandpasses to be integrated over
@param [in] columnNameList is a list of the names of the columns being calculated by this getter
@param [in] bandpassTag (optional) is a string indicating the name of the bandpass system (i.e. 'lsst', 'sdss', etc.). This is in case the user wants to calculate the magnitudes in multiple systems simultaneously. In that case, the dict will store magnitudes for each Sed in each magnitude system separately.
@param [out] a numpy array of magnitudes corresponding to bandpassDict. """
# figure out which of these columns we are actually calculating if name in self._actually_calculated_columns]
# need to return something when InstanceCatalog goes through # it's "dry run" to determine what columns are required from # the database
else:
def get_lsst_magnitudes(self): """ getter for LSST magnitudes of solar system objects """
""" Generate the magnitude in the filter of the observation. """ magFilter = 'lsst_' + self.obs_metadata.bandpass return self.column_by_name(magFilter)
""" Calculate the SNR for the observation, given m5 from obs_metadata and the trailing losses. """ magFilter = self.column_by_name('magFilter') bandpass = self.lsstBandpassDict[self.obs_metadata.bandpass] # Get m5 for the visit m5 = self.obs_metadata.m5[self.obs_metadata.bandpass] # Adjust the magnitude of the source for the trailing losses. dmagSNR = self.column_by_name('dmagTrailing') magObj = magFilter - dmagSNR if len(magObj) == 0: snr = [] else: snr, gamma = calcSNR_m5(magObj, bandpass, m5, self.photParams) return snr
""" Generate a None/1 flag indicating whether the object was detected or not.
Sets the random seed for 'calculateVisibility' using the obs_metadata.obsHistId """ magFilter = self.column_by_name('magFilter') dmagDetect = self.column_by_name('dmagDetection') magObj = magFilter - dmagDetect # Adjusted m5 value, accounting for the fact these are moving objects. mjdSeed = numpy.int(self.obs_metadata.mjd.TAI * 1000000) % 4294967295 visibility = self.calculateVisibility(magObj, randomSeed=mjdSeed, pre_generate_randoms=True) return visibility
def get_ssm_dmag(self): """ This getter will calculate:
dmagTrailing: the offset in m5 used to represent the loss in signal to noise resulting from the fact that the object's motion smears out its PSF
dmagDetection: the offset in m5 used to represent the shift in detection threshold resulting from the fact that the object's motion smears out its PSF """
"Your catalog's ObservationMetaData does not " "specify seeing.")
"Your catalog's ObservationMetaData contains multiple " "seeing values. Re-create your catalog with only one seeing value.")
"Your catalog does not have an associated PhotometricParameters " "member variable. It is impossible to know what the exposure time is.")
# i.e., no need to divide by cos(dec))
|