Beispiel #1
0
    def __call__(self, theta):
        """Posterior likelihood call."""
        # Evaluate prior
        lnpriors = np.array([self._priors[n](v)
                             for n, v in zip(self._param_names, theta)])
        lnprior = np.sum(lnpriors)
        if ~np.isfinite(lnprior):
            model_mjy = np.empty(self.n_computed_bands, np.float)
            model_mjy.fill(np.nan)
            blob = {"lnpost": -np.inf,
                    "logMstar": np.nan,
                    "logMdust": np.nan,
                    "logLbol": np.nan,
                    "logSFR": np.nan,
                    "logAge": np.nan,
                    "model_sed": model_mjy,
                    "lnpriors": lnpriors}
            return -np.inf, blob

        meta1 = np.empty(5, dtype=float)
        meta2 = np.empty(5, dtype=float)

        for name, val in zip(self._param_names, theta):
            if name == 'logmass':
                logm = val
            elif name == 'logZZsol':
                logZZsol = val
            elif name == 'logtau':
                self.sp.params['tau'] = 10. ** val
            elif name in self.sp.params.all_params:  # list of parameter names
                self.sp.params[name] = val

        zmet1, zmet2 = bracket_logz(logZZsol)
        # Compute fluxes with low metallicity
        self.sp.params['zmet'] = zmet1
        f1 = abs_ab_mag_to_micro_jy(
            self.sp.get_mags(tage=13.8, bands=self._compute_bands),
            self.d)
        meta1[0] = self.sp.stellar_mass
        meta1[1] = self.sp.dust_mass
        meta1[2] = self.sp.log_lbol
        meta1[3] = self.sp.sfr
        meta1[4] = self.sp.log_age
        # Compute fluxes with high metallicity
        self.sp.params['zmet'] = zmet2
        f2 = abs_ab_mag_to_micro_jy(
            self.sp.get_mags(tage=13.8, bands=self._compute_bands),
            self.d)
        meta2[0] = self.sp.stellar_mass
        meta2[1] = self.sp.dust_mass
        meta2[2] = self.sp.log_lbol
        meta2[3] = self.sp.sfr
        meta2[4] = self.sp.log_age

        # Interpolate and scale the SED by mass
        model_mjy = 10. ** logm * interp_logz(zmet1, zmet2, logZZsol, f1, f2)

        # Interpolate metadata between the two metallicities
        meta = interp_logz(zmet1, zmet2, logZZsol, meta1, meta2)

        # Compute likelihood
        # Automatically ignores pixels with no measurement (Nan)
        lnL = -0.5 * np.nansum(
            np.power((model_mjy[self.band_indices]
                      - self._sed) / self._err, 2.))
        lnpost = lnprior + lnL
        if ~np.isfinite(lnpost):
            lnpost = -np.inf

        # Scale statistics by the total mass
        blob = {"lnpost": lnpost,
                "logMstar": logm + np.log10(meta[0]),  # log solar masses,
                "logMdust": logm + np.log10(meta[1]),  # log solar masses
                "logLbol": logm * meta[2],  # log solar luminosities
                "logSFR": logm * meta[3],  # star formation rate, M_sun / yr
                "logAge": meta[4],
                "model_sed": model_mjy,
                "lnpriors": lnpriors}

        return lnpost, blob
