Esempio n. 1
0
    def model_photo(self, tt_arr, zred=0.1, filters=None, bands=None): 
        ''' very simple wrapper for a fsps model with minimal overhead. Generates photometry 
        in specified photometric bands 

        :param tt_arr:
            array of free parameters

        :param zred:
            redshift (default: 0.1) 

        :param filters:             
            speclite.filters filter object. Either filters or bands has to be specified. (default: None) 

        :param bands: (optional) 
            photometric bands to generate the photometry. Either bands or filters has to be 
            specified. (default: None)  

        :return outphoto:
            array of photometric fluxes in nanomaggies in the specified bands 
        '''
        if filters is None: 
            if bands is not None: 
                bands_list = self._get_bands(bands) # get list of bands 
                filters = specFilter.load_filters(*tuple(bands_list))
            else: 
                raise ValueError("specify either filters or bands") 

        w, spec = self.model(tt_arr, zred=zred) # get spectra  
    
        maggies = filters.get_ab_maggies(spec * 1e-17*U.erg/U.s/U.cm**2/U.Angstrom, wavelength=w.flatten()*U.Angstrom) # maggies 
        return np.array(list(maggies[0])) * 1e9
Esempio n. 2
0
    def __init__(self, nproc=1):
        from speclite import filters
        from scipy.spatial import KDTree

        self.nproc = nproc

        self.bgs_meta = read_basis_templates(objtype='BGS', onlymeta=True)
        self.elg_meta = read_basis_templates(objtype='ELG', onlymeta=True)
        self.lrg_meta = read_basis_templates(objtype='LRG', onlymeta=True)
        self.qso_meta = read_basis_templates(objtype='QSO', onlymeta=True)
        self.wd_da_meta = read_basis_templates(objtype='WD', subtype='DA', onlymeta=True)
        self.wd_db_meta = read_basis_templates(objtype='WD', subtype='DB', onlymeta=True)

        self.decamwise = filters.load_filters('decam2014-g', 'decam2014-r', 'decam2014-z',
                                              'wise2010-W1', 'wise2010-W2')

        # Read all the stellar spectra and synthesize DECaLS/WISE fluxes.
        self.star_phot()

        #self.elg_phot()
        #self.elg_kcorr = read_basis_templates(objtype='ELG', onlykcorr=True)

        self.bgs_tree = KDTree(self._bgs())
        self.elg_tree = KDTree(self._elg())
        #self.lrg_tree = KDTree(self._lrg())
        #self.qso_tree = KDTree(self._qso())
        self.star_tree = KDTree(self._star())
        self.wd_da_tree = KDTree(self._wd_da())
        self.wd_db_tree = KDTree(self._wd_db())
Esempio n. 3
0
def _get_decam_filters():
    global decam_filters
    if decam_filters is None:
        log = get_logger()
        log.info("read decam filters")
        decam_filters = filters.load_filters("decam2014-g", "decam2014-r",
                                             "decam2014-z")
    return decam_filters
Esempio n. 4
0
    def __init__(self, library_file):
        """
        holds all the observatories/instruments/filters


        :param library_file:
        """

        # get the filter file

        with open(library_file) as f:

            self._library = yaml.load(f, Loader=yaml.SafeLoader)

        self._instruments = []

        # create attributes which are lib.observatory.instrument
        # and the instrument attributes are speclite FilterResponse objects

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")

            print("Loading optical filters")

            for observatory, value in self._library.items():

                # create a node for the observatory
                this_node = ObservatoryNode(value)

                # attach it to the object

                setattr(self, observatory, this_node)

                # now get the instruments

                for instrument, value2 in value.items():

                    # update the instruments

                    self._instruments.append(instrument)

                    # create the filter response via speclite

                    filter_path = os.path.join(
                        get_speclite_filter_path(), observatory, instrument
                    )

                    filters_to_load = [
                        "%s-%s.ecsv" % (filter_path, filter) for filter in value2
                    ]

                    this_filter = spec_filter.load_filters(*filters_to_load)

                    # attach the filters to the observatory

                    setattr(this_node, instrument, this_filter)

        self._instruments.sort()
Esempio n. 5
0
    def __init__(self, library_file):
        """
        holds all the observatories/instruments/filters


        :param library_file:
        """

        # get the filter file

        with open(library_file) as f:

            self._library = yaml.safe_load(f)

        self._instruments = []

        # create attributes which are lib.observatory.instrument
        # and the instrument attributes are speclite FilterResponse objects

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")

            print('Loading optical filters')

            for observatory, value in self._library.iteritems():

                # create a node for the observatory
                this_node = ObservatoryNode(value)

                # attach it to the object

                setattr(self, observatory, this_node)

                # now get the instruments

                for instrument, value2 in value.iteritems():


                    # update the instruments

                    self._instruments.append(instrument)

                    # create the filter response via speclite

                    filter_path = os.path.join(get_speclite_filter_path(), observatory, instrument)

                    filters_to_load = ["%s-%s.ecsv" % (filter_path, filter) for filter in value2]

                    this_filter = spec_filter.load_filters(*filters_to_load)

                    # attach the filters to the observatory

                    setattr(this_node, instrument, this_filter)

        self._instruments.sort()
Esempio n. 6
0
def ellipse_sbprofile(ellipsefit, band=('g', 'r', 'z'), refband='r',
                      minerr=0.02, redshift=None, pixscale=0.262):
    """Convert ellipse-fitting results to a magnitude, color, and surface brightness
    profiles.

    """
    if redshift:
        from astropy.cosmology import WMAP9 as cosmo
        smascale = pixscale / cosmo.arcsec_per_kpc_proper(redshift).value # [kpc/pixel]
        smaunit = 'kpc'
    else:
        smascale = 1.0
        smaunit = 'pixels'

    indx = np.ones(len(ellipsefit[refband]), dtype=bool)

    sbprofile = dict()
    sbprofile['smaunit'] = smaunit
    sbprofile['sma'] = ellipsefit['r'].sma[indx] * smascale

    with np.errstate(invalid='ignore'):
        for filt in band:
            #area = ellipsefit[filt].sarea[indx] * pixscale**2

            sbprofile['mu_{}'.format(filt)] = 22.5 - 2.5 * np.log10(ellipsefit[filt].intens[indx])

            #sbprofile[filt] = 22.5 - 2.5 * np.log10(ellipsefit[filt].intens[indx])
            sbprofile['mu_{}_err'.format(filt)] = ellipsefit[filt].int_err[indx] / \
              ellipsefit[filt].intens[indx] / np.log(10)

            #sbprofile['mu_{}'.format(filt)] = sbprofile[filt] + 2.5 * np.log10(area)

            # Just for the plot use a minimum uncertainty
            #sbprofile['{}_err'.format(filt)][sbprofile['{}_err'.format(filt)] < minerr] = minerr

    sbprofile['gr'] = sbprofile['mu_g'] - sbprofile['mu_r']
    sbprofile['rz'] = sbprofile['mu_r'] - sbprofile['mu_z']
    sbprofile['gr_err'] = np.sqrt(sbprofile['mu_g_err']**2 + sbprofile['mu_r_err']**2)
    sbprofile['rz_err'] = np.sqrt(sbprofile['mu_r_err']**2 + sbprofile['mu_z_err']**2)

    # Just for the plot use a minimum uncertainty
    sbprofile['gr_err'][sbprofile['gr_err'] < minerr] = minerr
    sbprofile['rz_err'][sbprofile['rz_err'] < minerr] = minerr

    # Add the effective wavelength of each bandpass, although this needs to take
    # into account the DECaLS vs BASS/MzLS filter curves.
    from speclite import filters
    filt = filters.load_filters('decam2014-g', 'decam2014-r', 'decam2014-z', 'wise2010-W1', 'wise2010-W2')
    for ii, band in enumerate(('g', 'r', 'z', 'W1', 'W2')):
        sbprofile.update({'{}_wave_eff'.format(band): filt.effective_wavelengths[ii].value})

    return sbprofile
Esempio n. 7
0
def test_filter_set():

    sf = spec_filters.load_filters('bessell-*')

    fs1 = FilterSet(sf)

    #sf = spec_filters.load_filter('bessell-r')

    #fs2 = FilterSet(sf)

    with pytest.raises(NotASpeclikeFilter):

        fs2 = FilterSet('a')
def test_filter_set():

    sf = spec_filters.load_filters("bessell-*")

    fs1 = FilterSet(sf)

    # sf = spec_filters.load_filter('bessell-r')

    # fs2 = FilterSet(sf)

    with pytest.raises(NotASpeclikeFilter):

        fs2 = FilterSet("a")
Esempio n. 9
0
def Photo_DESI(wave, spectra):
    ''' generate photometry by convolving the input spectrum with DECAM and WISE 
    bandpasses: g, r, z, W1, W2, W3, W4 filters. 

    :param wave: 
        wavelength of input spectra in Angstroms. 2D array Nspec x Nwave.

    :param fluxes: 
        fluxes of input spectra. This should be noiseless source spectra. 
        2D array Nspec x Nwave. In units of 10e-17 erg/s/cm2/A 
    '''
    wave = np.atleast_2d(wave)
    assert wave.shape[1] == spectra.shape[1]

    n_spec = spectra.shape[0]  # number of spectra
    if wave.shape[0] == 1: wave = np.tile(wave, (n_spec, 1))

    from astropy import units as U

    # load DECAM g, r, z and WISE W1-4
    filter_response = specFilter.load_filters('decam2014-g', 'decam2014-r',
                                              'decam2014-z', 'wise2010-W1',
                                              'wise2010-W2', 'wise2010-W3',
                                              'wise2010-W4')

    # apply filters
    fluxes = np.zeros((n_spec, 7))  # photometric flux in nanomaggies
    for i in range(n_spec):
        spectrum = spectra[i]

        # apply filters
        flux = np.array(
            filter_response.get_ab_maggies(
                np.atleast_2d(spectrum) * 1e-17 * U.erg / U.s / U.cm**2 /
                U.Angstrom, wave[i, :] * U.Angstrom))
        # convert to nanomaggies
        fluxes[i, :] = 1e9 * np.array([
            flux[0][0], flux[0][1], flux[0][2], flux[0][3], flux[0][4],
            flux[0][5], flux[0][6]
        ])

    # calculate magnitudes (not advised due to NaNs)
    mags = 22.5 - 2.5 * np.log10(fluxes)
    return fluxes, mags
Esempio n. 10
0
    def __init__(self, lam, flam, family='sdss2010-*', axis=0,
                 redshift=None):

        self.filters = filters.load_filters(family)

        if redshift is not None:
            self.filters = filters.FilterSequence(
                [f_.create_shifted(band_shift=redshift)
                 for f_ in self.filters])
        else:
            pass
        # spectral dimension has to be the final one
        nl0 = flam.shape[axis]
        flam, self.lam = self.filters.pad_spectrum(
            spectrum=np.moveaxis(flam, axis, -1),
            wavelength=lam, method='zero')
        self.flam = np.moveaxis(flam, -1, axis)
        if self.flam.shape[axis] > nl0:
            warn('spectrum has been padded, bad mags possible',
                 Spec2PhotWarning)

        self.ABmags = self.filters.get_ab_magnitudes(
            spectrum=self.flam, wavelength=self.lam,
            axis=axis).as_array()
