def test_bottom_bracket_logz(): """Test for zinterp.bracket_logz()""" ZZsol = -1.98 zmet1, zmet2 = bracket_logz(ZZsol) assert zmet1 == 1 and zmet2 == 2 f1 = np.atleast_1d(2.) f2 = np.atleast_1d(4.) f = interp_logz(zmet1, zmet2, ZZsol, f1, f2) assert f[0] == f1[0]
def test_high_bracket_logz(): """Test for Z above grid.""" # Test too high Z logZZsol = 0.2 + 0.01 zmet1, zmet2 = bracket_logz(logZZsol) assert zmet1 == 21 and zmet2 == 22 f1 = np.atleast_1d(2.) f2 = np.atleast_1d(4.) f = interp_logz(zmet1, zmet2, logZZsol, f1, f2) assert f[0] == f2[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
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