Beispiel #2
0
def interp_z_likelihood(args):
    """Generic single-pixel likeihood function where a single metallicity
    is linearly interpolated.

    Note that the SED can contain values of NaN, those bands will be
    automatically ignored from the likelihood calculation
    """
    global SP

    theta, theta_names, phi, phi_names, B, area, sed, err, sed_bands, \
        compute_bands = args

    meta1 = np.empty(5, dtype=float)
    meta2 = np.empty(5, dtype=float)

    band_indices = np.array([compute_bands.index(b) for b in sed_bands])

    # Evaluate the ln-likelihood function by interpolating between
    # metallicty bracket
    for name, val in itertools.chain(zip(theta_names, theta),
                                     zip(phi_names, phi)):
        if name == 'logmass':
            logm = val
        elif name == 'logZZsol':
            logZZsol = val
        elif name == 'logtau':
            SP.params['tau'] = 10. ** val
        elif name in SP.params.all_params:  # list of parameter names
            SP.params[name] = val

    zmet1, zmet2 = bracket_logz(logZZsol)
    # Compute fluxes with low metallicity
    SP.params['zmet'] = zmet1
    f1 = abs_ab_mag_to_micro_jy(
        SP.get_mags(tage=13.8, bands=compute_bands),
        phi[0])
    meta1[0] = SP.stellar_mass
    meta1[1] = SP.dust_mass
    meta1[2] = SP.log_lbol
    meta1[3] = SP.sfr
    meta1[4] = SP.log_age
    # Compute fluxes with high metallicity
    SP.params['zmet'] = zmet2
    f2 = abs_ab_mag_to_micro_jy(
        SP.get_mags(tage=13.8, bands=compute_bands),
        phi[0])
    meta2[0] = SP.stellar_mass
    meta2[1] = SP.dust_mass
    meta2[2] = SP.log_lbol
    meta2[3] = SP.sfr
    meta2[4] = SP.log_age

    # Interpolate and scale the SED by mass
    model_mjy = 10. ** logm * interp_logz(zmet1, zmet2, logZZsol, f1, f2)

    # Interpolate metadata between the two metallicities
    meta = interp_logz(zmet1, zmet2, logZZsol, meta1, meta2)

    # Compute likelihood
    # Automatically ignores pixels with no measurement (Nan)
    L = -0.5 * np.nansum(
        np.power((model_mjy[band_indices] + B * area - sed) / err, 2.))

    # Scale statistics by the total mass
    blob = {"logMstar": logm + np.log10(meta[0]),  # log solar masses,
            "logMdust": logm + np.log10(meta[1]),  # log solar masses
            "logLbol": logm * meta[2],  # log solar luminosities
            "logSFR": logm * meta[3],  # star formation rate, M_sun / yr
            "logAge": meta[4],
            "model_sed": model_mjy}  # note: background no included

    return L, blob
Beispiel #3
0
    def compute_library_seds(self, bands, age=13.7, default_pset=None):
        """Compute an SED for each library model instance.

        Model SEDs are stored as absolute fluxes (µJy at d=10pc), normalized
        to a 1 Solar mass stellar population.

        .. todo:: Support parallel computation.

        Parameters
        ----------
        bands : list
            List of `FSPS bandpass names
            <http://dan.iel.fm/python-fsps/current/filters/>`_.
        default_pset : dict
            Default Python-FSPS parameters.
        """
        if default_pset is None:
            default_pset = {}

        # ALWAYS compute AB mags
        default_pset['compute_vega_mags'] = False

        # Solar magnitude in each bandpass
        solar_mags = [fsps.get_filter(n).msun_ab for n in bands]

        # Add bands and AB solar mags to the group attr metadata
        self.group.attrs['bands'] = bands
        self.group.attrs['msun_ab'] = solar_mags

        # Build the SED table
        table_names = ['seds', 'mass_light', 'meta']
        for name in table_names:
            if name in self.group:
                del self.group[name]

        # Table for SEDs
        n_models = len(self.group["params"])
        dtype = np.dtype([(n, np.float) for n in bands])
        sed_table = self.group.create_dataset("seds",
                                              (n_models,),
                                              dtype=dtype)

        # Table for M/L ratios in each bandpass
        dtype = np.dtype([(n, np.float) for n in bands])
        ml_table = self.group.create_dataset("mass_light",
                                             (n_models,),
                                             dtype=dtype)

        # Table for metadata (stellar mass, dust mass, etc..)
        meta_cols = ('logMstar', 'logMdust', 'logLbol', 'logSFR', 'logAge')
        dtype = np.dtype([(n, np.float) for n in meta_cols])
        meta_table = self.group.create_dataset("meta",
                                               (n_models,),
                                               dtype=dtype)

        # Iterate on each model
        # TODO eventually split this work between processors
        sp_param_names = self.group['params'].dtype.names
        sp = fsps.StellarPopulation(**default_pset)
        for i, row in enumerate(self.group["params"]):
            for n, p in zip(sp_param_names, row):
                sp.params[n] = float(p)
            mags = sp.get_mags(tage=age, bands=bands)
            fluxes = abs_ab_mag_to_micro_jy(mags, 10.)

            # Fill in SED and ML tables
            for n, msun, flux in zip(bands, solar_mags, fluxes):
                # interesting slicing syntax for structured array assignment
                sed_table[n, i] = flux

                logL = micro_jy_to_luminosity(flux, msun, 10.)
                log_ml = np.log10(sp.stellar_mass) - logL
                ml_table[n, i] = log_ml

            # Fill in meta data table
            meta_table['logMstar', i] = np.log10(sp.stellar_mass)
            meta_table['logMdust', i] = np.log10(sp.dust_mass)
            meta_table['logLbol', i] = np.log10(sp.log_lbol)
            meta_table['logSFR', i] = np.log10(sp.sfr)
            meta_table['logAge', i] = sp.log_age