Esempio n. 11
0
    def __init__(self, lam, flam, family='sdss2010-*', axis=0, redshift=None):

        self.filters = filters.load_filters(family)

        if redshift is not None:
            self.filters = filters.FilterSequence([
                f_.create_shifted(band_shift=redshift) for f_ in self.filters
            ])
        else:
            pass
        # spectral dimension has to be the final one
        nl0 = flam.shape[axis]
        flam, self.lam = self.filters.pad_spectrum(spectrum=np.moveaxis(
            flam, axis, -1),
                                                   wavelength=lam,
                                                   method='zero')
        self.flam = np.moveaxis(flam, -1, axis)
        if self.flam.shape[axis] > nl0:
            warn('spectrum has been padded, bad mags possible',
                 Spec2PhotWarning)

        self.ABmags = self.filters.get_ab_magnitudes(spectrum=self.flam,
                                                     wavelength=self.lam,
                                                     axis=axis).as_array()
Esempio n. 12
0
def PCA_stellar_mass(dapall,
                     plateifu=None,
                     filename=None,
                     vec_file=None,
                     vec_data=None,
                     pca_data_dir=None,
                     goodfrac_channel=2,
                     goodfrac_thresh=.0001,
                     use_mask=True):
    """
    Return absolute AB Magnitude in filter provided

    Parameters
    ----------
    dapall: 'Table', 'dict'
        DAPALL file data
    plateifu: 'str', list, optional, must be keyword
        plate-ifu of galaxy desired
    filename: 'str', optional, must be keyword
        pca data file to read in, ignores plateifu if provided
    vec_file: 'str', optional, must be keyword
        pca data file containing eigenvectors
    vec_data: 'tuple', optional, must be keyword
        eigenvector data (mean_spec, evec_spec, lam_spec)
    """

    if filename is None:
        if plateifu is None:
            plateifu = dapall["plateifu"]
        else:
            filename = os.path.join(pca_data_dir, plateifu,
                                    "{}_res.fits".format(plateifu))

    filter_obs = filters.load_filters("sdss2010-i")
    i_mag_abs = PCA_mag(dapall,
                        filter_obs,
                        plateifu=plateifu,
                        filename=filename,
                        vec_file=vec_file,
                        vec_data=vec_data,
                        pca_data_dir=pca_data_dir)

    sun_i = absmag_sun_band["i"] * u.ABmag
    i_sol_lum = 10**(-0.4 * (i_mag_abs - sun_i).value)

    # Load PCA Data for Galaxy
    if filename is None:
        filename = os.path.join(pca_data_dir, plateifu,
                                "{}_res.fits".format(plateifu))
    with fits.open(filename) as pca_data:
        MLi = pca_data["MLi"].data
        mask = pca_data["MASK"].data.astype(bool)
        goodfrac = pca_data["GOODFRAC"].data[goodfrac_channel]
    m_star = i_sol_lum * 10**MLi
    mask = mask | (goodfrac < goodfrac_thresh)

    mask_shaped = np.zeros_like(m_star, dtype=bool)
    if mask_shaped.shape[0] == 3:
        mask_shaped[0, :, :] = mask
        mask_shaped[1, :, :] = mask
        mask_shaped[1, :, :] = mask
    else:
        mask_shaped = mask

    m_star_masked = np.ma.masked_array(m_star * u.solMass, mask=mask_shaped)

    return m_star_masked
Esempio n. 13
0
def PCA_mag(dapall,
            filter_obs,
            plateifu=None,
            filename=None,
            vec_file=None,
            vec_data=None,
            pca_data_dir=None):
    """
    Return absolute AB Magnitude in filter provided

    Parameters
    ----------
    dapall: 'Table', 'dict'
        DAPALL file data
    filter_obs: 'str', 'speclite.filters.FilterSequence'
        observational filter to use
    plateifu: 'str', list, optional, must be keyword
        plate-ifu of galaxy desired
    filename: 'str', optional, must be keyword
        pca data file to read in, ignores plateifu if provided
    vec_file: 'str', optional, must be keyword
        pca data file containing eigenvectors
    vec_data: 'tuple', optional, must be keyword
        eigenvector data (mean_spec, evec_spec, lam_spec)
    """

    # Check filter status

    # CHECK PLATEIFU
    if plateifu is None:
        plateifu = dapall["plateifu"]

    if filter_obs.__class__ is not filters.FilterSequence:
        if filter_obs in ["GALEX-NUV", "GALEX-FUV"]:
            wav, resp = np.loadtxt(
                "{}/data/GALEX_GALEX.NUV.dat".format(directory)).T
            galex_nuv = filters.FilterResponse(wavelength=wav * u.Angstrom,
                                               response=resp,
                                               meta=dict(group_name='GALEX',
                                                         band_name='NUV'))

            wav, resp = np.loadtxt(
                "{}/data/GALEX_GALEX.FUV.dat".format(directory)).T
            galex_fuv = filters.FilterResponse(wavelength=wav * u.Angstrom,
                                               response=resp,
                                               meta=dict(group_name='GALEX',
                                                         band_name='FUV'))
        try:
            filter_obs = filters.load_filters(filter_obs)
        except ValueError:
            logging.warnings("Invalid filter, using default of 'sdss2010-i'")
            filter_obs = filters.load_filters("sdss2010-i")

    if filename is None:
        if plateifu is None:
            raise ValueError("No input file or plateifu provided")
        else:
            filename = os.path.join(pca_data_dir, plateifu,
                                    "{}_res.fits".format(plateifu))

    spectrum, wlen = PCA_Spectrum(plateifu=plateifu,
                                  filename=filename,
                                  vec_file=vec_file,
                                  vec_data=vec_data,
                                  pca_data_dir=pca_data_dir)

    mag = filter_obs.get_ab_magnitudes(
        spectrum, wlen, axis=0)[filter_obs.names[0]].data * u.ABmag
    mag_abs = mag - WMAP9.distmod(dapall["nsa_zdist"])

    return mag_abs
Esempio n. 14
0
def get_spectra(lyafile,
                nqso=None,
                wave=None,
                templateid=None,
                normfilter='sdss2010-g',
                seed=None,
                rand=None,
                qso=None,
                add_dlas=False,
                debug=False,
                nocolorcuts=True):
    """Generate a QSO spectrum which includes Lyman-alpha absorption.

    Args:
        lyafile (str): name of the Lyman-alpha spectrum file to read.
        nqso (int, optional): number of spectra to generate (starting from the
          first spectrum; if more flexibility is needed use TEMPLATEID).
        wave (numpy.ndarray, optional): desired output wavelength vector.
        templateid (int numpy.ndarray, optional): indices of the spectra
          (0-indexed) to read from LYAFILE (default is to read everything).  If
          provided together with NQSO, TEMPLATEID wins.
        normfilter (str, optional): normalization filter
        seed (int, optional): Seed for random number generator.
        rand (numpy.RandomState, optional): RandomState object used for the
          random number generation.  If provided together with SEED, this
          optional input superseeds the numpy.RandomState object instantiated by
          SEED.
        qso (desisim.templates.QSO, optional): object with which to generate
          individual spectra/templates.
        add_dlas (bool): Inject damped Lya systems into the Lya forest
          These are done according to the current best estimates for the incidence dN/dz
          (Prochaska et al. 2008, ApJ, 675, 1002)
          Set in calc_lz
          These are *not* inserted according to overdensity along the sightline
        nocolorcuts (bool, optional): Do not apply the fiducial rzW1W2 color-cuts
          cuts (default True).

    Returns (flux, wave, meta, dla_meta) where:

        * flux (numpy.ndarray): Array [nmodel, npix] of observed-frame spectra
          (erg/s/cm2/A).
        * wave (numpy.ndarray): Observed-frame [npix] wavelength array (Angstrom).
        * meta (astropy.Table): Table of meta-data [nmodel] for each output spectrum
          with columns defined in desisim.io.empty_metatable *plus* RA, DEC.
        * objmeta (astropy.Table): Table of additional object-specific meta-data
          [nmodel] for each output spectrum with columns defined in
          desisim.io.empty_metatable.
        * dla_meta (astropy.Table): Table of meta-data [ndla] for the DLAs injected
          into the spectra.  Only returned if add_dlas=True

    Note: `dla_meta` is only included if add_dlas=True.

    """
    from scipy.interpolate import interp1d

    import fitsio

    from speclite.filters import load_filters
    from desisim.templates import QSO
    from desisim.io import empty_metatable

    h = fitsio.FITS(lyafile)
    if templateid is None:
        if nqso is None:
            nqso = len(h) - 1
        templateid = np.arange(nqso)
    else:
        templateid = np.asarray(templateid)
        nqso = len(np.atleast_1d(templateid))

    if rand is None:
        rand = np.random.RandomState(seed)
    templateseed = rand.randint(2**32, size=nqso)

    #heads = [head.read_header() for head in h[templateid + 1]]
    heads = []
    for indx in templateid:
        heads.append(h[indx + 1].read_header())

    zqso = np.array([head['ZQSO'] for head in heads])
    ra = np.array([head['RA'] for head in heads])
    dec = np.array([head['DEC'] for head in heads])
    mag_g = np.array([head['MAG_G'] for head in heads])

    # Hard-coded filtername!  Should match MAG_G!
    normfilt = load_filters(normfilter)

    if qso is None:
        qso = QSO(normfilter_south=normfilter, wave=wave)

    wave = qso.wave
    flux = np.zeros([nqso, len(wave)], dtype='f4')

    meta, objmeta = empty_metatable(objtype='QSO', nmodel=nqso)
    meta['TEMPLATEID'][:] = templateid
    meta['REDSHIFT'][:] = zqso
    meta['MAG'][:] = mag_g
    meta['MAGFILTER'][:] = normfilter
    meta['SEED'][:] = templateseed
    meta['RA'] = ra
    meta['DEC'] = dec

    # Lists for DLA meta data
    if add_dlas:
        dla_NHI, dla_z, dla_id = [], [], []

    # Loop on quasars
    for ii, indx in enumerate(templateid):
        flux1, _, meta1, objmeta1 = qso.make_templates(
            nmodel=1,
            redshift=np.atleast_1d(zqso[ii]),
            mag=np.atleast_1d(mag_g[ii]),
            seed=templateseed[ii],
            nocolorcuts=nocolorcuts,
            lyaforest=False)
        flux1 *= 1e-17
        for col in meta1.colnames:
            meta[col][ii] = meta1[col][0]
        for col in objmeta1.colnames:
            objmeta[col][ii] = objmeta1[col][0]

        # read lambda and forest transmission
        data = h[indx + 1].read()
        la = data['LAMBDA'][:]
        tr = data['FLUX'][:]

        if len(tr):
            # Interpolate the transmission at the spectral wavelengths, if
            # outside the forest, the transmission is 1.
            itr = interp1d(la, tr, bounds_error=False, fill_value=1.0)
            flux1 *= itr(wave)

        # Inject a DLA?
        if add_dlas:
            if np.min(wave / lambda_RF_LYA - 1) < zqso[ii]:  # Any forest?
                dlas, dla_model = insert_dlas(wave,
                                              zqso[ii],
                                              seed=templateseed[ii])
                ndla = len(dlas)
                if ndla > 0:
                    flux1 *= dla_model
                    # Meta
                    dla_z += [idla['z'] for idla in dlas]
                    dla_NHI += [idla['N'] for idla in dlas]
                    dla_id += [indx] * ndla

        padflux, padwave = normfilt.pad_spectrum(flux1, wave, method='edge')
        normmaggies = np.array(
            normfilt.get_ab_maggies(padflux, padwave,
                                    mask_invalid=True)[normfilter])

        factor = 10**(-0.4 * mag_g[ii]) / normmaggies
        flux1 *= factor
        for key in ('FLUX_G', 'FLUX_R', 'FLUX_Z', 'FLUX_W1', 'FLUX_W2'):
            meta[key][ii] *= factor
        flux[ii, :] = flux1[:]

    h.close()

    # Finish
    if add_dlas:
        ndla = len(dla_id)
        if ndla > 0:
            from astropy.table import Table
            dla_meta = Table()
            dla_meta['NHI'] = dla_NHI  # log NHI values
            dla_meta['z'] = dla_z
            dla_meta['ID'] = dla_id
        else:
            dla_meta = None
        return flux * 1e17, wave, meta, objmeta, dla_meta
    else:
        return flux * 1e17, wave, meta, objmeta
