예제 #1
0
    def testFlush(self):
        """
        Test that the flush method of SedList behaves properly
        """
        imsimBand = Bandpass()
        imsimBand.imsimBandpass()
        nSed = 10
        sedNameList_0 = self.getListOfSedNames(nSed)
        magNormList_0 = self.rng.random_sample(nSed)*5.0 + 15.0
        internalAvList_0 = self.rng.random_sample(nSed)*0.3 + 0.1
        redshiftList_0 = self.rng.random_sample(nSed)*5.0
        galacticAvList_0 = self.rng.random_sample(nSed)*0.3 + 0.1
        wavelen_match = np.arange(300.0, 1500.0, 10.0)
        testList = SedList(sedNameList_0, magNormList_0,
                           fileDir=self.sedDir,
                           internalAvList=internalAvList_0,
                           redshiftList=redshiftList_0, galacticAvList=galacticAvList_0,
                           wavelenMatch=wavelen_match)

        self.assertEqual(len(testList), nSed)
        np.testing.assert_array_equal(wavelen_match, testList.wavelenMatch)

        for ix in range(len(sedNameList_0)):
            self.assertAlmostEqual(internalAvList_0[ix], testList.internalAvList[ix], 10)
            self.assertAlmostEqual(galacticAvList_0[ix], testList.galacticAvList[ix], 10)
            self.assertAlmostEqual(redshiftList_0[ix], testList.redshiftList[ix], 10)

        for ix, (name, norm, iav, gav, zz) in \
            enumerate(zip(sedNameList_0, magNormList_0, internalAvList_0,
                      galacticAvList_0, redshiftList_0)):

            sedControl = Sed()
            sedControl.readSED_flambda(os.path.join(self.sedDir, name+'.gz'))

            fnorm = sedControl.calcFluxNorm(norm, imsimBand)
            sedControl.multiplyFluxNorm(fnorm)

            a_coeff, b_coeff = sedControl.setupCCM_ab()
            sedControl.addDust(a_coeff, b_coeff, A_v=iav)

            sedControl.redshiftSED(zz, dimming=True)
            sedControl.resampleSED(wavelen_match=wavelen_match)

            a_coeff, b_coeff = sedControl.setupCCM_ab()
            sedControl.addDust(a_coeff, b_coeff, A_v=gav)

            sedTest = testList[ix]

            np.testing.assert_array_equal(sedControl.wavelen, sedTest.wavelen)
            np.testing.assert_array_equal(sedControl.flambda, sedTest.flambda)
            np.testing.assert_array_equal(sedControl.fnu, sedTest.fnu)

        testList.flush()

        sedNameList_1 = self.getListOfSedNames(nSed//2)
        magNormList_1 = self.rng.random_sample(nSed//2)*5.0 + 15.0
        internalAvList_1 = self.rng.random_sample(nSed//2)*0.3 + 0.1
        redshiftList_1 = self.rng.random_sample(nSed//2)*5.0
        galacticAvList_1 = self.rng.random_sample(nSed//2)*0.3 + 0.1

        testList.loadSedsFromList(sedNameList_1, magNormList_1,
                                  internalAvList=internalAvList_1,
                                  galacticAvList=galacticAvList_1,
                                  redshiftList=redshiftList_1)

        self.assertEqual(len(testList), nSed/2)
        self.assertEqual(len(testList.redshiftList), nSed/2)
        self.assertEqual(len(testList.internalAvList), nSed/2)
        self.assertEqual(len(testList.galacticAvList), nSed/2)
        np.testing.assert_array_equal(wavelen_match, testList.wavelenMatch)

        for ix in range(len(sedNameList_1)):
            self.assertAlmostEqual(internalAvList_1[ix], testList.internalAvList[ix], 10)
            self.assertAlmostEqual(galacticAvList_1[ix], testList.galacticAvList[ix], 10)
            self.assertAlmostEqual(redshiftList_1[ix], testList.redshiftList[ix], 10)

        for ix, (name, norm, iav, gav, zz) in \
            enumerate(zip(sedNameList_1, magNormList_1, internalAvList_1,
                      galacticAvList_1, redshiftList_1)):

            sedControl = Sed()
            sedControl.readSED_flambda(os.path.join(self.sedDir, name+'.gz'))

            fnorm = sedControl.calcFluxNorm(norm, imsimBand)
            sedControl.multiplyFluxNorm(fnorm)

            a_coeff, b_coeff = sedControl.setupCCM_ab()
            sedControl.addDust(a_coeff, b_coeff, A_v=iav)

            sedControl.redshiftSED(zz, dimming=True)
            sedControl.resampleSED(wavelen_match=wavelen_match)

            a_coeff, b_coeff = sedControl.setupCCM_ab()
            sedControl.addDust(a_coeff, b_coeff, A_v=gav)

            sedTest = testList[ix]

            np.testing.assert_array_equal(sedControl.wavelen, sedTest.wavelen)
            np.testing.assert_array_equal(sedControl.flambda, sedTest.flambda)
            np.testing.assert_array_equal(sedControl.fnu, sedTest.fnu)
예제 #2
0
class PhotometryStars(PhotometryBase):
    """
    This mixin provides the infrastructure for doing photometry on stars

    It assumes that we want LSST filters.
    """

    def _loadSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilename')
        magNormList = self.column_by_name('magNorm')
        galacticAvList = self.column_by_name('galacticAv')

        if len(sedNameList)==0:
            return np.ones((0))

        if not hasattr(self, '_sedList'):
            self._sedList = SedList(sedNameList, magNormList,
                                    galacticAvList=galacticAvList,
                                    wavelenMatch=wavelen_match,
                                    fileDir=getPackageDir('sims_sed_library'),
                                    specMap=defaultSpecMap)
        else:
            self._sedList.flush()
            self._sedList.loadSedsFromList(sedNameList, magNormList,
                                          galacticAvList=galacticAvList)


    def _quiescentMagnitudeGetter(self, bandpassDict, columnNameList):
        """
        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
        indices = [ii for ii, name in enumerate(columnNameList)
                   if name in self._actually_calculated_columns]

        if len(indices) == len(columnNameList):
            indices = None

        self._loadSedList(bandpassDict.wavelenMatch)

        if not hasattr(self, '_sedList'):
            magnitudes = np.ones((len(columnNameList),0))
        else:
            magnitudes = bandpassDict.magListForSedList(self._sedList, indices=indices).transpose()

        return magnitudes

    @compound('quiescent_lsst_u', 'quiescent_lsst_g', 'quiescent_lsst_r',
              'quiescent_lsst_i', 'quiescent_lsst_z', 'quiescent_lsst_y')
    def get_quiescent_lsst_magnitudes(self):

        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        return self._quiescentMagnitudeGetter(self.lsstBandpassDict,
                                              self.get_quiescent_lsst_magnitudes._colnames)

    @compound('lsst_u','lsst_g','lsst_r','lsst_i','lsst_z','lsst_y')
    def get_lsst_magnitudes(self):
        """
        getter for LSST stellar magnitudes
        """

        magnitudes = np.array([self.column_by_name('quiescent_lsst_u'),
                                  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')])

        delta = self._variabilityGetter(self.get_lsst_magnitudes._colnames)
        magnitudes += delta

        return magnitudes
예제 #3
0
class PhotometryGalaxies(PhotometryBase):
    """
    This mixin provides the code necessary for calculating the component magnitudes associated with
    galaxies.  It assumes that we want LSST filters.
    """

    def _hasCosmoDistMod(self):
        """
        Determine whether or not this InstanceCatalog has a column
        specifically devoted to the cosmological distance modulus.
        """
        if 'cosmologicalDistanceModulus' in self._all_available_columns:
            return True
        return False


    def _loadBulgeSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilenameBulge')
        magNormList = self.column_by_name('magNormBulge')
        redshiftList = self.column_by_name('redshift')
        internalAvList = self.column_by_name('internalAvBulge')
        cosmologicalDimming = not self._hasCosmoDistMod()

        if len(sedNameList)==0:
            return np.ones((0))

        if not hasattr(self, '_bulgeSedList'):
            self._bulgeSedList = SedList(sedNameList, magNormList,
                                         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)


    def _loadDiskSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilenameDisk')
        magNormList = self.column_by_name('magNormDisk')
        redshiftList = self.column_by_name('redshift')
        internalAvList = self.column_by_name('internalAvDisk')
        cosmologicalDimming = not self._hasCosmoDistMod()

        if len(sedNameList)==0:
            return np.ones((0))

        if not hasattr(self, '_diskSedList'):
            self._diskSedList = SedList(sedNameList, magNormList,
                                        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)


    def _loadAgnSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilenameAgn')
        magNormList = self.column_by_name('magNormAgn')
        redshiftList = self.column_by_name('redshift')
        cosmologicalDimming = not self._hasCosmoDistMod()

        if len(sedNameList)==0:
            return np.ones((0))

        if not hasattr(self, '_agnSedList'):
            self._agnSedList = SedList(sedNameList, magNormList,
                                       redshiftList=redshiftList,
                                       cosmologicalDimming=cosmologicalDimming,
                                       wavelenMatch=wavelen_match,
                                       fileDir=getPackageDir('sims_sed_library'),
                                       specMap=defaultSpecMap)
        else:
            self._agnSedList.flush()
            self._agnSedList.loadSedsFromList(sedNameList, magNormList,
                                               redshiftList=redshiftList)


    def sum_magnitudes(self, disk = None, bulge = None, agn = None):
        """
        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
        """
        with np.errstate(divide='ignore', invalid='ignore'):
            baselineType = type(None)
            if not isinstance(disk, type(None)):
                baselineType = type(disk)
                if baselineType == np.ndarray:
                    elements=len(disk)

            if not isinstance(bulge, type(None)):
                if baselineType == type(None):
                    baselineType = type(bulge)
                    if baselineType == np.ndarray:
                        elements = len(bulge)
                elif not isinstance(bulge, baselineType):
                    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 == np.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)")

            if baselineType is not float and \
               baselineType is not np.ndarray and \
               baselineType is not np.float and \
               baselineType is not np.float64:

                raise RuntimeError("Arguments of sum_magnitudes need to be " +
                                   "either floats or numpy arrays; you appear to have passed %s " % baselineType)

            mm_0 = 22.
            tol = 1.0e-30

            if baselineType == np.ndarray:
                nn = np.zeros(elements)
            else:
                nn = 0.0

            if disk is not None:
                nn += np.where(np.isnan(disk), 0.0, np.power(10, -0.4*(disk - mm_0)))

            if bulge is not None:
                nn += np.where(np.isnan(bulge), 0.0, np.power(10, -0.4*(bulge - mm_0)))

            if agn is not None:
                nn += np.where(np.isnan(agn), 0.0, np.power(10, -0.4*(agn - mm_0)))

            if baselineType == np.ndarray:
                # 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 np.where will be
                # circumventing the offending value, so it is probably okay
                return np.where(nn>tol, -2.5*np.log10(nn) + mm_0, np.NaN)
            else:
                if nn>tol:
                    return -2.5*np.log10(nn) + mm_0
                else:
                    return np.NaN


    def _quiescentMagnitudeGetter(self, componentName, bandpassDict, columnNameList):
        """
        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
        indices = [ii for ii, name in enumerate(columnNameList)
                   if name in self._actually_calculated_columns]

        if len(indices) == len(columnNameList):
            indices = None

        if componentName == 'bulge':
            self._loadBulgeSedList(bandpassDict.wavelenMatch)
            if not hasattr(self, '_bulgeSedList'):
                sedList = None
            else:
                sedList = self._bulgeSedList
        elif componentName == 'disk':
            self._loadDiskSedList(bandpassDict.wavelenMatch)
            if not hasattr(self, '_diskSedList'):
                sedList = None
            else:
                sedList = self._diskSedList
        elif componentName == 'agn':
            self._loadAgnSedList(bandpassDict.wavelenMatch)
            if not hasattr(self, '_agnSedList'):
                sedList = None
            else:
                sedList = self._agnSedList
        else:
            raise RuntimeError('_quiescentMagnitudeGetter does not understand component %s ' \
                               % componentName)

        if sedList is None:
            magnitudes = np.ones((len(columnNameList), 0))
        else:
            magnitudes = bandpassDict.magListForSedList(sedList, indices=indices).transpose()

        if self._hasCosmoDistMod():
            cosmoDistMod = self.column_by_name('cosmologicalDistanceModulus')
            if len(cosmoDistMod)>0:
               for ix in range(magnitudes.shape[0]):
                   magnitudes[ix] += cosmoDistMod

        return magnitudes


    @compound('sigma_uBulge', 'sigma_gBulge', 'sigma_rBulge',
              'sigma_iBulge', 'sigma_zBulge', 'sigma_yBulge')
    def get_photometric_uncertainties_bulge(self):
        """
        Getter for photometric uncertainties associated with galaxy bulges
        """

        return self._magnitudeUncertaintyGetter(['uBulge', 'gBulge', 'rBulge',
                                                'iBulge', 'zBulge', 'yBulge'],
                                                ['u', 'g', 'r', 'i', 'z', 'y'],
                                                'lsstBandpassDict')


    @compound('sigma_uDisk', 'sigma_gDisk', 'sigma_rDisk',
              'sigma_iDisk', 'sigma_zDisk', 'sigma_yDisk')
    def get_photometric_uncertainties_disk(self):
        """
        Getter for photometeric uncertainties associated with galaxy disks
        """

        return self._magnitudeUncertaintyGetter(['uDisk', 'gDisk', 'rDisk',
                                                'iDisk', 'zDisk', 'yDisk'],
                                                ['u', 'g', 'r', 'i', 'z', 'y'],
                                                'lsstBandpassDict')


    @compound('sigma_uAgn', 'sigma_gAgn', 'sigma_rAgn',
              'sigma_iAgn', 'sigma_zAgn', 'sigma_yAgn')
    def get_photometric_uncertainties_agn(self):
        """
        Getter for photometric uncertainties associated with Agn
        """

        return self._magnitudeUncertaintyGetter(['uAgn', 'gAgn', 'rAgn',
                                                'iAgn', 'zAgn', 'yAgn'],
                                                ['u', 'g', 'r', 'i', 'z', 'y'],
                                                'lsstBandpassDict')


    @compound('uBulge', 'gBulge', 'rBulge', 'iBulge', 'zBulge', 'yBulge')
    def get_lsst_bulge_mags(self):
        """
        Getter for bulge magnitudes in LSST bandpasses
        """

        # load a BandpassDict of LSST bandpasses, if not done already
        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        # actually calculate the magnitudes
        mag = self._quiescentMagnitudeGetter('bulge', self.lsstBandpassDict,
                                             self.get_lsst_bulge_mags._colnames)

        mag += self._variabilityGetter(self.get_lsst_bulge_mags._colnames)
        return mag


    @compound('uDisk', 'gDisk', 'rDisk', 'iDisk', 'zDisk', 'yDisk')
    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
        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        # actually calculate the magnitudes
        mag = self._quiescentMagnitudeGetter('disk', self.lsstBandpassDict,
                                             self.get_lsst_disk_mags._colnames)

        mag += self._variabilityGetter(self.get_lsst_disk_mags._colnames)
        return mag


    @compound('uAgn', 'gAgn', 'rAgn', 'iAgn', 'zAgn', 'yAgn')
    def get_lsst_agn_mags(self):
        """
        Getter for AGN magnitudes in the LSST bandpasses
        """

        # load a BandpassDict of LSST bandpasses, if not done already
        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        # actually calculate the magnitudes
        mag = self._quiescentMagnitudeGetter('agn', self.lsstBandpassDict,
                                             self.get_lsst_agn_mags._colnames)

        mag += self._variabilityGetter(self.get_lsst_agn_mags._colnames)
        return mag

    @compound('lsst_u', 'lsst_g', 'lsst_r', 'lsst_i', 'lsst_z', 'lsst_y')
    def get_lsst_total_mags(self):
        """
        Getter for total galaxy magnitudes in the LSST bandpasses
        """

        idList = self.column_by_name('uniqueId')
        numObj = len(idList)
        output = []

        # 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.
        for columnName in self.get_lsst_total_mags._colnames:
            if columnName not in self._actually_calculated_columns:
                sub_list = [np.NaN]*numObj
            else:
                bandpass = columnName[-1]
                bulge = self.column_by_name('%sBulge' % bandpass)
                disk = self.column_by_name('%sDisk' % bandpass)
                agn = self.column_by_name('%sAgn' % bandpass)
                sub_list = self.sum_magnitudes(bulge=bulge, disk=disk, agn=agn)

            output.append(sub_list)
        return np.array(output)
예제 #4
0
class PhotometryStars(PhotometryBase):
    """
    This mixin provides the infrastructure for doing photometry on stars

    It assumes that we want LSST filters.
    """

    def _loadSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilename')
        magNormList = self.column_by_name('magNorm')
        galacticAvList = self.column_by_name('galacticAv')

        if len(sedNameList)==0:
            return numpy.ones((0))

        if not hasattr(self, '_sedList'):
            self._sedList = SedList(sedNameList, magNormList,
                                         galacticAvList=galacticAvList,
                                         wavelenMatch=wavelen_match)
        else:
            self._sedList.flush()
            self._sedList.loadSedsFromList(sedNameList, magNormList,
                                          galacticAvList=galacticAvList)


    def _quiescentMagnitudeGetter(self, bandpassDict, columnNameList):
        """
        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
        indices = [ii for ii, name in enumerate(columnNameList)
                   if name in self._actually_calculated_columns]

        if len(indices) == len(columnNameList):
            indices = None

        self._loadSedList(bandpassDict.wavelenMatch)

        if not hasattr(self, '_sedList'):
            magnitudes = numpy.ones((len(columnNameList),0))
        else:
            magnitudes = bandpassDict.magListForSedList(self._sedList, indices=indices).transpose()

        return magnitudes

    @compound('quiescent_lsst_u', 'quiescent_lsst_g', 'quiescent_lsst_r',
              'quiescent_lsst_i', 'quiescent_lsst_z', 'quiescent_lsst_y')
    def get_quiescent_lsst_magnitudes(self):

        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        return self._quiescentMagnitudeGetter(self.lsstBandpassDict,
                                              self.get_quiescent_lsst_magnitudes._colnames)

    @compound('lsst_u','lsst_g','lsst_r','lsst_i','lsst_z','lsst_y')
    def get_lsst_magnitudes(self):
        """
        getter for LSST stellar magnitudes
        """

        magnitudes = numpy.array([self.column_by_name('quiescent_lsst_u'),
                                  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')])

        delta = self._variabilityGetter(self.get_lsst_magnitudes._colnames)
        magnitudes += delta

        return magnitudes
예제 #5
0
class PhotometryGalaxies(PhotometryBase):
    """
    This mixin provides the code necessary for calculating the component magnitudes associated with
    galaxies.  It assumes that we want LSST filters.
    """

    def _hasCosmoDistMod(self):
        """
        Determine whether or not this InstanceCatalog has a column
        specifically devoted to the cosmological distance modulus.
        """
        if 'cosmologicalDistanceModulus' in self._all_available_columns:
            return True
        return False


    def _loadBulgeSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilenameBulge')
        magNormList = self.column_by_name('magNormBulge')
        redshiftList = self.column_by_name('redshift')
        internalAvList = self.column_by_name('internalAvBulge')
        cosmologicalDimming = not self._hasCosmoDistMod()

        if len(sedNameList)==0:
            return numpy.ones((0))

        if not hasattr(self, '_bulgeSedList'):
            self._bulgeSedList = SedList(sedNameList, magNormList,
                                               internalAvList=internalAvList,
                                               redshiftList=redshiftList,
                                               cosmologicalDimming=cosmologicalDimming,
                                               wavelenMatch=wavelen_match)
        else:
            self._bulgeSedList.flush()
            self._bulgeSedList.loadSedsFromList(sedNameList, magNormList,
                                               internalAvList=internalAvList,
                                               redshiftList=redshiftList)


    def _loadDiskSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilenameDisk')
        magNormList = self.column_by_name('magNormDisk')
        redshiftList = self.column_by_name('redshift')
        internalAvList = self.column_by_name('internalAvDisk')
        cosmologicalDimming = not self._hasCosmoDistMod()

        if len(sedNameList)==0:
            return numpy.ones((0))

        if not hasattr(self, '_diskSedList'):
            self._diskSedList = SedList(sedNameList, magNormList,
                                               internalAvList=internalAvList,
                                               redshiftList=redshiftList,
                                               cosmologicalDimming=cosmologicalDimming,
                                               wavelenMatch=wavelen_match)
        else:
            self._diskSedList.flush()
            self._diskSedList.loadSedsFromList(sedNameList, magNormList,
                                               internalAvList=internalAvList,
                                               redshiftList=redshiftList)


    def _loadAgnSedList(self, wavelen_match):
        """
        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.
        """

        sedNameList = self.column_by_name('sedFilenameAgn')
        magNormList = self.column_by_name('magNormAgn')
        redshiftList = self.column_by_name('redshift')
        cosmologicalDimming = not self._hasCosmoDistMod()

        if len(sedNameList)==0:
            return numpy.ones((0))

        if not hasattr(self, '_agnSedList'):
            self._agnSedList = SedList(sedNameList, magNormList,
                                               redshiftList=redshiftList,
                                               cosmologicalDimming=cosmologicalDimming,
                                               wavelenMatch=wavelen_match)
        else:
            self._agnSedList.flush()
            self._agnSedList.loadSedsFromList(sedNameList, magNormList,
                                               redshiftList=redshiftList)


    def sum_magnitudes(self, disk = None, bulge = None, agn = None):
        """
        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(None)
        if not isinstance(disk, type(None)):
            baselineType = type(disk)
            if baselineType == numpy.ndarray:
                elements=len(disk)

        if not isinstance(bulge, type(None)):
            if baselineType == type(None):
                baselineType = type(bulge)
                if baselineType == numpy.ndarray:
                    elements = len(bulge)
            elif not isinstance(bulge, baselineType):
                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)")

        if baselineType is not float and \
           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)

        mm_0 = 22.
        tol = 1.0e-30

        if baselineType == numpy.ndarray:
            nn = numpy.zeros(elements)
        else:
            nn = 0.0

        if disk is not None:
            nn += numpy.where(numpy.isnan(disk), 0.0, numpy.power(10, -0.4*(disk - mm_0)))

        if bulge is not None:
            nn += numpy.where(numpy.isnan(bulge), 0.0, numpy.power(10, -0.4*(bulge - mm_0)))

        if agn is not None:
            nn += numpy.where(numpy.isnan(agn), 0.0, numpy.power(10, -0.4*(agn - mm_0)))

        if baselineType == numpy.ndarray:
            # 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
            return numpy.where(nn>tol, -2.5*numpy.log10(nn) + mm_0, numpy.NaN)
        else:
            if nn>tol:
                return -2.5*numpy.log10(nn) + mm_0
            else:
                return numpy.NaN


    def _quiescentMagnitudeGetter(self, componentName, bandpassDict, columnNameList):
        """
        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
        indices = [ii for ii, name in enumerate(columnNameList)
                   if name in self._actually_calculated_columns]

        if len(indices) == len(columnNameList):
            indices = None

        if componentName == 'bulge':
            self._loadBulgeSedList(bandpassDict.wavelenMatch)
            if not hasattr(self, '_bulgeSedList'):
                sedList = None
            else:
                sedList = self._bulgeSedList
        elif componentName == 'disk':
            self._loadDiskSedList(bandpassDict.wavelenMatch)
            if not hasattr(self, '_diskSedList'):
                sedList = None
            else:
                sedList = self._diskSedList
        elif componentName == 'agn':
            self._loadAgnSedList(bandpassDict.wavelenMatch)
            if not hasattr(self, '_agnSedList'):
                sedList = None
            else:
                sedList = self._agnSedList
        else:
            raise RuntimeError('_quiescentMagnitudeGetter does not understand component %s ' \
                               % componentName)

        if sedList is None:
            magnitudes = numpy.ones((len(columnNameList), 0))
        else:
            magnitudes = bandpassDict.magListForSedList(sedList, indices=indices).transpose()

        if self._hasCosmoDistMod():
            cosmoDistMod = self.column_by_name('cosmologicalDistanceModulus')
            if len(cosmoDistMod)>0:
               for ix in range(magnitudes.shape[0]):
                   magnitudes[ix] += cosmoDistMod

        return magnitudes


    @compound('sigma_uBulge', 'sigma_gBulge', 'sigma_rBulge',
              'sigma_iBulge', 'sigma_zBulge', 'sigma_yBulge')
    def get_photometric_uncertainties_bulge(self):
        """
        Getter for photometric uncertainties associated with galaxy bulges
        """

        return self._magnitudeUncertaintyGetter(['uBulge', 'gBulge', 'rBulge',
                                                'iBulge', 'zBulge', 'yBulge'],
                                                ['u', 'g', 'r', 'i', 'z', 'y'],
                                                'lsstBandpassDict')


    @compound('sigma_uDisk', 'sigma_gDisk', 'sigma_rDisk',
              'sigma_iDisk', 'sigma_zDisk', 'sigma_yDisk')
    def get_photometric_uncertainties_disk(self):
        """
        Getter for photometeric uncertainties associated with galaxy disks
        """

        return self._magnitudeUncertaintyGetter(['uDisk', 'gDisk', 'rDisk',
                                                'iDisk', 'zDisk', 'yDisk'],
                                                ['u', 'g', 'r', 'i', 'z', 'y'],
                                                'lsstBandpassDict')


    @compound('sigma_uAgn', 'sigma_gAgn', 'sigma_rAgn',
              'sigma_iAgn', 'sigma_zAgn', 'sigma_yAgn')
    def get_photometric_uncertainties_agn(self):
        """
        Getter for photometric uncertainties associated with Agn
        """

        return self._magnitudeUncertaintyGetter(['uAgn', 'gAgn', 'rAgn',
                                                'iAgn', 'zAgn', 'yAgn'],
                                                ['u', 'g', 'r', 'i', 'z', 'y'],
                                                'lsstBandpassDict')


    @compound('uBulge', 'gBulge', 'rBulge', 'iBulge', 'zBulge', 'yBulge')
    def get_lsst_bulge_mags(self):
        """
        Getter for bulge magnitudes in LSST bandpasses
        """

        # load a BandpassDict of LSST bandpasses, if not done already
        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        # actually calculate the magnitudes
        mag = self._quiescentMagnitudeGetter('bulge', self.lsstBandpassDict,
                                             self.get_lsst_bulge_mags._colnames)

        mag += self._variabilityGetter(self.get_lsst_bulge_mags._colnames)
        return mag


    @compound('uDisk', 'gDisk', 'rDisk', 'iDisk', 'zDisk', 'yDisk')
    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
        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        # actually calculate the magnitudes
        mag = self._quiescentMagnitudeGetter('disk', self.lsstBandpassDict,
                                             self.get_lsst_disk_mags._colnames)

        mag += self._variabilityGetter(self.get_lsst_disk_mags._colnames)
        return mag


    @compound('uAgn', 'gAgn', 'rAgn', 'iAgn', 'zAgn', 'yAgn')
    def get_lsst_agn_mags(self):
        """
        Getter for AGN magnitudes in the LSST bandpasses
        """

        # load a BandpassDict of LSST bandpasses, if not done already
        if not hasattr(self, 'lsstBandpassDict'):
            self.lsstBandpassDict = BandpassDict.loadTotalBandpassesFromFiles()

        # actually calculate the magnitudes
        mag = self._quiescentMagnitudeGetter('agn', self.lsstBandpassDict,
                                             self.get_lsst_agn_mags._colnames)

        mag += self._variabilityGetter(self.get_lsst_agn_mags._colnames)
        return mag

    @compound('lsst_u', 'lsst_g', 'lsst_r', 'lsst_i', 'lsst_z', 'lsst_y')
    def get_lsst_total_mags(self):
        """
        Getter for total galaxy magnitudes in the LSST bandpasses
        """

        idList = self.column_by_name('uniqueId')
        numObj = len(idList)
        output = []

        # 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.
        for columnName in self.get_lsst_total_mags._colnames:
            if columnName not in self._actually_calculated_columns:
                sub_list = [numpy.NaN]*numObj
            else:
                bandpass = columnName[-1]
                bulge = self.column_by_name('%sBulge' % bandpass)
                disk = self.column_by_name('%sDisk' % bandpass)
                agn = self.column_by_name('%sAgn' % bandpass)
                sub_list = self.sum_magnitudes(bulge=bulge, disk=disk, agn=agn)

            output.append(sub_list)
        return numpy.array(output)
    def testFlush(self):
        """
        Test that the flush method of SedList behaves properly
        """
        imsimBand = Bandpass()
        imsimBand.imsimBandpass()
        nSed = 10
        sedNameList_0 = self.getListOfSedNames(nSed)
        magNormList_0 = numpy.random.random_sample(nSed)*5.0 + 15.0
        internalAvList_0 = numpy.random.random_sample(nSed)*0.3 + 0.1
        redshiftList_0 = numpy.random.random_sample(nSed)*5.0
        galacticAvList_0 = numpy.random.random_sample(nSed)*0.3 + 0.1
        wavelen_match = numpy.arange(300.0, 1500.0, 10.0)
        testList = SedList(sedNameList_0, magNormList_0, internalAvList=internalAvList_0, \
                                 redshiftList=redshiftList_0, galacticAvList=galacticAvList_0,
                                 wavelenMatch=wavelen_match)

        self.assertEqual(len(testList), nSed)
        numpy.testing.assert_array_equal(wavelen_match, testList.wavelenMatch)

        for ix in range(len(sedNameList_0)):
            self.assertAlmostEqual(internalAvList_0[ix], testList.internalAvList[ix], 10)
            self.assertAlmostEqual(galacticAvList_0[ix], testList.galacticAvList[ix], 10)
            self.assertAlmostEqual(redshiftList_0[ix], testList.redshiftList[ix], 10)

        for ix, (name, norm, iav, gav, zz) in \
        enumerate(zip(sedNameList_0, magNormList_0, internalAvList_0, \
                      galacticAvList_0, redshiftList_0)):

            sedControl = Sed()
            sedControl.readSED_flambda(os.path.join(self.sedDir, name+'.gz'))

            fnorm = sedControl.calcFluxNorm(norm, imsimBand)
            sedControl.multiplyFluxNorm(fnorm)

            a_coeff, b_coeff = sedControl.setupCCMab()
            sedControl.addCCMDust(a_coeff, b_coeff, A_v=iav)

            sedControl.redshiftSED(zz, dimming=True)
            sedControl.resampleSED(wavelen_match=wavelen_match)

            a_coeff, b_coeff = sedControl.setupCCMab()
            sedControl.addCCMDust(a_coeff, b_coeff, A_v=gav)

            sedTest = testList[ix]

            numpy.testing.assert_array_equal(sedControl.wavelen, sedTest.wavelen)
            numpy.testing.assert_array_equal(sedControl.flambda, sedTest.flambda)
            numpy.testing.assert_array_equal(sedControl.fnu, sedTest.fnu)



        testList.flush()

        sedNameList_1 = self.getListOfSedNames(nSed/2)
        magNormList_1 = numpy.random.random_sample(nSed/2)*5.0 + 15.0
        internalAvList_1 = numpy.random.random_sample(nSed/2)*0.3 + 0.1
        redshiftList_1 = numpy.random.random_sample(nSed/2)*5.0
        galacticAvList_1 = numpy.random.random_sample(nSed/2)*0.3 + 0.1

        testList.loadSedsFromList(sedNameList_1, magNormList_1,
                                  internalAvList=internalAvList_1,
                                  galacticAvList=galacticAvList_1,
                                  redshiftList=redshiftList_1)

        self.assertEqual(len(testList), nSed/2)
        self.assertEqual(len(testList.redshiftList), nSed/2)
        self.assertEqual(len(testList.internalAvList), nSed/2)
        self.assertEqual(len(testList.galacticAvList), nSed/2)
        numpy.testing.assert_array_equal(wavelen_match, testList.wavelenMatch)


        for ix in range(len(sedNameList_1)):
            self.assertAlmostEqual(internalAvList_1[ix], testList.internalAvList[ix], 10)
            self.assertAlmostEqual(galacticAvList_1[ix], testList.galacticAvList[ix], 10)
            self.assertAlmostEqual(redshiftList_1[ix], testList.redshiftList[ix], 10)

        for ix, (name, norm, iav, gav, zz) in \
        enumerate(zip(sedNameList_1, magNormList_1, internalAvList_1, \
                      galacticAvList_1, redshiftList_1)):

            sedControl = Sed()
            sedControl.readSED_flambda(os.path.join(self.sedDir, name+'.gz'))

            fnorm = sedControl.calcFluxNorm(norm, imsimBand)
            sedControl.multiplyFluxNorm(fnorm)

            a_coeff, b_coeff = sedControl.setupCCMab()
            sedControl.addCCMDust(a_coeff, b_coeff, A_v=iav)

            sedControl.redshiftSED(zz, dimming=True)
            sedControl.resampleSED(wavelen_match=wavelen_match)

            a_coeff, b_coeff = sedControl.setupCCMab()
            sedControl.addCCMDust(a_coeff, b_coeff, A_v=gav)

            sedTest = testList[ix]

            numpy.testing.assert_array_equal(sedControl.wavelen, sedTest.wavelen)
            numpy.testing.assert_array_equal(sedControl.flambda, sedTest.flambda)
            numpy.testing.assert_array_equal(sedControl.fnu, sedTest.fnu)