Esempio n. 15
0
def get_spectra(lyafile,
                nqso=None,
                wave=None,
                templateid=None,
                normfilter='sdss2010-g',
                seed=None,
                rand=None,
                qso=None,
                nocolorcuts=False):
    '''Generate a QSO spectrum which includes Lyman-alpha absorption.

    Args:
        lyafile (str): name of the Lyman-alpha spectrum file to read.
        nqso (int, optional): number of spectra to generate (starting from the
          first spectrum; if more flexibility is needed use TEMPLATEID).
        wave (numpy.ndarray, optional): desired output wavelength vector.
        templateid (int numpy.ndarray, optional): indices of the spectra
          (0-indexed) to read from LYAFILE (default is to read everything).  If
          provided together with NQSO, TEMPLATEID wins.
        normfilter (str, optional): normalization filter
        seed (int, optional): Seed for random number generator.
        rand (numpy.RandomState, optional): RandomState object used for the
          random number generation.  If provided together with SEED, this
          optional input superseeds the numpy.RandomState object instantiated by
          SEED.
        qso (desisim.templates.QSO, optional): object with which to generate
          individual spectra/templates.
        nocolorcuts (bool, optional): Do not apply the fiducial rzW1W2 color-cuts
          cuts (default False).

    Returns:
        flux (numpy.ndarray):
            Array [nmodel, npix] of observed-frame spectra (erg/s/cm2/A).

        wave (numpy.ndarray):
            Observed-frame [npix] wavelength array (Angstrom).

        meta (astropy.Table):
            Table of meta-data [nmodel] for each output spectrum
            with columns defined in desisim.io.empty_metatable *plus* RA, DEC.

    '''
    import numpy as np
    from scipy.interpolate import interp1d

    import fitsio

    from speclite.filters import load_filters
    from desisim.templates import QSO
    from desisim.io import empty_metatable

    h = fitsio.FITS(lyafile)
    if templateid is None:
        if nqso is None:
            nqso = len(h) - 1
        templateid = np.arange(nqso)
    else:
        templateid = np.asarray(templateid)
        nqso = len(templateid)

    if rand is None:
        rand = np.random.RandomState(seed)
    templateseed = rand.randint(2**32, size=nqso)

    #heads = [head.read_header() for head in h[templateid + 1]]
    heads = []
    for indx in templateid:
        heads.append(h[indx + 1].read_header())

    zqso = np.array([head['ZQSO'] for head in heads])
    ra = np.array([head['RA'] for head in heads])
    dec = np.array([head['DEC'] for head in heads])
    mag_g = np.array([head['MAG_G'] for head in heads])

    # Hard-coded filtername!
    normfilt = load_filters(normfilter)

    if qso is None:
        qso = QSO(normfilter=normfilter, wave=wave)

    wave = qso.wave
    flux = np.zeros([nqso, len(wave)], dtype='f4')

    meta = empty_metatable(objtype='QSO', nmodel=nqso)
    meta['TEMPLATEID'] = templateid
    meta['REDSHIFT'] = zqso
    meta['MAG'] = mag_g
    meta['SEED'] = templateseed
    meta['RA'] = ra
    meta['DEC'] = dec

    for ii, indx in enumerate(templateid):
        flux1, _, meta1 = qso.make_templates(nmodel=1,
                                             redshift=np.atleast_1d(zqso[ii]),
                                             mag=np.atleast_1d(mag_g[ii]),
                                             seed=templateseed[ii],
                                             nocolorcuts=nocolorcuts)
        flux1 *= 1e-17
        for col in meta1.colnames:
            meta[col][ii] = meta1[col][0]

        # read lambda and forest transmission
        data = h[indx + 1].read()
        la = data['LAMBDA'][:]
        tr = data['FLUX'][:]

        if len(tr):
            # Interpolate the transmission at the spectral wavelengths, if
            # outside the forest, the transmission is 1.
            itr = interp1d(la, tr, bounds_error=False, fill_value=1.0)
            flux1 *= itr(wave)

        padflux, padwave = normfilt.pad_spectrum(flux1, wave, method='edge')
        normmaggies = np.array(
            normfilt.get_ab_maggies(padflux, padwave,
                                    mask_invalid=True)[normfilter])
        factor = 10**(-0.4 * mag_g[ii]) / normmaggies
        flux1 *= factor
        for key in ('FLUX_G', 'FLUX_R', 'FLUX_Z', 'FLUX_W1', 'FLUX_W2'):
            meta[key][ii] *= factor

        flux[ii, :] = flux1[:]

    h.close()

    return flux, wave, meta
Esempio n. 16
0
def mag_ab(wavelength,
           spectrum,
           filters,
           *,
           redshift=None,
           coefficients=None,
           distmod=None,
           interpolate=1000):
    r'''Compute AB magnitudes from spectra and filters.

    This function takes *emission* spectra and observation filters and computes
    bandpass AB magnitudes [1]_.

    The filter specification in the `filters` argument is passed unchanged to
    `speclite.filters.load_filters`. See there for the syntax, and the list of
    supported values.

    The emission spectra can optionally be redshifted. If the `redshift`
    parameter is given, the output array will have corresponding axes. If the
    `interpolate` parameter is not `False`, at most that number of redshifted
    spectra are computed, and the remainder is interpolated from the results.

    The spectra can optionally be combined. If the `coefficients` parameter is
    given, its shape must match `spectra`, and the corresponding axes are
    contracted using a product sum. If the spectra are redshifted, the
    coefficients array can contain axes for each redshift.

    By default, absolute magnitudes are returned. To compute apparent magnitudes
    instead, provide the `distmod` argument with the distance modulus for each
    redshift. The distance modulus is applied after redshifts and coefficients
    and should match the shape of the `redshift` array.

    Parameters
    ----------
    wavelength : (nw,) `~astropy.units.Quantity` or array_like
        Wavelength array of the spectrum.
    spectrum : ([ns,] nw,) `~astropy.units.Quantity` or array_like
        Emission spectrum. Can be multidimensional for computing with multiple
        spectra of the same wavelengths. The last axis is the wavelength axis.
    filters : str or list of str
        Filter specification, loaded filters are array_like of shape (nf,).
    redshift : (nz,) array_like, optional
        Optional array of redshifts. Can be multidimensional.
    coefficients : ([nz,] [ns,]) array_like
        Optional coefficients for combining spectra. Axes must be compatible
        with all redshift and spectrum dimensions.
    distmod : (nz,) array_like, optional
        Optional distance modulus for each redshift. Shape must be compatible
        with redshift dimensions.
    interpolate : int or `False`, optional
        Maximum number of redshifts to compute explicitly. Default is `1000`.

    Returns
    -------
    mag_ab : ([nz,] [ns,] nf,) array_like
        The AB magnitude of each redshift (if given), each spectrum (if not
        combined), and each filter.

    Warnings
    --------
    The :mod:`speclite` package must be installed to use this function.

    References
    ----------
    .. [1] M. R. Blanton et al., 2003, AJ, 125, 2348

    '''
    from speclite.filters import load_filters

    # load the filters
    if np.ndim(filters) == 0:
        filters = (filters, )
    filters = load_filters(*filters)
    if np.shape(filters) == (1, ):
        filters = filters[0]

    # number of dimensions for each input
    nd_s = len(np.shape(spectrum)[:-1])  # last axis is spectral axis
    nd_f = len(np.shape(filters))
    nd_z = len(np.shape(redshift))

    # check if interpolation is necessary
    if interpolate and np.size(redshift) <= interpolate:
        interpolate = False

    # if interpolating, split the redshift range into `interpolate` bits
    if interpolate:
        redshift_ = np.linspace(np.min(redshift), np.max(redshift),
                                interpolate)
    else:
        redshift_ = redshift if redshift is not None else 0

    # working array shape
    m_shape = np.shape(redshift_) + np.shape(spectrum)[:-1] + np.shape(filters)

    # compute AB maggies for every redshift, spectrum, and filter
    m = np.empty(m_shape)
    for i, z in np.ndenumerate(redshift_):
        for j, f in np.ndenumerate(filters):
            # create a shifted filter for redshift
            fs = f.create_shifted(z)
            m[i + (..., ) + j] = fs.get_ab_maggies(spectrum, wavelength)

    # if interpolating, compute the full set of redshifts
    if interpolate:
        # diy interpolation keeps memory use to a minimum
        dm = np.diff(m, axis=0, append=m[-1:])
        u, n = np.modf(
            np.interp(redshift, redshift_, np.arange(redshift_.size)))
        n = n.astype(int)
        u = u.reshape(u.shape + (1, ) * (nd_s + nd_f))
        m = np.ascontiguousarray(m[n])
        m += u * dm[n]
        del (dm, n, u)

    # combine spectra if asked to
    if coefficients is not None:
        # contraction over spectrum axes (`nd_z` to `nd_z+nd_s`)
        if nd_z == 0:
            m = np.matmul(coefficients, m)
        else:
            c = np.reshape(coefficients, np.shape(coefficients) + (1, ) * nd_f)
            m = np.sum(m * c, axis=tuple(range(nd_z, nd_z + nd_s)))
        # no spectrum axes left
        nd_s = 0

    # convert maggies to magnitudes
    np.log10(m, out=m)
    m *= -2.5

    # apply the redshift K-correction if necessary
    if redshift is not None:
        kcorr = -2.5 * np.log10(1 + redshift)
        m += np.reshape(kcorr, kcorr.shape + (1, ) * (nd_s + nd_f))

    # add distance modulus if given
    if distmod is not None:
        m += np.reshape(distmod, np.shape(distmod) + (1, ) * (nd_s + nd_f))

    # done
    return m
Esempio n. 17
0
    # [$10^{-17} erg/cm^{2}/s/\AA/arcsec^2$]
    return twi_wave, Isky


if __name__ == '__main__':
    import pylab as pl

    start = time.time()

    # specsim.
    config = specsim.config.load_config('desi')
    simulator = specsim.simulator.Simulator('desi')

    simulator.simulate()

    rfilter = filters.load_filters('decam2014-r')

    gfa_files = glob.glob(
        '/global/cfs/cdirs/desi/users/ameisner/GFA/conditions/offline_all_guide_ccds_SV1-thru_*.fits'
    )
    gfas = Table()

    for x in gfa_files:
        # gfas        = resource_filename('bgs-cmxsv', 'dat/offline_all_guide_ccds_SV1-thru_20210111.fits')
        x = Table.read(x)

        gfas = vstack((gfas, x))

    #
    gfas = gfas[gfas['N_SOURCES_FOR_PSF'] > 2]
    gfas = gfas[gfas['CONTRAST'] > 2]
Esempio n. 18
0
def Lgal_noisePhoto(lib='bc03', dust=False, overwrite=False, validate=False): 
    ''' generate photometry from noiseless spectral_challenge Lgal spectra 
    generated by Rita then add realistic noise from Legacy survey.
    '''
    fsource = f_nonoise(4, lib=lib)
    fsource = os.path.basename(fsource).rsplit('.', 1)[0].rsplit('_BGS_template_')[1]
    if dust: str_dust = 'dust'
    else: str_dust = 'nodust'
    fphot = os.path.join(UT.dat_dir(), 'spectral_challenge', 'bgs', 
            'mag.%s.%s.legacy_noise.dat' % (fsource, str_dust))

    if os.path.isfile(fphot) and not overwrite: 
        _mags = np.loadtxt(fphot, unpack=True, skiprows=1, usecols=[-7, -6, -5, -4, -3, -2, -1])
        mags = _mags.T
    else: 
        galids = np.unique(testGalIDs()) # IDs of unique spectral_challenge spectra 
        
        mags = np.zeros((len(galids), 7)) 
        for i, gid in enumerate(galids): 
            # read ins ource spectra
            spec_source = Lgal_nonoiseSpectra(gid, lib=lib)
            if dust: 
                flux = spec_source['flux_dust_nonoise']
            else: 
                flux = spec_source['flux_nodust_nonoise']
            # apply filters
            filter_response = specFilter.load_filters('decam2014-g', 'decam2014-r', 'decam2014-z', 
                    'wise2010-W1', 'wise2010-W2', 'wise2010-W3', 'wise2010-W4')
            mags_i = filter_response.get_ab_magnitudes(flux*U.Watt/U.m**2/U.Angstrom, spec_source['wave']*U.Angstrom)
            mags[i,:] = np.array([mags_i[0][0], mags_i[0][1], mags_i[0][2], mags_i[0][3], 
                mags_i[0][4], mags_i[0][5], mags_i[0][6]]) # this is because mags_i is an astropy table. ugh 
        fluxs = fUT.mag2flux(mags, method='log') 

        # add in noise from legacy 
        cats = Cats.GamaLegacy() 
        gleg = cats.Read('g15') 
        for ib, band in enumerate(['g', 'r', 'z', 'w1', 'w2', 'w3', 'w4']): 
            _flux = gleg['legacy-photo']['flux_%s' % band] 
            _ivar = gleg['legacy-photo']['flux_ivar_%s' % band]
            if ib == 0: 
                gleg_fluxs = np.zeros((len(_flux), 7))
                gleg_ivars = np.zeros((len(_flux), 7))

            gleg_fluxs[:,ib] = _flux
            gleg_ivars[:,ib] = _ivar
            
        tree = KDTree(gleg_fluxs[:,:5]) 
        dist, indx = tree.query(fluxs[:,:5])
        ivars = np.zeros_like(mags)
        ivars = gleg_ivars[indx,:] 
        # now lets apply noise to thse mags 
        sig = ivars**-0.5
        fluxs += sig * np.random.randn(sig.shape[0], sig.shape[1]) # noisy flux 
        noisy_mags = fUT.flux2mag(fluxs) 
        
        hdr = 'galid, flux_g, flux_r, flux_z, flux_w1, flux_w2, flux_w3, flux_w4, flux_ivar_g, flux_ivar_r, flux_ivar_z, flux_ivar_w1, flux_ivar_w2, flux_ivar_w3, flux_ivar_w4, mag_g, mag_r, mag_z, mag_w1, mag_w2, mag_w3, mag_w4'
        fmt = ['%.5e' for i in range(22)]
        fmt[0] = '%i'
        np.savetxt(fphot, np.vstack([galids, fluxs.T, ivars.T, noisy_mags.T]).T, header=hdr, 
                fmt=fmt) 

    if validate: # compare the Lgal nonoise photometry to photometry from GAMA-Legacy 
        cats = Cats.GamaLegacy() 
        gleg = cats.Read('g15') 
        # histogram of magnitudes
        fig = plt.figure(figsize=(20,4)) 
        for i_b, band in enumerate(['g', 'r', 'z', 'w1', 'w2']): 
            sub = fig.add_subplot(1,5,i_b+1) 
            sub.hist(fUT.flux2mag(gleg['legacy-photo']['flux_%s' % band]), color='k', range=(14,25), density=True, label='Legacy')
            sub.hist(mags[:,i_b], color='C1', range=(14, 25), density=True, alpha=0.5, label='LGal\nSpectral\nChallenge')
            sub.set_xlabel('%s magnitude' % band, fontsize=20) 
            sub.set_xlim(14, 25) 
        sub.legend(loc='upper right', fontsize=15) 
        fig.savefig(os.path.join(UT.fig_dir(), os.path.basename(fphot).replace('dat', 'hist.png')), bbox_inches='tight') 
        plt.close() 

        # g-r vs r-z
        fig = plt.figure(figsize=(6,6)) 
        sub = fig.add_subplot(111) 
        g_r = fUT.flux2mag(gleg['legacy-photo']['flux_g']) - fUT.flux2mag(gleg['legacy-photo']['flux_r'])
        r_z = fUT.flux2mag(gleg['legacy-photo']['flux_r']) - fUT.flux2mag(gleg['legacy-photo']['flux_z'])
        sub.scatter(g_r, r_z, c='k', s=1, label='Legacy')
        g_r = mags[:,0] - mags[:,1]
        r_z = mags[:,1] - mags[:,2]
        sub.scatter(g_r, r_z, c='C1', s=4, zorder=10, label='LGal\nSpectral Challenge')
        sub.set_xlabel('$g - r$', fontsize=20) 
        sub.set_xlim(-1., 3.)   
        sub.set_ylabel('$r - z$', fontsize=20) 
        sub.set_ylim(-1., 3.)   
        sub.legend(loc='upper right', handletextpad=0.2, markerscale=3, fontsize=15) 
        fig.savefig(os.path.join(UT.fig_dir(), os.path.basename(fphot).replace('dat', 'color.png')), bbox_inches='tight') 
        plt.close() 
    return mags 
Esempio n. 19
0
def get_spectra(lyafile, nqso=None, wave=None, templateid=None, normfilter='sdss2010-g',
                seed=None, rand=None, qso=None, add_dlas=False, debug=False, nocolorcuts=True):
    """Generate a QSO spectrum which includes Lyman-alpha absorption.

    Args:
        lyafile (str): name of the Lyman-alpha spectrum file to read.
        nqso (int, optional): number of spectra to generate (starting from the
          first spectrum; if more flexibility is needed use TEMPLATEID).
        wave (numpy.ndarray, optional): desired output wavelength vector.
        templateid (int numpy.ndarray, optional): indices of the spectra
          (0-indexed) to read from LYAFILE (default is to read everything).  If
          provided together with NQSO, TEMPLATEID wins.
        normfilter (str, optional): normalization filter
        seed (int, optional): Seed for random number generator.
        rand (numpy.RandomState, optional): RandomState object used for the
          random number generation.  If provided together with SEED, this
          optional input superseeds the numpy.RandomState object instantiated by
          SEED.
        qso (desisim.templates.QSO, optional): object with which to generate
          individual spectra/templates.
        add_dlas (bool): Inject damped Lya systems into the Lya forest
          These are done according to the current best estimates for the incidence dN/dz
          (Prochaska et al. 2008, ApJ, 675, 1002)
          Set in calc_lz
          These are *not* inserted according to overdensity along the sightline
        nocolorcuts (bool, optional): Do not apply the fiducial rzW1W2 color-cuts
          cuts (default True).

    Returns (flux, wave, meta, dla_meta) where:

        * flux (numpy.ndarray): Array [nmodel, npix] of observed-frame spectra
          (erg/s/cm2/A).
        * wave (numpy.ndarray): Observed-frame [npix] wavelength array (Angstrom).
        * meta (astropy.Table): Table of meta-data [nmodel] for each output spectrum
          with columns defined in desisim.io.empty_metatable *plus* RA, DEC.
        * objmeta (astropy.Table): Table of additional object-specific meta-data
          [nmodel] for each output spectrum with columns defined in
          desisim.io.empty_metatable.
        * dla_meta (astropy.Table): Table of meta-data [ndla] for the DLAs injected
          into the spectra.  Only returned if add_dlas=True

    Note: `dla_meta` is only included if add_dlas=True.

    """
    from scipy.interpolate import interp1d

    import fitsio

    from speclite.filters import load_filters
    from desisim.templates import QSO
    from desisim.io import empty_metatable

    h = fitsio.FITS(lyafile)
    if templateid is None:
        if nqso is None:
            nqso = len(h)-1
        templateid = np.arange(nqso)
    else:
        templateid = np.asarray(templateid)
        nqso = len(np.atleast_1d(templateid))

    if rand is None:
        rand = np.random.RandomState(seed)
    templateseed = rand.randint(2**32, size=nqso)

    #heads = [head.read_header() for head in h[templateid + 1]]
    heads = []
    for indx in templateid:
        heads.append(h[indx + 1].read_header())

    zqso = np.array([head['ZQSO'] for head in heads])
    ra = np.array([head['RA'] for head in heads])
    dec = np.array([head['DEC'] for head in heads])
    mag_g = np.array([head['MAG_G'] for head in heads])

    # Hard-coded filtername!  Should match MAG_G!
    normfilt = load_filters(normfilter)

    if qso is None:
        qso = QSO(normfilter_south=normfilter, wave=wave)

    wave = qso.wave
    flux = np.zeros([nqso, len(wave)], dtype='f4')

    meta, objmeta = empty_metatable(objtype='QSO', nmodel=nqso)
    meta['TEMPLATEID'][:] = templateid
    meta['REDSHIFT'][:] = zqso
    meta['MAG'][:] = mag_g
    meta['MAGFILTER'][:] = normfilter
    meta['SEED'][:] = templateseed
    meta['RA'] = ra
    meta['DEC'] = dec

    # Lists for DLA meta data
    if add_dlas:
        dla_NHI, dla_z, dla_id = [], [], []

    # Loop on quasars
    for ii, indx in enumerate(templateid):
        flux1, _, meta1, objmeta1 = qso.make_templates(nmodel=1, redshift=np.atleast_1d(zqso[ii]),
                                                mag=np.atleast_1d(mag_g[ii]), seed=templateseed[ii],
                                                nocolorcuts=nocolorcuts, lyaforest=False)
        flux1 *= 1e-17
        for col in meta1.colnames:
            meta[col][ii] = meta1[col][0]
        for col in objmeta1.colnames:
            objmeta[col][ii] = objmeta1[col][0]

        # read lambda and forest transmission
        data = h[indx + 1].read()
        la = data['LAMBDA'][:]
        tr = data['FLUX'][:]

        if len(tr):
            # Interpolate the transmission at the spectral wavelengths, if
            # outside the forest, the transmission is 1.
            itr = interp1d(la, tr, bounds_error=False, fill_value=1.0)
            flux1 *= itr(wave)

        # Inject a DLA?
        if add_dlas:
            if np.min(wave/lambda_RF_LYA - 1) < zqso[ii]: # Any forest?
                dlas, dla_model = insert_dlas(wave, zqso[ii], seed=templateseed[ii])
                ndla = len(dlas)
                if ndla > 0:
                    flux1 *= dla_model
                    # Meta
                    dla_z += [idla['z'] for idla in dlas]
                    dla_NHI += [idla['N'] for idla in dlas]
                    dla_id += [indx]*ndla

        padflux, padwave = normfilt.pad_spectrum(flux1, wave, method='edge')
        normmaggies = np.array(normfilt.get_ab_maggies(padflux, padwave,
                                                       mask_invalid=True)[normfilter])

        factor = 10**(-0.4 * mag_g[ii]) / normmaggies
        flux1 *= factor
        for key in ('FLUX_G', 'FLUX_R', 'FLUX_Z', 'FLUX_W1', 'FLUX_W2'):
            meta[key][ii] *= factor
        flux[ii, :] = flux1[:]

    h.close()

    # Finish
    if add_dlas:
        ndla = len(dla_id)
        if ndla > 0:
            from astropy.table import Table
            dla_meta = Table()
            dla_meta['NHI'] = dla_NHI  # log NHI values
            dla_meta['z'] = dla_z
            dla_meta['ID'] = dla_id
        else:
            dla_meta = None
        return flux*1e17, wave, meta, objmeta, dla_meta
    else:
        return flux*1e17, wave, meta, objmeta
Esempio n. 20
0
def main(args=None):

    log = get_logger()
    if isinstance(args, (list, tuple, type(None))):
        args = parse(args)

    if args.outfile is not None and len(args.infile)>1 :
        log.error("Cannot specify single output file with multiple inputs, use --outdir option instead")
        return 1

    if not os.path.isdir(args.outdir) :
        log.info("Creating dir {}".format(args.outdir))
        os.makedirs(args.outdir)

    if args.mags:
        log.warning('--mags is deprecated; please use --bbflux instead')
        args.bbflux = True

    exptime = args.exptime
    if exptime is None :
        exptime = 1000. # sec
        if args.eboss:
            exptime = 1000. # sec (added here in case we change the default)

    #- Generate obsconditions with args.program, then override as needed
    obsconditions = reference_conditions[args.program.upper()]
    if args.airmass is not None:
        obsconditions['AIRMASS'] = args.airmass
    if args.seeing is not None:
        obsconditions['SEEING'] = args.seeing
    if exptime is not None:
        obsconditions['EXPTIME'] = exptime
    if args.moonfrac is not None:
        obsconditions['MOONFRAC'] = args.moonfrac
    if args.moonalt is not None:
        obsconditions['MOONALT'] = args.moonalt
    if args.moonsep is not None:
        obsconditions['MOONSEP'] = args.moonsep

    if args.no_simqso:
        log.info("Load QSO model")
        model=QSO()
    else:
        log.info("Load SIMQSO model")
        #lya_simqso_model.py is located in $DESISIM/py/desisim/scripts/.
        #Uses a different emmision lines model than the default SIMQSO. 
        #We will update this soon to match with the one used in select_mock_targets. 
        model=SIMQSO(nproc=1,sqmodel='lya_simqso_model')
    decam_and_wise_filters = None
    bassmzls_and_wise_filters = None
    if args.target_selection or args.bbflux :
        log.info("Load DeCAM and WISE filters for target selection sim.")
        # ToDo @moustakas -- load north/south filters
        decam_and_wise_filters = filters.load_filters('decam2014-g', 'decam2014-r', 'decam2014-z',
                                                      'wise2010-W1', 'wise2010-W2')
        bassmzls_and_wise_filters = filters.load_filters('BASS-g', 'BASS-r', 'MzLS-z',
                                                     'wise2010-W1', 'wise2010-W2')

    footprint_healpix_weight = None
    footprint_healpix_nside  = None
    if args.desi_footprint :
        if not 'DESIMODEL' in os.environ :
            log.error("To apply DESI footprint, I need the DESIMODEL variable to find the file $DESIMODEL/data/footprint/desi-healpix-weights.fits")
            sys.exit(1)
        footprint_filename=os.path.join(os.environ['DESIMODEL'],'data','footprint','desi-healpix-weights.fits')
        if not os.path.isfile(footprint_filename):
            log.error("Cannot find $DESIMODEL/data/footprint/desi-healpix-weights.fits")
            sys.exit(1)
        pixmap=pyfits.open(footprint_filename)[0].data
        footprint_healpix_nside=256 # same resolution as original map so we don't loose anything
        footprint_healpix_weight = load_pixweight(footprint_healpix_nside, pixmap=pixmap)

    if args.gamma_kms_zfit and not args.zbest:
       log.info("Setting --zbest to true as required by --gamma_kms_zfit")
       args.zbest = True

    if args.extinction:
       sfdmap= SFDMap()
    else:
       sfdmap=None

    if args.balprob:
        bal=BAL()
    else:
        bal=None

    if args.eboss:
        eboss = { 'footprint':FootprintEBOSS(), 'redshift':RedshiftDistributionEBOSS() }
    else:
        eboss = None

    if args.nproc > 1:
        func_args = [ {"ifilename":filename , \
                       "args":args, "model":model , \
                       "obsconditions":obsconditions , \
                       "decam_and_wise_filters": decam_and_wise_filters , \
                       "bassmzls_and_wise_filters": bassmzls_and_wise_filters , \
                       "footprint_healpix_weight": footprint_healpix_weight , \
                       "footprint_healpix_nside": footprint_healpix_nside , \
                       "bal":bal,"sfdmap":sfdmap,"eboss":eboss \
                   } for i,filename in enumerate(args.infile) ]
        pool = multiprocessing.Pool(args.nproc)
        pool.map(_func, func_args)
    else:
        for i,ifilename in enumerate(args.infile) :
            simulate_one_healpix(ifilename,args,model,obsconditions,
                    decam_and_wise_filters,bassmzls_and_wise_filters,
                    footprint_healpix_weight,footprint_healpix_nside,
                    bal=bal,sfdmap=sfdmap,eboss=eboss)
Esempio n. 21
0
    def MCMC_photo(self, photo_obs, photo_ivar_obs, zred, bands='desi', 
            nwalkers=100, burnin=100, niter=1000, writeout=None, silent=True): 
        ''' infer the posterior distribution of the free parameters given observed
        photometric flux, and inverse variance using MCMC. The function 
        outputs a dictionary with the median theta of the posterior as well as the 
        1sigma and 2sigma errors on the parameters (see below).
        
        :param photo_obs: 
            array of the observed photometric flux __in units of nanomaggies__

        :param photo_ivar_obs: 
            array of the observed photometric flux **inverse variance**. Not uncertainty!

        :param zred: 
            float specifying the redshift of the observations  

        :param bands: 
            specify the photometric bands. Some pre-programmed bands available. e.g. 
            if bands == 'desi' then 
            bands_list = ['decam2014-g', 'decam2014-r', 'decam2014-z','wise2010-W1', 'wise2010-W2', 'wise2010-W3', 'wise2010-W4']. 
            (default: 'desi') 

        :param nwalkers: (optional) 
            number of walkers. (default: 100) 
        
        :param burnin: (optional) 
            int specifying the burnin. (default: 100) 
        
        :param nwalkers: (optional) 
            int specifying the number of iterations. (default: 1000) 
        
        :param writeout: (optional) 
            string specifying the output file. If specified, everything in the output dictionary 
            is written out as well as the entire MCMC chain. (default: None) 

        :param silent: (optional) 
            If False, a bunch of messages will be shown 

        :return output: 
            dictionary that with keys: 
            - output['redshift'] : redshift 
            - output['theta_med'] : parameter value of the median posterior
            - output['theta_1sig_plus'] : 1sigma above median 
            - output['theta_2sig_plus'] : 2sigma above median 
            - output['theta_1sig_minus'] : 1sigma below median 
            - output['theta_2sig_minus'] : 2sigma below median 
            - output['wavelength_model'] : wavelength of best-fit model 
            - output['flux_model'] : flux of best-fit model 
            - output['wavelength_data'] : wavelength of observations 
            - output['flux_data'] : flux of observations 
            - output['flux_ivar_data'] = inverse variance of the observed flux. 
        '''
        # get photometric bands  
        bands_list = self._get_bands(bands)
        assert len(bands_list) == len(photo_obs) 
        # get filters
        filters = specFilter.load_filters(*tuple(bands_list))

        # posterior function args and kwargs
        lnpost_args = (
                photo_obs,               # nanomaggies
                photo_ivar_obs,         # 1/nanomaggies^2
                zred
                ) 
        lnpost_kwargs = {
                'filters': filters,
                'prior_shape': 'flat'   # shape of prior (hardcoded) 
                }
    
        # run emcee and get MCMC chains 
        chain = self._emcee(self._lnPost_photo, lnpost_args, lnpost_kwargs, 
                nwalkers=nwalkers, burnin=burnin, niter=niter, silent=silent)
        # get quanitles of the posterior
        lowlow, low, med, high, highhigh = np.percentile(chain, [2.5, 16, 50, 84, 97.5], axis=0)
    
        output = {} 
        output['redshift'] = zred
        output['theta_med'] = med 
        output['theta_1sig_plus'] = high
        output['theta_2sig_plus'] = highhigh
        output['theta_1sig_minus'] = low
        output['theta_2sig_minus'] = lowlow
    
        flux_model = self.model_photo(med, zred=zred, filters=filters)
        output['flux_model'] = flux_model 
        output['flux_data'] = photo_obs
        output['flux_ivar_data'] = photo_ivar_obs
    
        # save prior and MCMC chain 
        output['priors'] = self.priors
        output['mcmc_chain'] = chain 

        if writeout is not None: 
            fh5  = h5py.File(writeout, 'w') 
            for k in output.keys(): 
                fh5.create_dataset(k, data=output[k]) 
            fh5.close() 
        return output  
Esempio n. 22
0
def Lgal_nonoisePhoto(lib='bc03', dust=False, overwrite=False, validate=False): 
    ''' generate noiseless photometry from noiseless spectral_challenge Lgal spectra 
    generated by Rita. Super simple code that convolves the spectra with the bandpass 
    decam g, r, z, W1, W2, W3, W4 filtes. 
    '''
    fsource = f_nonoise(4, lib=lib)
    fsource = os.path.basename(fsource).rsplit('.', 1)[0].rsplit('_BGS_template_')[1]
    if dust: str_dust = 'dust'
    else: str_dust = 'nodust'
    fphot = os.path.join(UT.dat_dir(), 'spectral_challenge', 'bgs','photo.%s.%s.nonoise.dat' % (fsource, str_dust))

    if os.path.isfile(fphot) and not overwrite: 
        _mags = np.loadtxt(fphot, unpack=True, skiprows=1, usecols=range(1,8))
        mags = _mags.T
    else: 
        galids = np.unique(testGalIDs()) # IDs of spectral_challenge galaxies 
            
        fluxes = np.zeros((len(galids), 8))
        fluxes[:,0] = galids
        for i, gid in enumerate(galids): 
            # read ins ource spectra
            spec_source = Lgal_nonoiseSpectra(gid, lib=lib)
            if dust: 
                flux = spec_source['flux_dust_nonoise']
            else: 
                flux = spec_source['flux_nodust_nonoise']
            # apply filters
            filter_response = specFilter.load_filters('decam2014-g', 'decam2014-r', 'decam2014-z','wise2010-W1', 'wise2010-W2', 'wise2010-W3', 'wise2010-W4')
            fluxes_i = filter_response.get_ab_maggies(np.atleast_2d(flux)*U.Watt/U.m**2/U.Angstrom, spec_source['wave']*U.Angstrom)
            fluxes[i,1:] = 1e9 * np.array([fluxes_i[0][0], fluxes_i[0][1], fluxes_i[0][2], fluxes_i[0][3], fluxes_i[0][4], fluxes_i[0][5], fluxes_i[0][6]]) # nanomaggies
        fmt = ['%.5e' for i in range(8)]
        fmt[0] = '%i'
        np.savetxt(fphot, fluxes, header='galid, g, r, z, W1, W2, W3, W4 fluxes in nanomaggies', fmt=fmt)
        mags = fUT.flux2mag(fluxes[:,1:], method='log') 

    if validate: # compare the Lgal nonoise photometry to photometry from GAMA-Legacy 
        cats = Cats.GamaLegacy() 
        gleg = cats.Read('g15') 

        fig = plt.figure(figsize=(20,4)) 
        for i_b, band in enumerate(['g', 'r', 'z', 'w1', 'w2']): 
            sub = fig.add_subplot(1,5,i_b+1) 
            sub.hist(fUT.flux2mag(gleg['legacy-photo']['flux_%s' % band]), color='k', range=(14,25), density=True, label='Legacy')
            sub.hist(mags[:,i_b], color='C1', range=(14, 25), density=True, alpha=0.5, label='LGal\nSpectral\nChallenge')
            sub.set_xlabel('%s magnitude' % band, fontsize=20) 
            sub.set_xlim(14, 25) 
        sub.legend(loc='upper right', fontsize=15) 
        fig.savefig(os.path.join(UT.fig_dir(), os.path.basename(fphot).replace('dat', 'hist.png')), bbox_inches='tight') 
        plt.close() 
    
        # g-r vs r-z
        fig = plt.figure(figsize=(6,6)) 
        sub = fig.add_subplot(111) 
        g_r = fUT.flux2mag(gleg['legacy-photo']['flux_g']) - fUT.flux2mag(gleg['legacy-photo']['flux_r'])
        r_z = fUT.flux2mag(gleg['legacy-photo']['flux_r']) - fUT.flux2mag(gleg['legacy-photo']['flux_z'])
        sub.scatter(g_r, r_z, c='k', s=1, label='Legacy')
        g_r = mags[:,0] - mags[:,1]
        r_z = mags[:,1] - mags[:,2]
        sub.scatter(g_r, r_z, c='C1', s=4, zorder=10, label='LGal\nSpectral Challenge')
        sub.set_xlabel('$g - r$', fontsize=20) 
        sub.set_xlim(-1., 3.)   
        sub.set_ylabel('$r - z$', fontsize=20) 
        sub.set_ylim(-1., 3.)   
        sub.legend(loc='upper right', handletextpad=0.2, markerscale=3, fontsize=15) 
        fig.savefig(os.path.join(UT.fig_dir(), os.path.basename(fphot).replace('dat', 'color.png')), bbox_inches='tight') 
        plt.close() 
    return mags 
Esempio n. 23
0
def main(args=None):

    log = get_logger()
    if isinstance(args, (list, tuple, type(None))):
        args = parse(args)

    if args.outfile is not None and len(args.infile)>1 :
        log.error("Cannot specify single output file with multiple inputs, use --outdir option instead")
        return 1

    if not os.path.isdir(args.outdir) :
        log.info("Creating dir {}".format(args.outdir))
        os.makedirs(args.outdir)

    if args.mags:
        log.warning('--mags is deprecated; please use --bbflux instead')
        args.bbflux = True

    exptime = args.exptime
    if exptime is None :
        exptime = 1000. # sec
        if args.eboss:
            exptime = 1000. # sec (added here in case we change the default)

    #- Generate obsconditions with args.program, then override as needed
    obsconditions = reference_conditions[args.program.upper()]
    if args.airmass is not None:
        obsconditions['AIRMASS'] = args.airmass
    if args.seeing is not None:
        obsconditions['SEEING'] = args.seeing
    if exptime is not None:
        obsconditions['EXPTIME'] = exptime
    if args.moonfrac is not None:
        obsconditions['MOONFRAC'] = args.moonfrac
    if args.moonalt is not None:
        obsconditions['MOONALT'] = args.moonalt
    if args.moonsep is not None:
        obsconditions['MOONSEP'] = args.moonsep

    if args.no_simqso:
        log.info("Load QSO model")
        model=QSO()
    else:
        log.info("Load SIMQSO model")
        #lya_simqso_model.py is located in $DESISIM/py/desisim/scripts/.
        #Uses a different emmision lines model than the default SIMQSO
        model=SIMQSO(nproc=1,sqmodel='lya_simqso_model')

    decam_and_wise_filters = None
    bassmzls_and_wise_filters = None
    if args.target_selection or args.bbflux :
        log.info("Load DeCAM and WISE filters for target selection sim.")
        # ToDo @moustakas -- load north/south filters
        decam_and_wise_filters = filters.load_filters('decam2014-g', 'decam2014-r', 'decam2014-z',
                                                      'wise2010-W1', 'wise2010-W2')
        bassmzls_and_wise_filters = filters.load_filters('BASS-g', 'BASS-r', 'MzLS-z',
                                                     'wise2010-W1', 'wise2010-W2')

    footprint_healpix_weight = None
    footprint_healpix_nside  = None
    if args.desi_footprint :
        if not 'DESIMODEL' in os.environ :
            log.error("To apply DESI footprint, I need the DESIMODEL variable to find the file $DESIMODEL/data/footprint/desi-healpix-weights.fits")
            sys.exit(1)
        footprint_filename=os.path.join(os.environ['DESIMODEL'],'data','footprint','desi-healpix-weights.fits')
        if not os.path.isfile(footprint_filename):
            log.error("Cannot find $DESIMODEL/data/footprint/desi-healpix-weights.fits")
            sys.exit(1)
        pixmap=pyfits.open(footprint_filename)[0].data
        footprint_healpix_nside=256 # same resolution as original map so we don't loose anything
        footprint_healpix_weight = load_pixweight(footprint_healpix_nside, pixmap=pixmap)

    if args.gamma_kms_zfit and not args.zbest:
       log.info("Setting --zbest to true as required by --gamma_kms_zfit")
       args.zbest = True

    if args.extinction:
       sfdmap= SFDMap()
    else:
       sfdmap=None

    if args.balprob:
        bal=BAL()
    else:
        bal=None

    if args.eboss:
        eboss = { 'footprint':FootprintEBOSS(), 'redshift':RedshiftDistributionEBOSS() }
    else:
        eboss = None

    if args.nproc > 1:
        func_args = [ {"ifilename":filename , \
                       "args":args, "model":model , \
                       "obsconditions":obsconditions , \
                       "decam_and_wise_filters": decam_and_wise_filters , \
                       "bassmzls_and_wise_filters": bassmzls_and_wise_filters , \
                       "footprint_healpix_weight": footprint_healpix_weight , \
                       "footprint_healpix_nside": footprint_healpix_nside , \
                       "bal":bal,"sfdmap":sfdmap,"eboss":eboss \
                   } for i,filename in enumerate(args.infile) ]
        pool = multiprocessing.Pool(args.nproc)
        pool.map(_func, func_args)
    else:
        for i,ifilename in enumerate(args.infile) :
            simulate_one_healpix(ifilename,args,model,obsconditions,
                    decam_and_wise_filters,bassmzls_and_wise_filters,
                    footprint_healpix_weight,footprint_healpix_nside,
                    bal=bal,sfdmap=sfdmap,eboss=eboss)
Esempio n. 24
0
def main(args=None):

    log = get_logger()
    if isinstance(args, (list, tuple, type(None))):
        args = parse(args)

    if isinstance(args, (list, tuple, type(None))):
        args = parse(args)

    if args.outfile is not None and len(args.infile) > 1:
        log.error(
            "Cannot specify single output file with multiple inputs, use --outdir option instead"
        )
        return 1

    if not os.path.isdir(args.outdir):
        log.info("Creating dir {}".format(args.outdir))
        os.makedirs(args.outdir)

    exptime = args.exptime
    if exptime is None:
        exptime = 1000.  # sec

    #- Generate obsconditions with args.program, then override as needed
    obsconditions = reference_conditions[args.program.upper()]
    if args.airmass is not None:
        obsconditions['AIRMASS'] = args.airmass
    if args.seeing is not None:
        obsconditions['SEEING'] = args.seeing
    if exptime is not None:
        obsconditions['EXPTIME'] = exptime
    if args.moonfrac is not None:
        obsconditions['MOONFRAC'] = args.moonfrac
    if args.moonalt is not None:
        obsconditions['MOONALT'] = args.moonalt
    if args.moonsep is not None:
        obsconditions['MOONSEP'] = args.moonsep

    log.info("Load SIMQSO model")
    model = SIMQSO(normfilter=args.norm_filter, nproc=1)

    decam_and_wise_filters = None
    if args.target_selection or args.mags:
        log.info("Load DeCAM and WISE filters for target selection sim.")
        decam_and_wise_filters = filters.load_filters('decam2014-g',
                                                      'decam2014-r',
                                                      'decam2014-z',
                                                      'wise2010-W1',
                                                      'wise2010-W2')

    footprint_healpix_weight = None
    footprint_healpix_nside = None
    if args.desi_footprint:
        if not 'DESIMODEL' in os.environ:
            log.error(
                "To apply DESI footprint, I need the DESIMODEL variable to find the file $DESIMODEL/data/footprint/desi-healpix-weights.fits"
            )
            sys.exit(1)
        footprint_filename = os.path.join(os.environ['DESIMODEL'], 'data',
                                          'footprint',
                                          'desi-healpix-weights.fits')
        if not os.path.isfile(footprint_filename):
            log.error(
                "Cannot find $DESIMODEL/data/footprint/desi-healpix-weights.fits"
            )
            sys.exit(1)
        pixmap = pyfits.open(footprint_filename)[0].data
        footprint_healpix_nside = 256  # same resolution as original map so we don't loose anything
        footprint_healpix_weight = load_pixweight(footprint_healpix_nside,
                                                  pixmap=pixmap)

    if args.seed is not None:
        np.random.seed(args.seed)

    # seeds for each healpix are themselves random numbers
    seeds = np.random.randint(2**32, size=len(args.infile))
    if args.balprob:
        bal = BAL()

    if args.nproc > 1:
        func_args = [ {"ifilename":filename , \
                       "args":args, "model":model , \
                       "obsconditions":obsconditions , \
                       "decam_and_wise_filters": decam_and_wise_filters , \
                       "footprint_healpix_weight": footprint_healpix_weight , \
                       "footprint_healpix_nside": footprint_healpix_nside , \
                       "seed":seeds[i]
                   } for i,filename in enumerate(args.infile) ]
        pool = multiprocessing.Pool(args.nproc)
        pool.map(_func, func_args)
    else:
        for i, ifilename in enumerate(args.infile):
            if args.balprob:
                simulate_one_healpix(ifilename,
                                     args,
                                     model,
                                     obsconditions,
                                     decam_and_wise_filters,
                                     footprint_healpix_weight,
                                     footprint_healpix_nside,
                                     seed=seeds[i],
                                     bal=bal)
            else:
                simulate_one_healpix(ifilename,
                                     args,
                                     model,
                                     obsconditions,
                                     decam_and_wise_filters,
                                     footprint_healpix_weight,
                                     footprint_healpix_nside,
                                     seed=seeds[i])
Esempio n. 25
0
def get_sky(night,
            expid,
            exptime,
            ftype="model",
            redux="daily",
            smoothing=100.0,
            specsim_darksky=False,
            nightly_darksky=False):
    # AR ftype = "data" or "model"
    # AR redux = "daily" or "blanc"
    # AR if ftype = "data" : read the sky fibers from frame*fits + apply flat-field
    # AR if ftype = "model": read the sky model from sky*.fits for the first fiber of each petal (see DJS email from 29Dec2020)
    # AR those are in electron / angstrom
    # AR to integrate over the decam-r-band, we need cameras b and r
    if ftype not in ["data", "model"]:
        sys.exit("ftype should be 'data' or 'model'")

    sky = np.zeros(len(fullwave))
    reduxdir = dailydir.replace("daily", redux)

    # AR see AK email [desi-data 5218]
    if redux == "blanc":
        specs = ["0", "1", "3", "4", "5", "7", "8", "9"]
    else:
        specs = np.arange(10, dtype=int).astype(str)

    for camera in ["b", "r", "z"]:
        norm_cam = np.zeros(len(fullwave[cslice[camera]]))
        sky_cam = np.zeros(len(fullwave[cslice[camera]]))

        for spec in specs:
            # AR data
            if ftype == "data":
                frfn = os.path.join(
                    reduxdir,
                    "exposures",
                    "{}".format(night),
                    expid,
                    "frame-{}{}-{}.fits".format(camera, spec, expid),
                )

                if not os.path.isfile(frfn):
                    print("Skipping non-existent {}".format(frfn))

                    continue

                fr = read_frame(frfn, skip_resolution=True)

                flfn = os.environ['DESI_SPECTRO_CALIB'] + '/' + CalibFinder(
                    [fr.meta]).data['FIBERFLAT']

                # calib_flux [1e-17 erg/s/cm2/Angstrom] = uncalib_flux [electron/Angstrom] / (calibration_model * exptime [s])
                # fl = read_fiberflat(flfn)

                # No exptime correction.
                # apply_fiberflat(fr, fl)

                # AR cutting on sky fibers with at least one valid pixel.
                ii = (fr.fibermap["OBJTYPE"]
                      == "SKY") & (fr.ivar.sum(axis=1) > 0)

                # AR frame*fits are in e- / angstrom ; adding the N sky fibers
                # sky_cam += fr.flux[ii, :].sum(axis=0)
                # nspec += ii.sum()

                # Ignores fiberflat corrected (fl), as includes e.g. fiberloss.
                sky_cam += (fr.flux[ii, :] * fr.ivar[ii, :]).sum(axis=0)
                norm_cam += fr.ivar[ii, :].sum(axis=0)

            # AR model
            if ftype == "model":
                fn = os.path.join(
                    reduxdir,
                    "exposures",
                    "{}".format(night),
                    expid,
                    "sky-{}{}-{}.fits".format(camera, spec, expid),
                )
                if not os.path.isfile(fn):
                    print("Skipping non-existent {}".format(fn))

                else:
                    print("Solving for {}".format(fn))

                    fd = fitsio.FITS(fn)

                    assert np.allclose(fullwave[cslice[camera]],
                                       fd["WAVELENGTH"].read())

                    fd = fitsio.FITS(fn)

                    with fd as hdus:
                        exptime = hdus[0].read_header()['EXPTIME']

                        flux = hdus['SKY'].read()
                        ivar = hdus['IVAR'].read()
                        mask = hdus['MASK'].read()

                        # Verify that we have the expected wavelengths.
                        # assert np.allclose(detected[camera].wave, hdus['WAVELENGTH'].read())
                        # Verify that ivar is purely statistical.
                        # assert np.array_equal(ivar, hdus['STATIVAR'].read())
                        # Verify that the model has no masked pixels.
                        # assert np.all((mask == 0) & (ivar > 0))
                        # Verify that the sky model is constant.
                        # assert np.array_equal(np.max(ivar, axis=0), np.min(ivar, axis=0))

                        # assert np.allclose(np.max(flux, axis=0), np.min(flux, axis=0))
                        # There are actually small variations in flux!
                        # TODO: figure out where these variations come from.
                        # For now, take the median over fibers.
                        if fd["IVAR"][0, :][0].max() > 0:
                            sky_cam += fd["SKY"][0, :][
                                0]  # AR reading the first fiber only
                            norm_cam += np.ones(len(fullwave[cslice[camera]]))

                        # sky_cam  += np.median(flux, axis=0)
                        # norm_cam += np.ones(len(fullwave[cslice[camera]]))

                    fd.close()

        # AR sky model flux in incident photon / angstrom / s
        # if nspec > 0:
        keep = norm_cam > 0

        if keep.sum() > 0:
            # [e/A/s] / throughput.
            sky[cslice[camera]][keep] = (sky_cam[keep] / norm_cam[keep] /
                                         exptime / spec_thru[camera][keep])
        else:
            print("{}-{}-{}: no spectra for {}".format(night, expid, camera,
                                                       ftype))

    # AR sky model flux in erg / angstrom / s (using the photon energy in erg).
    e_phot_erg = (constants.h.to(units.erg * units.s) *
                  constants.c.to(units.angstrom / units.s) /
                  (fullwave * units.angstrom))
    sky *= e_phot_erg.value

    # AR sky model flux in [erg / angstrom / s / cm**2 / arcsec**2].
    sky /= (telap_cm2 * fiber_area_arcsec2)

    if smoothing > 0.0:
        sky = scipy.ndimage.gaussian_filter1d(sky, 100.)

    # AR integrate over the DECam r-band
    vfilter = filters.load_filters('bessell-V')
    rfilter = filters.load_filters('decam2014-r')

    # AR zero-padding spectrum so that it covers the DECam r-band range
    sky_pad, fullwave_pad = vfilter.pad_spectrum(sky, fullwave, method="zero")
    vmag = vfilter.get_ab_magnitudes(
        sky_pad * units.erg / (units.cm**2 * units.s * units.angstrom),
        fullwave_pad * units.angstrom).as_array()[0][0]

    # AR zero-padding spectrum so that it covers the DECam r-band range
    sky_pad, fullwave_pad = rfilter.pad_spectrum(sky, fullwave, method="zero")
    rmag = rfilter.get_ab_magnitudes(
        sky_pad * units.erg / (units.cm**2 * units.s * units.angstrom),
        fullwave_pad * units.angstrom).as_array()[0][0]

    if specsim_darksky:
        fd = fitsio.FITS(fn)

        # Dark Sky at given airmass (cnst. across spectrograph / camera).
        simulator.atmosphere.airmass = fd['SKY'].read_header()['AIRMASS']

        # Force below the horizon: dark sky.
        simulator.atmosphere.moon.moon_zenith = 120. * u.deg

        simulator.simulate()

        # [1e-17 erg / (Angstrom arcsec2 cm2 s)].
        sim_darksky = simulator.atmosphere.surface_brightness
        sim_darksky *= 1.e-17

        dsky_pad, dskywave_pad = rfilter.pad_spectrum(sim_darksky.value,
                                                      config.wavelength.value,
                                                      method="zero")
        dsky_rmag = rfilter.get_ab_magnitudes(
            dsky_pad * units.erg / (units.cm**2 * units.s * units.angstrom),
            dskywave_pad * units.angstrom).as_array()[0][0]

        sim_darksky = resample_flux(fullwave, config.wavelength.value,
                                    sim_darksky.value)
        sim_darksky *= u.erg / (u.cm**2 * u.s * u.angstrom * u.arcsec**2)

        sky = np.clip(sky - sim_darksky.value, a_min=0.0, a_max=None)

        # AR zero-padding spectrum so that it covers the DECam r-band range
        sky_pad, fullwave_pad = vfilter.pad_spectrum(sky,
                                                     fullwave,
                                                     method="zero")
        vmag_nodark = vfilter.get_ab_magnitudes(
            sky_pad * units.erg / (units.cm**2 * units.s * units.angstrom),
            fullwave_pad * units.angstrom).as_array()[0][0]

        # AR zero-padding spectrum so that it covers the DECam r-band range
        sky_pad, fullwave_pad = rfilter.pad_spectrum(sky,
                                                     fullwave,
                                                     method="zero")
        rmag_nodark = rfilter.get_ab_magnitudes(
            sky_pad * units.erg / (units.cm**2 * units.s * units.angstrom),
            fullwave_pad * units.angstrom).as_array()[0][0]

        return fullwave, sky, vmag, rmag, vmag_nodark, rmag_nodark

    elif nightly_darksky:
        from pkg_resources import resource_filename

        if night in nightly_dsky_cache.keys():
            return nightly_dsky_cache[night]

        gfa_info = resource_filename('bgs-cmxsv', 'dat/sv1-exposures.fits')
        gfa_info = Table.read(gfa_info)

        bright_cut = 20.50

        good_conds = (gfa_info['GFA_TRANSPARENCY_MED'] >
                      0.95) & (gfa_info['GFA_SKY_MAG_AB_MED'] >= bright_cut)
        good_conds = gfa_info[good_conds]

        expids = np.array([
            np.int(x.split('/')[-1]) for x in glob.glob(
                os.path.join(reduxdir, "exposures", "{}/00*".format(night)))
        ])
        isgood = np.isin(good_conds['EXPID'], expids)

        if np.any(isgood):
            good_conds = good_conds[isgood]
            best = good_conds['GFA_SKY_MAG_AB_MED'] == good_conds[
                'GFA_SKY_MAG_AB_MED'].max()

            print('Nightly Dark GFA r-mag for {}:  {}'.format(
                night, good_conds['GFA_SKY_MAG_AB_MED'].max()))

            best_expid = good_conds[best]['EXPID'][0]
            best_expid = '{:08d}'.format(best_expid)

            darkwave, darksky, dark_vmag, dark_rmag = get_sky(
                night,
                best_expid,
                exptime,
                ftype="model",
                redux="daily",
                smoothing=0.0,
                specsim_darksky=False,
                nightly_darksky=False)

            sky = np.clip(sky - darksky, a_min=0.0, a_max=None)

            # AR zero-padding spectrum so that it covers the DECam r-band range
            sky_pad, fullwave_pad = vfilter.pad_spectrum(sky,
                                                         fullwave,
                                                         method="zero")
            vmag_nodark = vfilter.get_ab_magnitudes(
                sky_pad * units.erg / (units.cm**2 * units.s * units.angstrom),
                fullwave_pad * units.angstrom).as_array()[0][0]

            # AR zero-padding spectrum so that it covers the DECam r-band range
            sky_pad, fullwave_pad = rfilter.pad_spectrum(sky,
                                                         fullwave,
                                                         method="zero")
            rmag_nodark = rfilter.get_ab_magnitudes(
                sky_pad * units.erg / (units.cm**2 * units.s * units.angstrom),
                fullwave_pad * units.angstrom).as_array()[0][0]

            nightly_dsky_cache[
                night] = fullwave, sky, vmag, rmag, vmag_nodark, rmag_nodark

        else:
            print(
                'No nightly darksky available for night: {}.  Defaulting to specsim.'
                .format(night))

            nightly_dsky_cache[night] = get_sky(night,
                                                expid,
                                                exptime,
                                                ftype="model",
                                                redux="daily",
                                                smoothing=0.0,
                                                specsim_darksky=True,
                                                nightly_darksky=False)

        return nightly_dsky_cache[night]

    else:
        pass

    return fullwave, sky, vmag, rmag
Esempio n. 26
0
    def MCMC_spectrophoto(self, wave_obs, flux_obs, flux_ivar_obs, photo_obs, photo_ivar_obs, zred, f_fiber_prior=None, 
            mask=None, bands='desi',
            nwalkers=100, burnin=100, niter=1000, writeout=None, silent=True): 
        ''' infer the posterior distribution of the free parameters given spectroscopy and photometry:
        observed wavelength, spectra flux, inverse variance flux, photometry, inv. variance photometry
        using MCMC. The function outputs a dictionary with the median theta of the posterior as well as 
        the 1sigma and 2sigma errors on the parameters (see below).

        :param wave_obs: 
            array of the observed wavelength
        
        :param flux_obs: 
            array of the observed flux __in units of ergs/s/cm^2/Ang__

        :param flux_ivar_obs: 
            array of the observed flux **inverse variance**. Not uncertainty!
        
        :param photo_obs: 
            array of the observed photometric flux __in units of nanomaggies__

        :param photo_ivar_obs: 
            array of the observed photometric flux **inverse variance**. Not uncertainty!

        :param zred: 
            float specifying the redshift of the observations  
    
        :param f_fiber_prior: 
            list specifying the range of f_fiber factor proir. (default: None) 

        :param mask: (optional) 
            boolean array specifying where to mask the spectra. If mask == 'emline' the spectra
            is masked around emission lines at 3728., 4861., 5007., 6564. Angstroms. (default: None) 

        :param nwalkers: (optional) 
            number of walkers. (default: 100) 
        
        :param burnin: (optional) 
            int specifying the burnin. (default: 100) 
        
        :param nwalkers: (optional) 
            int specifying the number of iterations. (default: 1000) 
        
        :param writeout: (optional) 
            string specifying the output file. If specified, everything in the output dictionary 
            is written out as well as the entire MCMC chain. (default: None) 

        :param silent: (optional) 
            If False, a bunch of messages will be shown 

        :return output: 
            dictionary that with keys: 
            - output['redshift'] : redshift 
            - output['theta_med'] : parameter value of the median posterior
            - output['theta_1sig_plus'] : 1sigma above median 
            - output['theta_2sig_plus'] : 2sigma above median 
            - output['theta_1sig_minus'] : 1sigma below median 
            - output['theta_2sig_minus'] : 2sigma below median 
            - output['wavelength_model'] : wavelength of best-fit model 
            - output['flux_model'] : flux of best-fit model 
            - output['wavelength_data'] : wavelength of observations 
            - output['flux_data'] : flux of observations 
            - output['flux_ivar_data'] = inverse variance of the observed flux. 
        '''
        import scipy.optimize as op
        import emcee

        self.priors.append(f_fiber_prior) # add f_fiber priors 
        ndim = len(self.priors)
    
        # check mask for spectra 
        _mask = self._check_mask(mask, wave_obs, flux_ivar_obs, zred) 
        
        # get photometric bands  
        bands_list = self._get_bands(bands)
        assert len(bands_list) == len(photo_obs) 
        # get filters
        filters = specFilter.load_filters(*tuple(bands_list))

        # posterior function args and kwargs
        lnpost_args = (wave_obs, 
                flux_obs,        # 10^-17 ergs/s/cm^2/Ang
                flux_ivar_obs,   # 1/(10^-17 ergs/s/cm^2/Ang)^2
                photo_obs,               # nanomaggies
                photo_ivar_obs,         # 1/nanomaggies^2
                zred) 
        lnpost_kwargs = {
                'mask': _mask,           # emission line mask 
                'filters': filters,
                'prior_shape': 'flat'   # shape of prior (hardcoded) 
                }
        
        # run emcee and get MCMC chains 
        chain = self._emcee(self._lnPost_spectrophoto, lnpost_args, lnpost_kwargs, 
                nwalkers=nwalkers, burnin=burnin, niter=niter, silent=silent)
        # get quanitles of the posterior
        lowlow, low, med, high, highhigh = np.percentile(chain, [2.5, 16, 50, 84, 97.5], axis=0)
    
        output = {} 
        output['redshift'] = zred
        output['theta_med'] = med 
        output['theta_1sig_plus'] = high
        output['theta_2sig_plus'] = highhigh
        output['theta_1sig_minus'] = low
        output['theta_2sig_minus'] = lowlow
    
        w_model, flux_model = self.model(med, zred=zred, wavelength=wave_obs)
        output['wavelength_model'] = w_model
        output['flux_model'] = flux_model 
       
        output['wavelength_data'] = wave_obs
        output['flux_data'] = flux_obs
        output['flux_ivar_data'] = flux_ivar_obs
        
        # save prior and MCMC chain 
        output['priors'] = self.priors
        output['mcmc_chain'] = chain 

        if writeout is not None: 
            fh5  = h5py.File(writeout, 'w') 
            for k in output.keys(): 
                fh5.create_dataset(k, data=output[k]) 
            fh5.close() 
        return output  
Esempio n. 27
0
def create_galaxy_counts(cmau_array, mag_bins, z_array, wav, alpha0, alpha1,
                         weight, ab_offset, filter_name, al_inf):
    r'''
    Create a simulated distribution of galaxy magnitudes for a particular
    bandpass by consideration of double Schechter functions (for blue and
    red galaxies) in a specified range of redshifts, following [1]_.

    Parameters
    ----------
    cmau_array : numpy.ndarray
        Array holding the c/m/a/u values that describe the parameterisation
        of the Schechter functions with wavelength, following Wilson (2022, RNAAS,
        6, 60) [1]_. Shape should be `(5, 2, 4)`, with 5 parameters for both
        blue and red galaxies.
    mag_bins : numpy.ndarray
        The apparent magnitudes at which to evaluate the on-sky differential
        galaxy density.
    z_array : numpy.ndarray
        Redshift bins to evaluate Schechter densities in the middle of.
    wav : float
        The wavelength, in microns, of the bandpass observations should be
        simulated in. Should likely be the effective wavelength.
    alpha0 : list of numpy.ndarray or numpy.ndarray
        List of arrays of parameters :math:`\alpha_{i, 0}` used to calculate
        Dirichlet-distributed SED coefficients. Should either be a two-element
        list of arrays of 5 elements, or an array of shape ``(2, 5)``, with
        coefficients for blue galaxies before red galaxies. See [2]_ and [3]_
        for more details.
    alpha1 : list of numpy.ndarray or numpy.ndarray
        :math:`\alpha_{i, 1}` used in the calculation of Dirichlet-distributed SED
        coefficients. Two-element list or ``(2, 5)`` shape array of blue
        then red galaxy coefficients.
    weight : list of numpy.ndarray or numpy.ndarray
        Corresponding weights for the derivation of Dirichlet `kcorrect`
        coefficients. Must match shape of ``alpha0`` and ``alpha1``.
    ab_offset : float
        Zeropoint offset for differential galaxy count observations in a
        non-AB magnitude system. Must be in the sense of m_desired = m_AB - offset.
    filter_name : str
        ``speclite`` compound filterset-filter name for the response curve
        of the particular observations. If observations are in a filter system
        not provided by ``speclite``, response curve can be generated using
        ``generate_speclite_filters``.
    al_inf : float
        The reddening at infinity by which to extinct all galaxy magnitudes.

    Returns
    -------
    gal_dens : numpy.ndarray
        Simulated numbers of galaxies per square degree per magnitude in the
        specified observed bandpass.

    References
    ----------
    .. [1] Wilson T. J. (2022), RNAAS, 6, 60
    .. [2] Herbel J., Kacprzak T., Amara A., et al. (2017), JCAP, 8, 35
    .. [3] Blanton M. R., Roweis S. (2007), AJ, 133, 734

    '''
    cosmology = default_cosmology.get()
    gal_dens = np.zeros_like(mag_bins)
    log_wav = np.log10(wav)

    alpha0_blue, alpha0_red = alpha0
    alpha1_blue, alpha1_red = alpha1
    weight_blue, weight_red = weight

    # Currently just set up a very wide absolute magnitude bin range to ensure
    # we get the dynamic range right. Inefficient but should be reliable...
    abs_mag_bins = np.linspace(-60, 50, 1100)
    for i in range(len(z_array) - 1):
        mini_z_array = z_array[[i, i + 1]]
        z = 0.5 * np.sum(mini_z_array)

        phi_model1 = generate_phi(cmau_array, 0, log_wav, z, abs_mag_bins)
        phi_model2 = generate_phi(cmau_array, 1, log_wav, z, abs_mag_bins)

        # differential_comoving_volume is "per redshift per steradian" at each
        # redshift, so we take the average and "integrate" over z.
        dV_dOmega = np.sum(
            cosmology.differential_comoving_volume(mini_z_array).to_value(
                'Mpc3 / deg2')) / 2 * np.diff(mini_z_array)

        model_densities = [phi_model1 * dV_dOmega, phi_model2 * dV_dOmega]

        # Blanton & Roweis (2007) kcorrect templates, via skypy.
        w = skygal.spectrum.kcorrect.wavelength
        t = skygal.spectrum.kcorrect.templates
        # Generate redshifts and coefficients and k-corrections for each
        # realisation, and then take the median k-correction.
        for _alpha0, _alpha1, _weight, model_density in zip(
            [alpha0_blue, alpha0_red], [alpha1_blue, alpha1_red],
            [weight_blue, weight_red], model_densities):
            rng = np.random.default_rng()
            redshift = rng.uniform(z_array[i], z_array[i + 1], 100)
            spectral_coefficients = skygal.spectrum.dirichlet_coefficients(
                redshift=redshift,
                alpha0=_alpha0,
                alpha1=_alpha1,
                weight=_weight)

            kcorr = np.empty_like(redshift)
            for j in range(len(redshift)):
                _z = redshift[j]
                f = load_filters(filter_name)[0]
                fs = f.create_shifted(_z)
                non_shift_ab_maggy, shift_ab_maggy = 0, 0
                for k in range(len(t)):
                    non_shift_ab_maggy += spectral_coefficients[
                        j, k] * f.get_ab_maggies(t[k], w)
                    try:
                        shift_ab_maggy += spectral_coefficients[
                            j, k] * fs.get_ab_maggies(t[k], w)
                    except ValueError:
                        _t, _w = fs.pad_spectrum(t[k], w, method='edge')
                        shift_ab_maggy += spectral_coefficients[
                            j, k] * fs.get_ab_maggies(_t, _w)
                # Backwards to Hogg+ astro-ph/0210394, our "shifted" bandpass is the rest-frame
                # as opposed to the observer frame.
                kcorr[j] = -2.5 * np.log10(
                    1 / (1 + _z) * shift_ab_maggy / non_shift_ab_maggy)
            # e.g. Loveday+2015 for absolute -> apparent magnitude conversion
            gal_dens += np.interp(
                mag_bins, abs_mag_bins + cosmology.distmod(z).value +
                np.percentile(kcorr, 50) - ab_offset + al_inf, model_density)

    return gal_dens