def plot(self, mass=None, sfr=None, z=None, FQdist=None, sfms_prop=None, **mkwargs): ''' Plot the quiescent fraction as a function of stellar mass. The quiescent fraction is calculated based on an evolving sSFR(M*,z) cut. Parameters ---------- FQdist : list List that specifies the mass bins and the quiescent fraction (eq. [massbin, quiescentfraction]) ''' if FQdist is None: if sfr is None or z is None: raise ValueError fq_obj = Fq() masses, fq = fq_obj.Calculate(mass=mass, sfr=sfr, z=z, sfms_prop=sfms_prop) else: masses, fq = FQdist self.masses = masses self.z = z if self.kwargs == {}: kwargs = mkwargs.copy() else: kwargs = (self.kwargs).copy() kwargs.update(mkwargs) if 'label' in kwargs: fq_label = kwargs['label'] else: fq_label = None if 'line_color' in kwargs: line_color = kwargs['line_color'] else: line_color = 'black' if 'line_style' in kwargs: line_style = kwargs['line_style'] else: line_style = '-' if 'lw' in kwargs: line_width = kwargs['lw'] else: line_width = 4 self.subs.plot(masses, fq, color = line_color, lw = line_width, ls = line_style, label = fq_label) return None
def _getPq(ancestor, descendant, succession=None, will=None, pq_prop=None, sfr_prop=None): '''' Calculate the quenching probability for Star-Forming ancestor galaxies in the ancestor CGPop object. The quenching probability is calculated using P_Q = ( f_Q(Mf,zf) - f_Q(M0,z0) ) / (1 - f_Q(M0,z0)) + Offset_P_Q where Offset_P_Q is a fudge factor dictated by nuisance parameters described by pq_prop. Parameters ---------- pq_prop : dict Quenching properties dictionary. Keywords are 'slope' and 'yint' which describes the offset to the quenchign probability. The quenchign probability is fudged around to match the observed quenching fraction at z_final: fQ(M*, z_final). Returns ------- P_q : array Array that specifies the quenching probabilities for the SF ancestor galaxies. ''' z_final = descendant.zsnap # z_final of evolution # SF ancestors sf_ancestors = np.where(ancestor.sfr_class[will] == 'star-forming')[0] P_q_offset = pq_prop['slope'] * ( descendant.mass[succession[sf_ancestors]] - 9.5) + pq_prop['yint'] # fQ(M*, z_final) fq_obj = Fq() fqf = fq_obj.model(descendant.mass[succession[sf_ancestors]], z_final, lit=sfr_prop['fq']['name']) # fQ(M*, z_initial), which is calculated using mass and redshifts when # the host subhalo passes the M* threshold. fq0 = fq_obj.model(descendant.mass_genesis[succession[sf_ancestors]], descendant.zsnap_genesis[succession[sf_ancestors]], lit=sfr_prop['fq']['name']) notallquench = np.where(fq0 < 1.0) P_q = np.repeat(1.0, len(sf_ancestors)) P_q[notallquench] = (fqf[notallquench] - fq0[notallquench]) / (1.0 - fq0[notallquench]) P_q += P_q_offset return P_q
def model(self, fq_prop={'name': 'wetzelsmooth'}, z=None, **mkwargs): ''' Plot the model Parameterized queiscent fraction as a function of stellar mass ''' if z is None: if self.z is None: raise ValeuError else: redshift = self.z else: redshift = z self.z = z if self.kwargs == {}: kwargs = mkwargs.copy() else: kwargs = (self.kwargs).copy() kwargs.update(mkwargs) if 'label' in kwargs and kwargs['label'] is not None: fq_label = kwargs['label'] else: fq_label = fq_prop['name']+'; z = '+str(redshift) if 'line_color' in kwargs: line_color = kwargs['line_color'] else: line_color = 'black' if 'line_style' in kwargs: line_style = kwargs['line_style'] else: line_style = '-' if 'lw' in kwargs: line_width = kwargs['lw'] else: line_width = 4 # parameterized fq fq_obj = Fq() fq = fq_obj.model(self.masses, self.z, lit=fq_prop['name']) self.subs.plot( self.masses, fq, color = line_color, lw = 4, ls = '--', label = fq_label ) return None
def plotSFMS(self, **pltkwargs): ''' Plot the Star Forming Main Sequence of the CGPop object Notes ----- Uses bovy_plot.scatter_plot so things are a big clunky ''' plt.close() sfms_plot = plots.PlotSFMS() if 'scatter' in pltkwargs: if not pltkwargs['scatter']: pass else: sfms_plot.plot(mass=self.mass, sfr=self.sfr, sfr_class=self.sfr_class, color=self.nsnap, **pltkwargs) else: sfms_plot.plot(mass=self.mass, sfr=self.sfr, sfr_class=self.sfr_class, color=self.nsnap, **pltkwargs) if 'sfqcut' in pltkwargs.keys(): if pltkwargs['sfqcut']: qfrac = Fq() m_arr = np.arange(9.0, 12.5, 0.5) sfms_plot.sub.plot(m_arr, qfrac.SFRcut( m_arr, self.zsnap, sfms_prop=self.sfr_prop['sfms']), c='k', ls='--', lw=4) if 'model' in pltkwargs.keys(): if pltkwargs['model']: sfms_plot.model(z=self.zsnap) if 'savefig' in pltkwargs.keys(): if isinstance(pltkwargs['savefig'], str): sfms_plot.save_fig(pltkwargs['savefig']) else: ValueError('savefig = figure_file_name') return None else: return sfms_plot
def Plot_fQcen_SDSS(): ''' Compare the quiescent fraction of SDSS from the *corrected* SDSS fQ^cen from Tinker et al. (2013) versus the Wetzel et al. (2013) parameterization. ''' # mass binnning we impose m_low = np.array([9.5, 10., 10.5, 11., 11.5]) m_high = np.array([10., 10.5, 11., 11.5, 12.0]) m_mid = 0.5 * (m_low + m_high) # SDSS fq_file = ''.join( ['dat/observations/cosmos_fq/', 'fcen_red_sdss_scatter.dat']) m_sdss, fqcen_sdss, N_sdss = np.loadtxt(fq_file, unpack=True, usecols=[0, 1, 2]) fqcen_sdss_rebin = [] for im, m_mid_i in enumerate(m_mid): sdss_mbin = np.where((m_sdss >= m_low[im]) & (m_sdss < m_high[im])) fqcen_sdss_rebin.append( np.sum(fqcen_sdss[sdss_mbin] * N_sdss[sdss_mbin].astype('float')) / np.sum(N_sdss[sdss_mbin].astype('float'))) fqcen_sdss_rebin = np.array(fqcen_sdss_rebin) prettyplot() pretty_colors = prettycolors() fig = plt.figure() sub = fig.add_subplot(111) qf = Fq() fqcen_model = qf.model(m_mid, 0.05, lit='cosmos_tinker') sub.plot(m_mid, fqcen_model, c=pretty_colors[3], lw=3, label=r'Wetzel et al. (2013) fit') sub.scatter(m_mid, fqcen_sdss_rebin, color=pretty_colors[0], lw=0, s=40, label=r'Tinker et al. (2013)') sub.set_xlim([9.0, 12.0]) sub.set_xlabel(r'$\mathtt{log\;M_*}$', fontsize=25) sub.set_ylim([0.0, 1.0]) sub.set_ylabel(r'$\mathtt{f_Q^{cen}}$', fontsize=25) sub.legend(loc='upper left', scatterpoints=1, markerscale=3) fig_file = ''.join(['figure/test/', 'Fq_central_SDSS.png']) fig.savefig(fig_file, bbox_inches='tight') plt.close()
def _getPq(ancestor, descendant, succession=None, will=None, pq_prop=None, sfr_prop=None): '''' Calculate the quenching probability for Star-Forming ancestor galaxies in the ancestor CGPop object. The quenching probability is calculated using P_Q = ( f_Q(Mf,zf) - f_Q(M0,z0) ) / (1 - f_Q(M0,z0)) + Offset_P_Q where Offset_P_Q is a fudge factor dictated by nuisance parameters described by pq_prop. Parameters ---------- pq_prop : dict Quenching properties dictionary. Keywords are 'slope' and 'yint' which describes the offset to the quenchign probability. The quenchign probability is fudged around to match the observed quenching fraction at z_final: fQ(M*, z_final). Returns ------- P_q : array Array that specifies the quenching probabilities for the SF ancestor galaxies. ''' z_final = descendant.zsnap # z_final of evolution # SF ancestors sf_ancestors = np.where(ancestor.sfr_class[will] == 'star-forming')[0] P_q_offset = pq_prop['slope'] * (descendant.mass[succession[sf_ancestors]] - 9.5) + pq_prop['yint'] # fQ(M*, z_final) fq_obj = Fq() fqf = fq_obj.model(descendant.mass[succession[sf_ancestors]], z_final, lit = sfr_prop['fq']['name']) # fQ(M*, z_initial), which is calculated using mass and redshifts when # the host subhalo passes the M* threshold. fq0 = fq_obj.model(descendant.mass_genesis[succession[sf_ancestors]], descendant.zsnap_genesis[succession[sf_ancestors]], lit=sfr_prop['fq']['name']) notallquench = np.where(fq0 < 1.0) P_q = np.repeat(1.0, len(sf_ancestors)) P_q[notallquench] = (fqf[notallquench] - fq0[notallquench] ) / (1.0 - fq0[notallquench]) P_q += P_q_offset return P_q
def Plot_fQcen_SDSS(): ''' Compare the quiescent fraction of SDSS from the *corrected* SDSS fQ^cen from Tinker et al. (2013) versus the Wetzel et al. (2013) parameterization. ''' # mass binnning we impose m_low = np.array([9.5, 10., 10.5, 11., 11.5]) m_high = np.array([10., 10.5, 11., 11.5, 12.0]) m_mid = 0.5 * (m_low + m_high) # SDSS fq_file = ''.join(['dat/observations/cosmos_fq/', 'fcen_red_sdss_scatter.dat']) m_sdss, fqcen_sdss, N_sdss = np.loadtxt(fq_file, unpack=True, usecols=[0,1,2]) fqcen_sdss_rebin = [] for im, m_mid_i in enumerate(m_mid): sdss_mbin = np.where( (m_sdss >= m_low[im]) & (m_sdss < m_high[im])) fqcen_sdss_rebin.append( np.sum(fqcen_sdss[sdss_mbin] * N_sdss[sdss_mbin].astype('float'))/np.sum(N_sdss[sdss_mbin].astype('float')) ) fqcen_sdss_rebin = np.array(fqcen_sdss_rebin) prettyplot() pretty_colors = prettycolors() fig = plt.figure() sub = fig.add_subplot(111) qf = Fq() fqcen_model = qf.model(m_mid, 0.05, lit='cosmos_tinker') sub.plot(m_mid, fqcen_model, c=pretty_colors[3], lw=3, label=r'Wetzel et al. (2013) fit') sub.scatter(m_mid, fqcen_sdss_rebin, color=pretty_colors[0], lw=0, s=40, label=r'Tinker et al. (2013)') sub.set_xlim([9.0, 12.0]) sub.set_xlabel(r'$\mathtt{log\;M_*}$', fontsize=25) sub.set_ylim([0.0, 1.0]) sub.set_ylabel(r'$\mathtt{f_Q^{cen}}$', fontsize=25) sub.legend(loc='upper left', scatterpoints=1, markerscale=3) fig_file = ''.join(['figure/test/', 'Fq_central_SDSS.png']) fig.savefig(fig_file, bbox_inches='tight') plt.close()
def Fq(self, **fq_kwargs): ''' Calculate quiescent fraction of CenQue class object ''' if self.zsnap is None: raise ValueError if self.mass is None: raise ValueError if self.sfr is None: raise ValueError if self.sfr_prop is None: raise ValueError qfrac = Fq() # Star-forming or Quiescent return qfrac.Calculate(mass=self.mass, sfr=self.sfr, z=self.zsnap, sfms_prop=self.sfr_prop['sfms'])
def DataSummary(Mrcut=18, observables=['ssfr']): ''' Summary statistics of the data. In our case that is the SSFR distribution of the SDSS group catalog. ''' obvs = [] if 'ssfr' in observables: # Group Catalog object groupcat = GroupCat(Mrcut=Mrcut, position='central') # SSFR distribution of group catalog bins, dist = groupcat.Ssfr() obvs.append([np.array(bins), np.array(dist)]) if 'fqz03' in observables: qfrac = Fq() M_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_mid = 0.5 * (M_bin[:-1] + M_bin[1:]) fq_model = qfrac.model(M_mid, 0.3412, lit='wetzel') obvs.append([M_mid, fq_model]) if len(observables) == 1: obvs = obvs[0] return obvs
def SimSummary(observables=['ssfr'], **sim_kwargs): ''' Summary statistics of the simulation. In our case, the simulation is InheritSF and the summary statistic is the SSFR distribution. ''' obvs = [] if 'ssfr' in observables: bloodline = InheritSF( 1, nsnap_ancestor=sim_kwargs['nsnap_ancestor'], subhalo_prop=sim_kwargs['subhalo_prop'], sfr_prop=sim_kwargs['sfr_prop'], evol_prop=sim_kwargs['evol_prop']) descendant = getattr(bloodline, 'descendant_snapshot1') bins, dist = descendant.Ssfr() obvs.append([np.array(bins), np.array(dist)]) if 'fqz03' in observables: bloodline = InheritSF( 6, nsnap_ancestor=sim_kwargs['nsnap_ancestor'], subhalo_prop=sim_kwargs['subhalo_prop'], sfr_prop=sim_kwargs['sfr_prop'], evol_prop=sim_kwargs['evol_prop']) descendant = getattr(bloodline, 'descendant_snapshot6') qfrac = Fq() M_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_mid = 0.5 * (M_bin[:-1] + M_bin[1:]) sfq = qfrac.Classify(descendant.mass, descendant.sfr, descendant.zsnap, sfms_prop=sim_kwargs['sfr_prop']['sfms']) ngal, dum = np.histogram(descendant.mass, bins=M_bin) ngal_q, dum = np.histogram(descendant.mass[sfq == 'quiescent'], bins=M_bin) obvs.append([M_mid, ngal_q.astype('float')/ngal.astype('float')]) if len(observables) == 1: obvs = obvs[0] return obvs
def Evol_shamMstarSFR(t0, tfs, t_step=0.5, tQ0=None, MQ0=None, SFR0=None, q_Mshams=None, sf_Mshams=None, quiet=True, **kwargs): ''' Evolve SFR of the SF galaxies while quenching some of them at the same time. Notes ----- * SF galaxies are quenched based on the following prescription: The number of galaxies that start quenching between t0 and t0+tstep is determined by first guessing, N_quenching = N_sf(t0) * (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep ''' dutycycle_prop = kwargs['dutycycle_prop'] tau_prop = kwargs['tau_prop'] fq_prop = kwargs['fq_prop'] sfms_prop = kwargs['sfms_prop'] massevol_prop = kwargs['massevol_prop'] fudge_prop = kwargs['fudge_prop'] tQ = tQ0.copy() Mq = MQ0.copy() t00 = t0.min() # earliest starting time (cosmic time of ancestor snapshot) t_evol = t_snap[np.abs(t_snap - np.max(tfs)).argmin() - 1:np.abs(t_snap - t00).argmin() + 1][::-1] qf = Fq() Fq_anal = qf.model # Mass bins M_bins = np.arange(6.0, 13., 0.5) M_mid = 0.5 * (M_bins[:-1] + M_bins[1:]) for i_t, tt in enumerate(t_evol[:-1]): if not quiet: print 't_cosmic = ', tt t_one_tstep = time.time() # M_sham of the quiescent galaxies at the closest snapshot. closest_t0_snap = np.abs(t_snap - tt).argmin() - 1 Msham_q0 = q_Mshams[:, closest_t0_snap].copy() Msham_sf0 = sf_Mshams[:, closest_t0_snap].copy() within = np.where((Msham_sf0 > 0.) & (t0 <= tt)) # tsnap_genesis <= t sf_within = np.where((Msham_sf0 > 0.) & (t0 <= tt) & (tQ == 999.))[0] # Not quenching SF galaxies Nsf_0 = len(sf_within) M_t0_sample = np.concatenate( [Msham_sf0[within], Msham_q0[np.where(Msham_q0 > 0.)]]) P_sf = np.random.uniform(0., 1., Nsf_0) # Initial estimate of quenching probability given by dFq/dt # P_q = (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep Ng0, dum = np.histogram(M_t0_sample, bins=M_bins) Nsf0, dum = np.histogram(Msham_sf0[sf_within], bins=M_bins) P_q_arr = Ng0 / Nsf0 * dFqdt( M_mid, tt + 0.5 * t_step, lit=fq_prop['name']) * t_step P_q_arr[np.where(Nsf0 == 0)] = 0. if not quiet: print 'M* : ', M_mid[-6:] print 'P_q : ', P_q_arr[-6:] Pq_M = interpolate.interp1d(M_mid, P_q_arr, kind='linear') P_q = Pq_M(Msham_sf0[sf_within]) q_ing0 = np.where(P_q > P_sf) Nqing0 = len(q_ing0[0]) # M_sham of the quiescent galaxies at the closest snapshot. closest_t_snap = np.abs(t_snap - t_evol[i_t + 1]).argmin() - 1 Msham_q1 = q_Mshams[:, closest_t_snap] Msham_sf1 = sf_Mshams[:, closest_t_snap] M_t1_sample = np.concatenate([Msham_sf1[within], Msham_q1]) # dPQ correction to the quenching to account for change in Ng(M*,t) Ngp, dum = np.histogram(M_t1_sample, bins=M_bins) dPq = (Ngp - Ng0) / Nsf0.astype('float') * Fq_anal( M_mid, z_of_t(tt + t_step), lit=fq_prop['name']) dPq[np.where(dPq < 0.)] = 0. dPq[np.where(Nsf0 == 0)] = 0. if not quiet: print 'dPq : ', dPq[-6:] dPq_M = interpolate.interp1d(M_mid, dPq, kind='linear') P_q += dPq_M(Msham_sf0[sf_within]) # fudge factor for P_Q fudge_factor = fudge_prop['slope'] * ( Msham_sf0[sf_within] - fudge_prop['fidmass']) + fudge_prop['offset'] fudge_factor[np.where(fudge_factor < 1.)] = 1. P_q *= fudge_factor q_ing = np.where(P_sf < P_q) if not quiet: print 'Initial guess ', Nqing0, ' final: ', len( q_ing[0]), ' SF gal out of ', Nsf_0, ' start quenching' print time.time() - t_one_tstep print '----------------' # assign them quenching times then actually evolve their stellar masses tQ[sf_within[q_ing]] = np.random.uniform(low=tt, high=tt + t_step, size=len(q_ing[0])) quenching = np.where((Mq == -999.) & (tQ < 999.) & (tQ > 0))[0] Nquenching = len(quenching) closest_tQ_index = np.abs( np.tile(t_snap, (Nquenching, 1)) - np.tile(tQ[quenching].reshape(Nquenching, 1), (1, len(t_snap)))).argmin(axis=1) - 1 Mq[quenching] = sf_Mshams[quenching, closest_tQ_index].copy() SFR_list = [] for tf in tfs: closest_tf_snap = np.abs(t_snap - tf).argmin() - 1 Msham_f = sf_Mshams[:, closest_tf_snap].copy() if closest_tf_snap == 0: before = Msham_f[:10] kwargs_sfr = { 't_init': t0.copy(), 't_q': tQ.copy(), 'M_q': Mq.copy(), 'dutycycle_prop': dutycycle_prop, 'tau_prop': tau_prop, 'sfms_prop': sfms_prop } SFR, M_qq = logSFR_M_t(Msham_f.copy(), tf, **kwargs_sfr) if closest_tf_snap == 0: print 'is same? ', np.array_equal(before, Msham_f[:10]) print tf, SFR.min(), SFR.max() # correct for the galaxies that were originally in the green valley. # ultimately doesn't make a difference in the outcome, but to be meticulous gv0 = np.where(tQ0 == 0.) # galaxies that were initiall quenching SFR[gv0] -= sfr_evol.AverageLogSFR_sfms(Mq[gv0], z_of_t(t0[gv0]), sfms_prop=sfms_prop) SFR[gv0] -= sfr_evol.DeltaLogSFR_quenching(tQ[gv0], t0[gv0], M_q=Mq[gv0], tau_prop=tau_prop) SFR[gv0] += SFR0[gv0].copy() SFR_list.append(SFR.copy()) del SFR return SFR_list, tQ.copy()
def Evol_IntegMstarSFR(M0, t0, tf, t_step=0.5, tQ0=None, MQ0=None, ancestor_Mq=None, **kwargs): ''' Evolve stellar mass and SFR of the SF galaxies while quenching some of them at the same time. Notes ----- * SF galaxies are quenched based on the following prescription: The number of galaxies that start quenching between t0 and t0+tstep is determined by first guessing, N_quenching = N_sf(t0) * (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep ''' dutycycle_prop = kwargs['dutycycle_prop'] tau_prop = kwargs['tau_prop'] fq_prop = kwargs['fq_prop'] sfms_prop = kwargs['sfms_prop'] massevol_prop = kwargs['massevol_prop'] fudge_prop = kwargs['fudge_prop'] Mstar = M0 SFR = np.repeat(-999., len(M0)) tQ = tQ0 Mq = MQ0 t00 = t0.min() # earliest starting time (cosmic time of ancestor snapshot) t_evol = np.arange(t00, tf + t_step, t_step) t_evol[-1] = tf qf = Fq() Fq_anal = qf.model # Mass bins M_bins = np.arange(6.0, 13., 0.5) M_mid = 0.5 * (M_bins[:-1] + M_bins[1:]) for tt in t_evol: print 't_cosmic = ', tt t_one_tstep = time.time() within = np.where(t0 <= tt) # tsnap_genesis <= t sf_within = np.where((t0 <= tt) & (tQ == 999.))[0] # Not quenching SF galaxies Nsf_0 = len(sf_within) # M_sham of the quiescent galaxies at the closest snapshot. closest_t0_snap = np.abs(t_snap - tt).argmin() - 1 Msham_q0 = ancestor_Mq[:, closest_t0_snap] M_t0_sample = np.concatenate( [Mstar[within], Msham_q0[np.where(Msham_q0 > 0.)]]) P_sf = np.random.uniform(0., 1., Nsf_0) # Initial estimate of quenching probability given by dFq/dt # P_q = (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep Ng0, dum = np.histogram(M_t0_sample, bins=M_bins) Nsf0, dum = np.histogram(Mstar[sf_within], bins=M_bins) P_q_arr = Ng0 / Nsf0 * dFqdt( M_mid, tt + 0.5 * t_step, lit=fq_prop['name']) * t_step P_q_arr[np.where(Nsf0 == 0)] = 0. print 'M* : ', M_mid[-6:] print 'P_q : ', P_q_arr[-6:] Pq_M = interpolate.interp1d(M_mid, P_q_arr, kind='linear') P_q = Pq_M(Mstar[sf_within]) q_ing = np.where(P_q > P_sf) Nqing0 = len(q_ing[0]) # assign them quenching times tQ_tmp = tQ tQ_tmp[sf_within[q_ing]] = np.random.uniform(low=tt, high=tt + t_step, size=Nqing0) kwargs_sfr = { 't_init': t0[within], 't_q': tQ_tmp[within], 'M_q': Mq[within], 'dutycycle_prop': dutycycle_prop, 'tau_prop': tau_prop, 'sfms_prop': sfms_prop, 'indices': within } M_evol, sfr_evol, Mq_evol = M_integrate(Mstar[within], tt, tt + t_step, massevol_prop=massevol_prop, kwargs_sfr=kwargs_sfr) # M_sham of the quiescent galaxies at the closest snapshot. closest_t_snap = np.abs(t_snap - tt - t_step).argmin() - 1 Msham_qf = ancestor_Mq[:, closest_t_snap] M_tf_sample = np.concatenate([M_evol, Msham_qf]) # dPQ correction to the quenching to account for change in Ng(M*,t) Ngp, dum = np.histogram(M_tf_sample, bins=M_bins) dPq = (Ngp - Ng0) / Nsf0.astype('float') * Fq_anal( M_mid, z_of_t(tt + t_step), lit=fq_prop['name']) dPq[np.where(dPq < 0.)] = 0. dPq[np.where(Nsf0 == 0)] = 0. print 'dPq : ', dPq[-6:] dPq_M = interpolate.interp1d(M_mid, dPq, kind='linear') P_q += dPq_M(Mstar[sf_within]) fudge_factor = fudge_prop['slope'] * ( Mstar[sf_within] - fudge_prop['fidmass']) + fudge_prop['offset'] fudge_factor[np.where(fudge_factor < 1.)] = 1. P_q *= fudge_factor q_ing = np.where(P_sf < P_q) print 'Initial guess ', Nqing0, ' after correction: ', len( q_ing[0] ), ' SF galaxies out of ', Nsf_0, ' galaxies start quenching' print time.time() - t_one_tstep print '----------------' # assign them quenching times then actually evolve their stellar masses tQ[sf_within[q_ing]] = np.random.uniform(low=tt, high=tt + t_step, size=len(q_ing[0])) kwargs_sfr = { 't_init': t0[within], 't_q': tQ[within], 'M_q': Mq[within], 'dutycycle_prop': dutycycle_prop, 'tau_prop': tau_prop, 'sfms_prop': sfms_prop, 'indices': within } M_evol, sfr_evol, Mq_evol = M_integrate(Mstar[within], tt, tt + t_step, massevol_prop=massevol_prop, kwargs_sfr=kwargs_sfr) Mstar[within] = M_evol SFR[within] = sfr_evol Mq[within] = Mq_evol if SFR.min() == -999.: raise ValueError return Mstar, SFR, tQ
def SimSummary(observables=['ssfr'], **sim_kwargs): ''' Summary statistics of the simulation. In our case, the simulation is Inherit and the summary statistic is the SSFR distribution. ''' obvs = [] if 'fqz03' in observables and 'fqz_multi' in observables: raise ValueError nsnap_ds = [1] if 'fqz03' in observables: nsnap_ds += [6] if 'fqz_multi' in observables: nsnap_ds += [3, 6] inh = Inherit(nsnap_ds, nsnap_ancestor=sim_kwargs['nsnap_ancestor'], subhalo_prop=sim_kwargs['subhalo_prop'], sfr_prop=sim_kwargs['sfr_prop'], evol_prop=sim_kwargs['evol_prop']) des_dict = inh() # SSFR des1 = des_dict['1'] if 'ssfr' in observables: bins, dist = des1.Ssfr() obvs.append([np.array(bins), np.array(dist)]) if 'fqz03' in observables: # fQ(nsnap = 6) des6 = des_dict['6'] qfrac = Fq() M_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_mid = 0.5 * (M_bin[:-1] + M_bin[1:]) sfq = qfrac.Classify(des6.mass, des6.sfr, des6.zsnap, sfms_prop=sim_kwargs['sfr_prop']['sfms']) ngal, dum = np.histogram(des6.mass, bins=M_bin) ngal_q, dum = np.histogram(des6.mass[sfq == 'quiescent'], bins=M_bin) obvs.append([M_mid, ngal_q.astype('float')/ngal.astype('float')]) if 'fqz_multi' in observables: # fQ at multiple snapshots qfrac = Fq() M_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_mid = 0.5 * (M_bin[:-1] + M_bin[1:]) fq_list = [M_mid] for nd in nsnap_ds: des_tmp = des_dict[str(nd)] sfq = qfrac.Classify(des_tmp.mass, des_tmp.sfr, des_tmp.zsnap, sfms_prop=sim_kwargs['sfr_prop']['sfms']) ngal, dum = np.histogram(des_tmp.mass, bins=M_bin) ngal_q, dum = np.histogram(des_tmp.mass[sfq == 'quiescent'], bins=M_bin) fq_tmp = ngal_q.astype('float')/ngal.astype('float') fq_list += [fq_tmp] # ancesotr sfq = qfrac.Classify(inh.ancestor.mass, inh.ancestor.sfr, inh.ancestor.zsnap, sfms_prop=sim_kwargs['sfr_prop']['sfms']) ngal, dum = np.histogram(inh.ancestor.mass, bins=M_bin) ngal_q, dum = np.histogram(inh.ancestor.mass[sfq == 'quiescent'], bins=M_bin) fq_tmp = ngal_q.astype('float')/ngal.astype('float') fq_list += [fq_tmp] obvs.append(fq_list) if len(observables) == 1: obvs = obvs[0] return obvs
def ABC(T, eps_input, Npart=1000, cen_tf=None, cen_prior_name=None, cen_abcrun=None): ''' ABC-PMC implementation. Parameters ---------- T : (int) Number of iterations eps_input : (float) Starting epsilon threshold value N_part : (int) Number of particles prior_name : (string) String that specifies what prior to use. abcrun : (string) String that specifies abc run information ''' abcinh = ABCInherit(cen_tf, abcrun=cen_abcrun, prior_name=cen_prior_name) # Data (Group Catalog Satellite fQ) grpcat = GroupCat(Mrcut=18, position='satellite') grpcat.Read() qfrac = Fq() m_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_mid = 0.5 * (m_bin[:-1] + m_bin[1:]) sfq = qfrac.Classify(grpcat.mass, grpcat.sfr, np.median(grpcat.z), sfms_prop=abcinh.sim_kwargs['sfr_prop']['sfms']) ngal, dum = np.histogram(grpcat.mass, bins=m_bin) ngal_q, dum = np.histogram(grpcat.mass[sfq == 'quiescent'], bins=m_bin) data_sum = [M_mid, ngal_q.astype('float') / ngal.astype('float')] # Simulator cen_assigned_sat_file = ''.join([ '/data1/hahn/pmc_abc/pickle/', 'satellite', '.cenassign', '.', cen_abcrun, '_ABC', '.', cen_prior_name, '_prior', '.p' ]) if not os.path.isfile(cen_assigned_sat_file): sat_cen = AssignCenSFR(cen_tf, abcrun=cen_abcrun, prior_name=cen_prior_name) pickle.dump(sat_cen, open(cen_assigned_sat_file, 'wb')) else: sat_cen = pickle.load(open(cen_assigned_sat_file, 'rb')) def Simz(tt): # Simulator (forward model) tqdel_dict = {'name': 'explin', 'm': tt[0], 'b': tt[1]} sat_evol = EvolveSatSFR(sat_cen, tqdelay_dict=tqdel_dict) sfq_sim = qfrac.Classify(sat_evol.mass, sat_evol.sfr, sat_evol.zsnap, sfms_prop=sat_evol.sfms_prop) ngal_sim, dum = np.histogram(sat_evol.mass, bins=m_bin) ngal_q_sim, dum = np.histogram(sat_evol.mass[sfq_sim == 'quiescent'], bins=m_bin) sim_sum = [ M_mid, ngal_q_sim.astype('float') / ngal_sim.astype('float') ] return sim_sum # Priors prior_min = [-11.75, 2.] prior_max = [-10.25, 4.] prior = abcpmc.TophatPrior(prior_min, prior_max) # ABCPMC prior object def rho(simum, datum): datum_dist = datum[1] simum_dist = simum[1] drho = np.sum((datum_dist - simum_dist)**2) return drho abcrun_flag = cen_abcrun + '_central' theta_file = lambda pewl: ''.join([ code_dir(), 'dat/pmc_abc/', 'Satellite.tQdelay.theta_t', str(pewl), '_', abcrun_flag, '.dat' ]) w_file = lambda pewl: ''.join([ code_dir(), 'dat/pmc_abc/', 'Satellite.tQdelay.w_t', str(pewl), '_', abcrun_flag, '.dat' ]) dist_file = lambda pewl: ''.join([ code_dir(), 'dat/pmc_abc/', 'Satellite.tQdelay.dist_t', str(pewl), '_', abcrun_flag, '.dat' ]) eps_file = ''.join([ code_dir(), 'dat/pmc_abc/Satellite.tQdelay.epsilon_', abcrun_flag, '.dat' ]) eps = abcpmc.ConstEps(T, eps_input) try: mpi_pool = mpi_util.MpiPool() abcpmc_sampler = abcpmc.Sampler( N=Npart, # N_particles Y=data_sum, # data postfn=Simz, # simulator dist=rho, # distance function pool=mpi_pool) except AttributeError: abcpmc_sampler = abcpmc.Sampler( N=Npart, # N_particles Y=data_sum, # data postfn=Simz, # simulator dist=rho) # distance function abcpmc_sampler.particle_proposal_cls = abcpmc.ParticleProposal pools = [] f = open(eps_file, "w") f.close() eps_str = '' for pool in abcpmc_sampler.sample(prior, eps, pool=None): print '----------------------------------------' print 'eps ', pool.eps new_eps_str = '\t' + str(pool.eps) + '\n' if eps_str != new_eps_str: # if eps is different, open fiel and append f = open(eps_file, "a") eps_str = new_eps_str f.write(eps_str) f.close() print("T:{0},ratio: {1:>.4f}".format(pool.t, pool.ratio)) print eps(pool.t) # write theta, weights, and distances to file np.savetxt(theta_file(pool.t), pool.thetas, header='tQdelay_slope, tQdelay_offset') np.savetxt(w_file(pool.t), pool.ws) np.savetxt(dist_file(pool.t), pool.dists) # update epsilon based on median thresholding eps.eps = np.median(pool.dists) pools.append(pool) return pools
def EvolveSatSFR(sg_in, tqdelay_dict=None): ''' Evolve the infalling SFR assigned based on central galaxy SFRs ''' if tqdelay_dict == None: raise ValueError # initalize sg_obj = SGPop() sg_obj.ilk = sg_in.ilk.copy() sg_obj.pos = sg_in.pos.copy() sg_obj.snap_index = sg_in.snap_index.copy() sg_obj.zsnap = sg_in.zsnap.copy() sg_obj.t_cosmic = sg_in.t_cosmic.copy() sg_obj.sfms_prop = sg_in.sfms_prop.copy() sg_obj.abcrun = sg_in.abcrun sg_obj.prior_name = sg_in.prior_name sg_obj.mass = sg_in.mass.copy() sg_obj.sfr = np.repeat(-999., len(sg_obj.mass)) sg_obj.ssfr = np.repeat(-999., len(sg_obj.mass)) sg_obj.halo_mass = sg_in.halo_mass.copy() sg_obj.first_infall_nsnap = sg_in.first_infall_nsnap.copy() sg_obj.first_infall_z = sg_in.first_infall_z.copy() sg_obj.first_infall_t = sg_in.first_infall_t.copy() sg_obj.first_infall_sfr = sg_in.first_infall_sfr.copy() sg_obj.first_infall_mass = sg_in.first_infall_mass.copy() sg_obj.t_qstart = np.repeat(-999., len(sg_obj.mass)) sg_obj.z_qstart = np.repeat(-999., len(sg_obj.mass)) sg_obj.q_ssfr = np.repeat(-999., len(sg_obj.mass)) # First classify the galaxies into SF, Q, and Qing # this is so that t_Q,start = t_inf for Qing galaxies, # Q galaxies are left alone # SF galaxies are affected by the delay time infall = np.where((sg_obj.first_infall_mass > 0.) & (sg_obj.first_infall_sfr > -999.)) fq_obj = Fq() sfq_class = fq_obj.Classify(sg_obj.first_infall_mass[infall], sg_obj.first_infall_sfr[infall], sg_obj.first_infall_z[infall], sg_obj.sfms_prop) sf_infall = (infall[0])[np.where( sfq_class == 'star-forming')] # starforming @ infall q_infall = (infall[0])[np.where( sfq_class == 'quiescent')] # quiescent @ infall ssfr_final = sfr_evol.AverageLogSSFR_q_peak(sg_obj.mass[infall]) + \ sfr_evol.ScatterLogSSFR_q_peak(sg_obj.mass[infall]) * np.random.randn(len(infall[0])) # sub-divide the quiescent @ infall population to those that are # quenching @ infall + quiescent @ infall based on simple SSFR cut q_mass_infall = sg_obj.first_infall_mass[q_infall] q_sfr_infall = sg_obj.first_infall_sfr[q_infall] q_ssfr_infall = q_sfr_infall - q_mass_infall q_cut_SSFR = sfr_evol.AverageLogSSFR_q_peak(q_mass_infall) + \ 1.5 * sfr_evol.ScatterLogSSFR_q_peak(q_mass_infall) qing_infall = q_infall[np.where(q_ssfr_infall > q_cut_SSFR)] # quenching qq_infall = q_infall[np.where(q_ssfr_infall <= q_cut_SSFR)] # quenched # Quiescent @ infall----- # The SSFR is preserved from infall, so effectively their SFR decreases sg_obj.ssfr[qq_infall] = sg_obj.first_infall_sfr[qq_infall] - \ sg_obj.first_infall_mass[qq_infall] sg_obj.sfr[qq_infall] = sg_obj.mass[qq_infall] + sg_obj.ssfr[qq_infall] # Quenching @ infall----- # Quenching satellite galaxies skip the delay phase and immediately # start quenching when the simulation begins. sg_obj.t_qstart[qing_infall] = sg_obj.first_infall_t[qing_infall] sg_obj.z_qstart[qing_infall] = sg_obj.first_infall_z[qing_infall] sg_obj.q_ssfr[qing_infall] = sfr_evol.AverageLogSSFR_q_peak(sg_obj.mass[qing_infall]) + \ sfr_evol.ScatterLogSSFR_q_peak(sg_obj.mass[qing_infall]) * np.random.randn(len(qing_infall)) dlogSFR_MS_M = 0.53 * (sg_obj.mass[qing_infall] - sg_obj.first_infall_mass[qing_infall]) dlogSFR_MS_z = sg_obj.sfms_prop['zslope'] * ( sg_obj.zsnap - sg_obj.first_infall_z[qing_infall]) dlogSFR_Q = sfr_evol.DeltaLogSFR_quenching(sg_obj.t_qstart[qing_infall], sg_obj.t_cosmic, M_q=sg_obj.mass[qing_infall], tau_prop={'name': 'satellite'}) sg_obj.sfr[qing_infall] = sg_obj.first_infall_sfr[qing_infall] + \ dlogSFR_MS_M + dlogSFR_MS_z + dlogSFR_Q sg_obj.ssfr[ qing_infall] = sg_obj.sfr[qing_infall] - sg_obj.mass[qing_infall] # deal with over quenching #overquenched = np.where(sg_obj.ssfr[qing_infall] < sg_obj.q_ssfr[qing_infall]) #sg_obj.ssfr[qing_infall[overquenched]] = sg_obj.q_ssfr[qing_infall[overquenched]] # Star-forming @ infall if tqdelay_dict['name'] == 'hacked': sg_obj.t_qstart[sf_infall] = sg_obj.first_infall_t[sf_infall] + \ tDelay(sg_obj.mass[sf_infall], **tqdelay_dict) else: sg_obj.t_qstart[sf_infall] = sg_obj.first_infall_t[sf_infall] + \ tDelay(sg_obj.first_infall_mass[sf_infall], **tqdelay_dict) # if t_qstart > t_cosmic, then it does not quenching during the simualtion sf_q = np.where(sg_obj.t_qstart[sf_infall] < sg_obj.t_cosmic) sf_noq = np.where(sg_obj.t_qstart[sf_infall] >= sg_obj.t_cosmic) sf_infall_q = sf_infall[sf_q] sf_infall_noq = sf_infall[sf_noq] sg_obj.z_qstart[sf_infall_q] = Util.get_zsnap(sg_obj.t_qstart[sf_infall_q]) sg_obj.z_qstart[sf_infall_noq] = 999. # SF galaxies that quench sg_obj.q_ssfr[sf_infall_q] = \ sfr_evol.AverageLogSSFR_q_peak(sg_obj.mass[sf_infall_q]) + \ sfr_evol.ScatterLogSSFR_q_peak(sg_obj.mass[sf_infall_q]) * \ np.random.randn(len(sf_infall_q)) dlogSFR_MS_M = 0.53 * (sg_obj.mass[sf_infall_q] - sg_obj.first_infall_mass[sf_infall_q]) dlogSFR_MS_z = sg_obj.sfms_prop['zslope'] * ( sg_obj.zsnap - sg_obj.first_infall_z[sf_infall_q]) dlogSFR_Q = sfr_evol.DeltaLogSFR_quenching(sg_obj.t_qstart[sf_infall_q], sg_obj.t_cosmic, M_q=sg_obj.mass[sf_infall_q], tau_prop={'name': 'satellite'}) sg_obj.sfr[sf_infall_q] = sg_obj.first_infall_sfr[sf_infall_q] + \ dlogSFR_MS_M + dlogSFR_MS_z + dlogSFR_Q sg_obj.ssfr[ sf_infall_q] = sg_obj.sfr[sf_infall_q] - sg_obj.mass[sf_infall_q] # deal with over quenching #overquenched = np.where(sg_obj.ssfr[sf_infall_q] < sg_obj.q_ssfr[sf_infall_q]) #sg_obj.ssfr[sf_infall_q[overquenched]] = sg_obj.q_ssfr[sf_infall_q[overquenched]] # SF galaxies that do NOT quench dlogSFR_MS_M = 0.53 * (sg_obj.mass[sf_infall_noq] - sg_obj.first_infall_mass[sf_infall_noq]) dlogSFR_MS_z = sg_obj.sfms_prop['zslope'] * ( sg_obj.zsnap - sg_obj.first_infall_z[sf_infall_noq]) sg_obj.sfr[sf_infall_noq] = sg_obj.first_infall_sfr[sf_infall_noq] + \ dlogSFR_MS_M + dlogSFR_MS_z sg_obj.ssfr[ sf_infall_noq] = sg_obj.sfr[sf_infall_noq] - sg_obj.mass[sf_infall_noq] # deal with overquenching all at once overquench = np.where(sg_obj.ssfr[infall] < ssfr_final) sg_obj.ssfr[infall[0][overquench]] = ssfr_final[overquench] sg_obj.sfr[infall[0][overquench]] = ssfr_final[overquench] + sg_obj.mass[ infall[0][overquench]] return sg_obj
def AssignCenSFR(tf, abcrun=None, prior_name=None): ''' Given SGPop object, assign SFRs at infalling time based on the median ABC Run of the Central Galaxy evolution ''' if abcrun is None: raise ValueError if prior_name is None: raise ValueError abcinh = ABCInherit(tf, abcrun=abcrun, prior_name=prior_name) inh = abcinh.PickleLoad('all') sg_obj = SGPop() sg_obj.ImportSubhalo(subhalo_prop=abcinh.sim_kwargs['subhalo_prop']) sg_obj.sfms_prop = abcinh.sim_kwargs['sfr_prop']['sfms'] sg_obj.abcrun = abcrun sg_obj.prior_name = prior_name sg_obj.first_infall_sfr = np.repeat(-999., len(sg_obj.first_infall_nsnap)) for i_snap in range(2, abcinh.sim_kwargs['nsnap_ancestor']): infall_now = np.where((sg_obj.first_infall_nsnap == i_snap) & (sg_obj.first_infall_mass > 0.))[0] # satellite galaxies that end up massive but have 0. infalling mass #massive_infall_zero =np.where( # (sg_obj.first_infall_mass[infall_now] == 0.) & # (sg_obj.mass[infall_now] > 0.) # ) des_snap = inh[str(i_snap)] m_bins = np.arange(des_snap.mass.min() - 0.1, des_snap.mass.max() + 0.2, 0.2) for i_m in range(len(m_bins) - 1): in_massbin = np.where((des_snap.mass >= m_bins[i_m]) & (des_snap.mass < m_bins[i_m + 1])) infall_massbin = np.where( (sg_obj.first_infall_nsnap == i_snap) & (sg_obj.first_infall_mass >= m_bins[i_m]) & (sg_obj.first_infall_mass < m_bins[i_m + 1])) if len(infall_massbin[0]) == 0: continue des_ssfrs = des_snap.sfr[in_massbin] - des_snap.mass[in_massbin] pdf_ssfr_i, ssfr_binedges = np.histogram(des_ssfrs, bins=np.arange( -13.0, -8.0, 0.2), normed=True) cdf_ssfr_i = np.zeros(len(ssfr_binedges)) cdf_ssfr_i[1:] = np.cumsum(pdf_ssfr_i * np.diff(ssfr_binedges)) cdf_interp = interp1d(cdf_ssfr_i, ssfr_binedges, kind='linear') rand_i = np.random.uniform(size=len(infall_massbin[0])) sg_obj.first_infall_sfr[infall_massbin] = cdf_interp(rand_i) + \ sg_obj.first_infall_mass[infall_massbin] # assign SFR to galaxies that fell in before nsnap = 15 old_infall = np.where( (sg_obj.first_infall_nsnap >= abcinh.sim_kwargs['nsnap_ancestor']) & (sg_obj.first_infall_mass > 0.))[0] Pq = np.random.uniform(size=len(old_infall)) qfrac = Fq() fq_oldinfall = qfrac.model(sg_obj.first_infall_mass[old_infall], sg_obj.first_infall_z[old_infall], lit='wetzel') # star-forming sfing = np.where(Pq > fq_oldinfall) sig_sfms = sfr_evol.ScatterLogSFR_sfms( sg_obj.first_infall_mass[old_infall[sfing]], sg_obj.first_infall_z[old_infall[sfing]], sfms_prop=sg_obj.sfms_prop) mu_sfms = sfr_evol.AverageLogSFR_sfms( sg_obj.first_infall_mass[old_infall[sfing]], sg_obj.first_infall_z[old_infall[sfing]], sfms_prop=sg_obj.sfms_prop) sg_obj.first_infall_sfr[old_infall[sfing]] = mu_sfms + np.random.randn( len(sfing[0])) * sig_sfms # quiescent qed = np.where(Pq <= fq_oldinfall) mu_ssfr_q = sfr_evol.AverageLogSSFR_q_peak( sg_obj.first_infall_mass[old_infall[qed]]) sig_ssfr_q = sfr_evol.ScatterLogSSFR_q_peak( sg_obj.first_infall_mass[old_infall[qed]]) ssfr_q = mu_ssfr_q + np.random.randn(len(qed[0])) * sig_ssfr_q sg_obj.first_infall_sfr[ old_infall[qed]] = ssfr_q + sg_obj.first_infall_mass[old_infall[qed]] return sg_obj
def AssignCenSFR(tf, abcrun=None, prior_name=None): ''' Given SGPop object, assign SFRs at infalling time based on the median ABC Run of the Central Galaxy evolution ''' if abcrun is None: raise ValueError if prior_name is None: raise ValueError abcinh = ABCInherit(tf, abcrun=abcrun, prior_name=prior_name) inh = abcinh.PickleLoad('all') sg_obj = SGPop() sg_obj.ImportSubhalo(subhalo_prop=abcinh.sim_kwargs['subhalo_prop']) sg_obj.sfms_prop = abcinh.sim_kwargs['sfr_prop']['sfms'] sg_obj.abcrun = abcrun sg_obj.prior_name = prior_name sg_obj.first_infall_sfr = np.repeat(-999., len(sg_obj.first_infall_nsnap)) for i_snap in range(2, abcinh.sim_kwargs['nsnap_ancestor']): infall_now = np.where( (sg_obj.first_infall_nsnap == i_snap) & (sg_obj.first_infall_mass > 0.))[0] # satellite galaxies that end up massive but have 0. infalling mass #massive_infall_zero =np.where( # (sg_obj.first_infall_mass[infall_now] == 0.) & # (sg_obj.mass[infall_now] > 0.) # ) des_snap = inh[str(i_snap)] m_bins = np.arange(des_snap.mass.min()-0.1, des_snap.mass.max()+0.2, 0.2) for i_m in range(len(m_bins)-1): in_massbin = np.where( (des_snap.mass >= m_bins[i_m]) & (des_snap.mass < m_bins[i_m+1])) infall_massbin = np.where( (sg_obj.first_infall_nsnap == i_snap) & (sg_obj.first_infall_mass >= m_bins[i_m]) & (sg_obj.first_infall_mass < m_bins[i_m+1])) if len(infall_massbin[0]) == 0: continue des_ssfrs = des_snap.sfr[in_massbin] - des_snap.mass[in_massbin] pdf_ssfr_i, ssfr_binedges = np.histogram(des_ssfrs, bins=np.arange(-13.0, -8.0, 0.2), normed=True) cdf_ssfr_i = np.zeros(len(ssfr_binedges)) cdf_ssfr_i[1:] = np.cumsum(pdf_ssfr_i * np.diff(ssfr_binedges)) cdf_interp = interp1d(cdf_ssfr_i, ssfr_binedges, kind='linear') rand_i = np.random.uniform(size=len(infall_massbin[0])) sg_obj.first_infall_sfr[infall_massbin] = cdf_interp(rand_i) + \ sg_obj.first_infall_mass[infall_massbin] # assign SFR to galaxies that fell in before nsnap = 15 old_infall = np.where( (sg_obj.first_infall_nsnap >= abcinh.sim_kwargs['nsnap_ancestor']) & (sg_obj.first_infall_mass > 0.))[0] Pq = np.random.uniform(size=len(old_infall)) qfrac = Fq() fq_oldinfall = qfrac.model(sg_obj.first_infall_mass[old_infall], sg_obj.first_infall_z[old_infall], lit='wetzel') # star-forming sfing = np.where(Pq > fq_oldinfall) sig_sfms = sfr_evol.ScatterLogSFR_sfms( sg_obj.first_infall_mass[old_infall[sfing]], sg_obj.first_infall_z[old_infall[sfing]], sfms_prop=sg_obj.sfms_prop) mu_sfms = sfr_evol.AverageLogSFR_sfms( sg_obj.first_infall_mass[old_infall[sfing]], sg_obj.first_infall_z[old_infall[sfing]], sfms_prop=sg_obj.sfms_prop) sg_obj.first_infall_sfr[old_infall[sfing]] = mu_sfms + np.random.randn(len(sfing[0])) * sig_sfms # quiescent qed = np.where(Pq <= fq_oldinfall) mu_ssfr_q = sfr_evol.AverageLogSSFR_q_peak(sg_obj.first_infall_mass[old_infall[qed]]) sig_ssfr_q = sfr_evol.ScatterLogSSFR_q_peak(sg_obj.first_infall_mass[old_infall[qed]]) ssfr_q = mu_ssfr_q + np.random.randn(len(qed[0])) * sig_ssfr_q sg_obj.first_infall_sfr[old_infall[qed]] = ssfr_q + sg_obj.first_infall_mass[old_infall[qed]] return sg_obj
def DescendantQAplot(nsnap_descendants, **sfinh_kwargs): ''' The ultimate QAplot t rule them all. 4 panels showing all the properties. ''' sfinherit_file = InheritSF_file(nsnap_descendants, **sfinh_kwargs) bloodline = Lineage(nsnap_ancestor=sfinh_kwargs['nsnap_ancestor'], subhalo_prop=sfinh_kwargs['subhalo_prop']) if not isinstance(nsnap_descendants, list): nsnap_descendants = [nsnap_descendants] bloodline.Read(nsnap_descendants, filename=sfinherit_file) for nsnap_descendant in nsnap_descendants: descendant = getattr(bloodline, 'descendant_snapshot' + str(nsnap_descendant)) descendant.sfr_prop = sfinh_kwargs['sfr_prop'] started_here = np.where( descendant.nsnap_genesis == sfinh_kwargs['nsnap_ancestor']) start_mass = descendant.mass_genesis[started_here] # Mass bins mass_bins = np.arange(7., 12.5, 0.5) mass_bin_low = mass_bins[:-1] mass_bin_high = mass_bins[1:] plt.close() prettyplot() fig = plt.figure(1, figsize=[25, 6]) for i_sub in range(1, 5): sub_i = fig.add_subplot(1, 4, i_sub) if i_sub == 1: # SMF mf = SMF() mass, phi = mf.Obj(descendant) sub_i.plot(mass, phi, lw=4, c=pretty_colors[descendant.nsnap], label=r'Simulated') censub = CentralSubhalos() censub.Read(descendant.nsnap, scatter=sfinh_kwargs['subhalo_prop']['scatter'], source=sfinh_kwargs['subhalo_prop']['source'], nsnap_ancestor=sfinh_kwargs['nsnap_ancestor']) mass, phi = mf._smf(censub.mass) sub_i.plot(mass, phi, c='k', lw=4, ls='--', label='Central Subhalos') sub_i.set_ylim([10**-5, 10**-1]) sub_i.set_xlim([7.5, 12.0]) plt.xticks([8., 9., 10., 11., 12.]) sub_i.set_yscale('log') # x,y labels sub_i.set_xlabel(r'Mass $\mathtt{M_*}$', fontsize=25) sub_i.set_ylabel(r'Stellar Mass Function $\mathtt{\Phi}$', fontsize=25) sub_i.legend(loc='upper right', frameon=False) elif i_sub == 2: # SFMS # SMF composition based on their initial mass at nsnap_ancestor for i_m in range(len(mass_bin_low)): mbin = np.where((start_mass > mass_bin_low[i_m]) & (start_mass <= mass_bin_high[i_m])) sub_i.scatter(descendant.mass[started_here[0][mbin]], descendant.sfr[started_here[0][mbin]], color=pretty_colors[i_m], label=r"$\mathtt{M_{*,i}=}$" + str(round(mass_bin_low[i_m], 2)) + "-" + str(round(mass_bin_high[i_m], 2))) qfrac = Fq() m_arr = np.arange(9.0, 12.5, 0.5) sub_i.plot(m_arr, qfrac.SFRcut( m_arr, descendant.zsnap, sfms_prop=(sfinh_kwargs['sfr_prop'])['sfms']), c='k', ls='--', lw=4) sub_i.set_xlim([9.0, 12.0]) sub_i.set_ylim([-5.0, 2.0]) sub_i.set_xlabel(r'$\mathtt{log\;M_*}$', fontsize=25) sub_i.set_ylabel(r'$\mathtt{log\;SFR}$', fontsize=25) elif i_sub == 3: #SMHM for i_m in range(len(mass_bin_low)): mbin = np.where((start_mass > mass_bin_low[i_m]) & (start_mass <= mass_bin_high[i_m])) sub_i.scatter(descendant.halo_mass[started_here[0][mbin]], descendant.mass[started_here[0][mbin]], color=pretty_colors[i_m], label=r"$\mathtt{M_{*,i}=}$" + str(round(mass_bin_low[i_m], 2)) + "-" + str(round(mass_bin_high[i_m], 2))) stellarmass = descendant.mass[started_here] halomass = descendant.halo_mass[started_here] mbin = np.arange(halomass.min(), halomass.max(), 0.25) mlow = mbin[:-1] mhigh = mbin[1:] muMstar = np.zeros(len(mlow)) sigMstar = np.zeros(len(mlow)) for im in range(len(mlow)): mbin = np.where((halomass > mlow[im]) & (halomass <= mhigh[im])) muMstar[im] = np.mean(stellarmass[mbin]) sigMstar[im] = np.std(stellarmass[mbin]) sub_i.errorbar(0.5 * (mlow + mhigh), muMstar, yerr=sigMstar, color='k', lw=3, fmt='o', capthick=2) sub_i.set_ylim([9.0, 12.0]) sub_i.set_xlim([10.0, 15.0]) sub_i.set_ylabel(r'Stellar Mass $\mathtt{M_*}$', fontsize=25) sub_i.set_xlabel(r'Halo Mass $\mathtt{M_{Halo}}$', fontsize=25) #sub_i.legend(loc='upper left', frameon=False, scatterpoints=1) elif i_sub == 4: # Fq #mass, fq = descendant.Fq() sfq = qfrac.Classify(descendant.mass, descendant.sfr, descendant.zsnap, sfms_prop=descendant.sfr_prop['sfms']) gc = GroupCat(Mrcut=18, position='central') gc.Read() gc_sfq = qfrac.Classify(gc.mass, gc.sfr, np.mean(gc.z), sfms_prop=descendant.sfr_prop['sfms']) #sub_i.plot(mass, fq, color=pretty_colors[descendant.nsnap], lw=3, ls='--', # label=r'$\mathtt{z =} '+str(descendant.zsnap)+'$') M_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_low = M_bin[:-1] M_high = M_bin[1:] M_mid = 0.5 * (M_low + M_high) fq = np.zeros(len(M_low)) gc_fq = np.zeros(len(M_low)) for i_m in xrange(len(M_low)): mlim = np.where((descendant.mass > M_low[i_m]) & (descendant.mass <= M_high[i_m])) gc_mlim = np.where((gc.mass > M_low[i_m]) & (gc.mass <= M_high[i_m])) ngal = np.float(len(mlim[0])) gc_ngal = np.float(len(gc_mlim[0])) if ngal != 0: # no galaxy in mass bin ngal_q = np.float( len(np.where(sfq[mlim] == 'quiescent')[0])) fq[i_m] = ngal_q / ngal if gc_ngal != 0: gc_ngal_q = np.float( len(np.where(gc_sfq[gc_mlim] == 'quiescent')[0])) gc_fq[i_m] = gc_ngal_q / gc_ngal sub_i.plot(M_mid, fq, color=pretty_colors[descendant.nsnap], lw=3, label=r'$\mathtt{z =} ' + str(descendant.zsnap) + '$') fq_model = qfrac.model( M_bin, descendant.zsnap, lit=sfinh_kwargs['sfr_prop']['fq']['name']) sub_i.plot(M_bin, fq_model, color='k', lw=4, ls='--', label=sfinh_kwargs['sfr_prop']['fq']['name']) sub_i.scatter(M_mid, gc_fq, color='k', s=100, lw=0, label='Group Catalog') sub_i.set_xlim([9.0, 12.0]) sub_i.set_ylim([0.0, 1.0]) sub_i.set_xlabel(r'Mass $\mathtt{M_*}$') sub_i.set_ylabel(r'Quiescent Fraction $\mathtt{f_Q}$', fontsize=20) sub_i.legend(loc='upper left', frameon=False, scatterpoints=1, markerscale=0.75) plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) fig_name = ''.join([ 'figure/test/', 'QAplot.', '.nsnap', str(nsnap_descendant), '.'.join( (sfinherit_file.rsplit('/')[-1]).rsplit('.')[:-1]), '.png' ]) fig.savefig(fig_name, bbox_inches='tight') plt.close() return None
def AssignSFR(mass, redshift, sfr_prop=None, ancestor=None, descendant=None, quiet=True): ''' Assign star-forming properties based on the input mass and redshift. Return sfr_class (star-forming or quiescent), SFR, and sSFR given a set of masses and redshifts. Parameters ---------- mass : array Array of galaxy stellar mass redshift : array Array of corresponding galaxy redshift sfr_prop : dictionary Dictionary that specifies the star-forming properties. Notes ----- * Takes ~1.5 seconds for assign_sfr_ancestor in lineage object ''' if sfr_prop is None: raise ValueError('Specify SFR Properties dictionary') # Dictionaries that specify fQ, SFMS, f_GV fq_dict = sfr_prop['fq'] sfms_dict = sfr_prop['sfms'] gv_dict = sfr_prop['gv'] if 'subhalogrowth' in sfr_prop.keys(): if descendant is None: raise ValueError if ancestor is None: raise ValueError for key in descendant.__dict__.keys(): if 'ancestor' in key: ancestor_index = getattr(descendant, key) ngal = len(mass) # Ngal sfr_class= np.repeat('', ngal).astype('|S16') sfr = np.repeat(-999., ngal) ssfr = np.repeat(-999., ngal) delta_sfr = np.repeat(-999., ngal) avg_sfr = np.repeat(-999., ngal) tQ = np.repeat(999., ngal) MQ = np.repeat(-999., ngal) qfrac = Fq() # Fq object M_bins = np.arange(6.0, 13., 0.5) # mass bin M_mid = 0.5 * (M_bins[:-1] + M_bins[1:]) # For z = z_ancestor massive = np.where((mass > 0.0) & (redshift == redshift.max()))[0] ngal = len(massive) ngal_M, dum = np.histogram(mass[massive], bins=M_bins) np.random.seed() rand = np.random.uniform(0., 1., ngal) # f_GV(M*) Green valley fraction gvfrac = gv_dict['slope'] * (mass[massive] - gv_dict['fidmass']) + gv_dict['offset'] greenvalley = np.where(rand < gvfrac)[0] ngal_green = len(greenvalley) ngal_green_M, dum = np.histogram(mass[massive[greenvalley]], bins=M_bins) if not quiet: print ngal_green, ' green valley galaxies out of ', ngal, ' galaxies' sfr_class[massive[greenvalley]] = 'star-forming' # classified as star-forming ssfr_q_peak = AverageLogSSFR_q_peak(mass[massive[greenvalley]]) # Q peak SSFR value ssfr_sf_peak = AverageLogSFR_sfms(mass[massive[greenvalley]], # SF peak SSFR value redshift[massive[greenvalley]], sfms_prop=sfms_dict) - mass[massive[greenvalley]] ssfr[massive[greenvalley]] = np.random.uniform(ssfr_q_peak, ssfr_sf_peak, ngal_green) sfr[massive[greenvalley]] = ssfr[massive[greenvalley]] + mass[massive[greenvalley]] tQ[massive[greenvalley]] = Util.get_tsnap(redshift.max()) # quenching cosmic time MQ[massive[greenvalley]] = mass[massive[greenvalley]] # some green valley galaxies will be classified in observations as # quiescent or star-forming. green_class = qfrac.Classify( mass[massive[greenvalley]], sfr[massive[greenvalley]], redshift[massive[greenvalley]], sfms_prop=sfms_dict) GQ = np.where(green_class == 'quiescent') ngal_GQ = len(GQ[0]) ngal_GQ_M, dum = np.histogram(mass[massive[greenvalley[GQ]]], bins=M_bins) # f_Q(M*, z) for each massive galaxy fq_M = qfrac.model(M_mid, redshift.max(), lit=fq_dict['name']) fq_prime_arr = (ngal_M * fq_M - ngal_GQ_M)/(ngal_M - ngal_green_M) fq_prime_arr[np.where(ngal_M == 0)] = 0. fq_prime_M = interpolate.interp1d(M_mid, fq_prime_arr, kind='linear') # assign SFR to the not so green valley notgreenvalley = np.where(rand >= gvfrac)[0] ngal_notgreenvalley = len(notgreenvalley) rand_notgreen = np.random.uniform(0., 1., ngal_notgreenvalley) fq_prime = fq_prime_M(mass[massive[notgreenvalley]]) # fQ' lowz = np.where((mass > 0.0) & (redshift != redshift.max()))[0] ngal_lowz = len(lowz) rand_lowz = np.random.uniform(0., 1., ngal_lowz) fq_lowz = qfrac.model(mass[lowz], redshift[lowz], lit=fq_dict['name']) quiescent = np.concatenate([ massive[notgreenvalley[np.where(rand_notgreen < fq_prime)]], lowz[np.where(rand_lowz < fq_lowz)]]) starforming = np.concatenate([ massive[notgreenvalley[np.where(rand_notgreen >= fq_prime)]], lowz[np.where(rand_lowz >= fq_lowz)]]) ngal_q = len(quiescent) ngal_sf = len(starforming) # Assign SFR to quiescent galaxies sfr_class[quiescent] = 'quiescent' mu_q_ssfr = AverageLogSSFR_q_peak(mass[quiescent]) sig_q_ssfr = ScatterLogSSFR_q_peak(mass[quiescent]) ssfr[quiescent] = sig_q_ssfr * np.random.randn(ngal_q) + mu_q_ssfr sfr[quiescent] = ssfr[quiescent] + mass[quiescent] # Assign SFR to star-forming galaxies sfr_class[starforming] = 'star-forming' mu_sf_sfr = AverageLogSFR_sfms( mass[starforming], redshift[starforming], sfms_prop=sfms_dict) sigma_sf_sfr = ScatterLogSFR_sfms( mass[starforming], redshift[starforming], sfms_prop=sfms_dict) avg_sfr[starforming] = mu_sf_sfr delta_sfr[starforming] = sigma_sf_sfr * np.random.randn(ngal_sf) sfr[starforming] = mu_sf_sfr + delta_sfr[starforming] ssfr[starforming] = sfr[starforming] - mass[starforming] if 'subhalogrowth' in sfr_prop.keys(): # if SFR assignment is dependent on subhalo growth, # loop through mass bins and assign SFR by abundance matching the # SFR to the Delta M*_sham. mass_range = np.arange(mass[starforming].min(), mass[starforming].max(), 0.1) m_low = mass_range[:-1] m_high = mass_range[1:] for im in range(len(m_low)): sf_mass_bin = np.where( (mass[starforming] > m_low[im]) & (mass[starforming] <= m_high[im]))[0] succession, will = Util.intersection_index( ancestor_index, ancestor.snap_index[starforming]) deltaM = descendant.mass[succession] - mass[starforming[will]] dM_sort_index = np.argsort(deltaM) deltaSFR = sigma_sf_sfr * np.random.randn(len(deltaM)) dSFR_sort_index = np.argsort(deltaSFR) # abundance matched. delta_sfr[starforming[will[dM_sort_index]]] = deltaSFR[dSFR_sort_index] sfr[starforming] = mu_sf_sfr + delta_sfr[starforming] ssfr[starforming] = sfr[starforming] - mass[starforming] return [sfr_class, sfr, ssfr, delta_sfr, avg_sfr, tQ, MQ]
def AssignSFR(mass, redshift, sfr_prop=None, ancestor=None, descendant=None, quiet=True): ''' Assign star-forming properties based on the input mass and redshift. Return sfr_class (star-forming or quiescent), SFR, and sSFR given a set of masses and redshifts. Parameters ---------- mass : array Array of galaxy stellar mass redshift : array Array of corresponding galaxy redshift sfr_prop : dictionary Dictionary that specifies the star-forming properties. Notes ----- * Takes ~1.5 seconds for assign_sfr_ancestor in lineage object ''' if sfr_prop is None: raise ValueError('Specify SFR Properties dictionary') # Dictionaries that specify fQ, SFMS, f_GV fq_dict = sfr_prop['fq'] sfms_dict = sfr_prop['sfms'] gv_dict = sfr_prop['gv'] if 'subhalogrowth' in sfr_prop.keys(): if descendant is None: raise ValueError if ancestor is None: raise ValueError for key in descendant.__dict__.keys(): if 'ancestor' in key: ancestor_index = getattr(descendant, key) ngal = len(mass) # Ngal sfr_class = np.repeat('', ngal).astype('|S16') sfr = np.repeat(-999., ngal) ssfr = np.repeat(-999., ngal) delta_sfr = np.repeat(-999., ngal) avg_sfr = np.repeat(-999., ngal) tQ = np.repeat(999., ngal) MQ = np.repeat(-999., ngal) qfrac = Fq() # Fq object M_bins = np.arange(6.0, 13., 0.5) # mass bin M_mid = 0.5 * (M_bins[:-1] + M_bins[1:]) # For z = z_ancestor massive = np.where((mass > 0.0) & (redshift == redshift.max()))[0] ngal = len(massive) ngal_M, dum = np.histogram(mass[massive], bins=M_bins) np.random.seed() rand = np.random.uniform(0., 1., ngal) # f_GV(M*) Green valley fraction gvfrac = gv_dict['slope'] * (mass[massive] - gv_dict['fidmass']) + gv_dict['offset'] greenvalley = np.where(rand < gvfrac)[0] ngal_green = len(greenvalley) ngal_green_M, dum = np.histogram(mass[massive[greenvalley]], bins=M_bins) if not quiet: print ngal_green, ' green valley galaxies out of ', ngal, ' galaxies' sfr_class[ massive[greenvalley]] = 'star-forming' # classified as star-forming ssfr_q_peak = AverageLogSSFR_q_peak( mass[massive[greenvalley]]) # Q peak SSFR value ssfr_sf_peak = AverageLogSFR_sfms( mass[massive[greenvalley]], # SF peak SSFR value redshift[massive[greenvalley]], sfms_prop=sfms_dict) - mass[massive[greenvalley]] ssfr[massive[greenvalley]] = np.random.uniform(ssfr_q_peak, ssfr_sf_peak, ngal_green) sfr[massive[greenvalley]] = ssfr[massive[greenvalley]] + mass[ massive[greenvalley]] tQ[massive[greenvalley]] = Util.get_tsnap( redshift.max()) # quenching cosmic time MQ[massive[greenvalley]] = mass[massive[greenvalley]] # some green valley galaxies will be classified in observations as # quiescent or star-forming. green_class = qfrac.Classify(mass[massive[greenvalley]], sfr[massive[greenvalley]], redshift[massive[greenvalley]], sfms_prop=sfms_dict) GQ = np.where(green_class == 'quiescent') ngal_GQ = len(GQ[0]) ngal_GQ_M, dum = np.histogram(mass[massive[greenvalley[GQ]]], bins=M_bins) # f_Q(M*, z) for each massive galaxy fq_M = qfrac.model(M_mid, redshift.max(), lit=fq_dict['name']) fq_prime_arr = (ngal_M * fq_M - ngal_GQ_M) / (ngal_M - ngal_green_M) fq_prime_arr[np.where(ngal_M == 0)] = 0. fq_prime_M = interpolate.interp1d(M_mid, fq_prime_arr, kind='linear') # assign SFR to the not so green valley notgreenvalley = np.where(rand >= gvfrac)[0] ngal_notgreenvalley = len(notgreenvalley) rand_notgreen = np.random.uniform(0., 1., ngal_notgreenvalley) fq_prime = fq_prime_M(mass[massive[notgreenvalley]]) # fQ' lowz = np.where((mass > 0.0) & (redshift != redshift.max()))[0] ngal_lowz = len(lowz) rand_lowz = np.random.uniform(0., 1., ngal_lowz) fq_lowz = qfrac.model(mass[lowz], redshift[lowz], lit=fq_dict['name']) quiescent = np.concatenate([ massive[notgreenvalley[np.where(rand_notgreen < fq_prime)]], lowz[np.where(rand_lowz < fq_lowz)] ]) starforming = np.concatenate([ massive[notgreenvalley[np.where(rand_notgreen >= fq_prime)]], lowz[np.where(rand_lowz >= fq_lowz)] ]) ngal_q = len(quiescent) ngal_sf = len(starforming) # Assign SFR to quiescent galaxies sfr_class[quiescent] = 'quiescent' mu_q_ssfr = AverageLogSSFR_q_peak(mass[quiescent]) sig_q_ssfr = ScatterLogSSFR_q_peak(mass[quiescent]) ssfr[quiescent] = sig_q_ssfr * np.random.randn(ngal_q) + mu_q_ssfr sfr[quiescent] = ssfr[quiescent] + mass[quiescent] # Assign SFR to star-forming galaxies sfr_class[starforming] = 'star-forming' mu_sf_sfr = AverageLogSFR_sfms(mass[starforming], redshift[starforming], sfms_prop=sfms_dict) sigma_sf_sfr = ScatterLogSFR_sfms(mass[starforming], redshift[starforming], sfms_prop=sfms_dict) avg_sfr[starforming] = mu_sf_sfr delta_sfr[starforming] = sigma_sf_sfr * np.random.randn(ngal_sf) sfr[starforming] = mu_sf_sfr + delta_sfr[starforming] ssfr[starforming] = sfr[starforming] - mass[starforming] if 'subhalogrowth' in sfr_prop.keys(): # if SFR assignment is dependent on subhalo growth, # loop through mass bins and assign SFR by abundance matching the # SFR to the Delta M*_sham. mass_range = np.arange(mass[starforming].min(), mass[starforming].max(), 0.1) m_low = mass_range[:-1] m_high = mass_range[1:] for im in range(len(m_low)): sf_mass_bin = np.where((mass[starforming] > m_low[im]) & (mass[starforming] <= m_high[im]))[0] succession, will = Util.intersection_index( ancestor_index, ancestor.snap_index[starforming]) deltaM = descendant.mass[succession] - mass[starforming[will]] dM_sort_index = np.argsort(deltaM) deltaSFR = sigma_sf_sfr * np.random.randn(len(deltaM)) dSFR_sort_index = np.argsort(deltaSFR) # abundance matched. delta_sfr[starforming[ will[dM_sort_index]]] = deltaSFR[dSFR_sort_index] sfr[starforming] = mu_sf_sfr + delta_sfr[starforming] ssfr[starforming] = sfr[starforming] - mass[starforming] return [sfr_class, sfr, ssfr, delta_sfr, avg_sfr, tQ, MQ]
def DescendantQAplot(nsnap_descendants, **sfinh_kwargs): ''' The ultimate QAplot t rule them all. 4 panels showing all the properties. ''' sfinherit_file = InheritSF_file(nsnap_descendants, **sfinh_kwargs) bloodline = Lineage( nsnap_ancestor=sfinh_kwargs['nsnap_ancestor'], subhalo_prop=sfinh_kwargs['subhalo_prop'] ) if not isinstance(nsnap_descendants, list): nsnap_descendants = [nsnap_descendants] bloodline.Read(nsnap_descendants, filename=sfinherit_file) for nsnap_descendant in nsnap_descendants: descendant = getattr(bloodline, 'descendant_snapshot'+str(nsnap_descendant)) descendant.sfr_prop = sfinh_kwargs['sfr_prop'] started_here = np.where(descendant.nsnap_genesis == sfinh_kwargs['nsnap_ancestor']) start_mass = descendant.mass_genesis[started_here] # Mass bins mass_bins = np.arange(7., 12.5, 0.5) mass_bin_low = mass_bins[:-1] mass_bin_high = mass_bins[1:] plt.close() prettyplot() fig = plt.figure(1, figsize=[25,6]) for i_sub in range(1,5): sub_i = fig.add_subplot(1,4,i_sub) if i_sub == 1: # SMF mf = SMF() mass, phi = mf.Obj(descendant) sub_i.plot(mass, phi, lw=4, c=pretty_colors[descendant.nsnap], label=r'Simulated') censub = CentralSubhalos() censub.Read(descendant.nsnap, scatter=sfinh_kwargs['subhalo_prop']['scatter'], source=sfinh_kwargs['subhalo_prop']['source'], nsnap_ancestor=sfinh_kwargs['nsnap_ancestor']) mass, phi = mf._smf(censub.mass) sub_i.plot(mass, phi, c='k', lw=4, ls='--', label='Central Subhalos') sub_i.set_ylim([10**-5, 10**-1]) sub_i.set_xlim([7.5, 12.0]) plt.xticks([8., 9., 10., 11., 12.]) sub_i.set_yscale('log') # x,y labels sub_i.set_xlabel(r'Mass $\mathtt{M_*}$', fontsize=25) sub_i.set_ylabel(r'Stellar Mass Function $\mathtt{\Phi}$', fontsize=25) sub_i.legend(loc='upper right', frameon=False) elif i_sub == 2: # SFMS # SMF composition based on their initial mass at nsnap_ancestor for i_m in range(len(mass_bin_low)): mbin = np.where((start_mass > mass_bin_low[i_m]) & (start_mass <= mass_bin_high[i_m])) sub_i.scatter( descendant.mass[started_here[0][mbin]], descendant.sfr[started_here[0][mbin]], color=pretty_colors[i_m], label=r"$\mathtt{M_{*,i}=}$"+str(round(mass_bin_low[i_m],2))+"-"+str(round(mass_bin_high[i_m],2)) ) qfrac = Fq() m_arr = np.arange(9.0, 12.5, 0.5) sub_i.plot( m_arr, qfrac.SFRcut(m_arr, descendant.zsnap, sfms_prop=(sfinh_kwargs['sfr_prop'])['sfms']), c='k', ls='--', lw=4) sub_i.set_xlim([9.0, 12.0]) sub_i.set_ylim([-5.0, 2.0]) sub_i.set_xlabel(r'$\mathtt{log\;M_*}$', fontsize=25) sub_i.set_ylabel(r'$\mathtt{log\;SFR}$', fontsize=25) elif i_sub == 3: #SMHM for i_m in range(len(mass_bin_low)): mbin = np.where((start_mass > mass_bin_low[i_m]) & (start_mass <= mass_bin_high[i_m])) sub_i.scatter( descendant.halo_mass[started_here[0][mbin]], descendant.mass[started_here[0][mbin]], color=pretty_colors[i_m], label=r"$\mathtt{M_{*,i}=}$"+str(round(mass_bin_low[i_m],2))+"-"+str(round(mass_bin_high[i_m],2)) ) stellarmass = descendant.mass[started_here] halomass = descendant.halo_mass[started_here] mbin = np.arange(halomass.min(), halomass.max(), 0.25) mlow = mbin[:-1] mhigh = mbin[1:] muMstar = np.zeros(len(mlow)) sigMstar = np.zeros(len(mlow)) for im in range(len(mlow)): mbin = np.where((halomass > mlow[im]) & (halomass <= mhigh[im])) muMstar[im] = np.mean(stellarmass[mbin]) sigMstar[im] = np.std(stellarmass[mbin]) sub_i.errorbar(0.5*(mlow+mhigh), muMstar, yerr=sigMstar, color='k', lw=3, fmt='o', capthick=2) sub_i.set_ylim([9.0, 12.0]) sub_i.set_xlim([10.0, 15.0]) sub_i.set_ylabel(r'Stellar Mass $\mathtt{M_*}$', fontsize=25) sub_i.set_xlabel(r'Halo Mass $\mathtt{M_{Halo}}$', fontsize=25) #sub_i.legend(loc='upper left', frameon=False, scatterpoints=1) elif i_sub == 4: # Fq #mass, fq = descendant.Fq() sfq = qfrac.Classify(descendant.mass, descendant.sfr, descendant.zsnap, sfms_prop=descendant.sfr_prop['sfms']) gc = GroupCat(Mrcut=18, position='central') gc.Read() gc_sfq = qfrac.Classify(gc.mass, gc.sfr, np.mean(gc.z), sfms_prop=descendant.sfr_prop['sfms']) #sub_i.plot(mass, fq, color=pretty_colors[descendant.nsnap], lw=3, ls='--', # label=r'$\mathtt{z =} '+str(descendant.zsnap)+'$') M_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_low = M_bin[:-1] M_high = M_bin[1:] M_mid = 0.5 * (M_low + M_high) fq = np.zeros(len(M_low)) gc_fq = np.zeros(len(M_low)) for i_m in xrange(len(M_low)): mlim = np.where((descendant.mass > M_low[i_m]) & (descendant.mass <= M_high[i_m])) gc_mlim = np.where((gc.mass > M_low[i_m]) & (gc.mass <= M_high[i_m])) ngal = np.float(len(mlim[0])) gc_ngal = np.float(len(gc_mlim[0])) if ngal != 0: # no galaxy in mass bin ngal_q = np.float(len(np.where(sfq[mlim] == 'quiescent')[0])) fq[i_m] = ngal_q/ngal if gc_ngal != 0: gc_ngal_q = np.float(len(np.where(gc_sfq[gc_mlim] == 'quiescent')[0])) gc_fq[i_m] = gc_ngal_q/gc_ngal sub_i.plot(M_mid, fq, color=pretty_colors[descendant.nsnap], lw=3, label=r'$\mathtt{z =} '+str(descendant.zsnap)+'$') fq_model = qfrac.model(M_bin, descendant.zsnap, lit=sfinh_kwargs['sfr_prop']['fq']['name']) sub_i.plot(M_bin, fq_model, color='k', lw=4, ls='--', label=sfinh_kwargs['sfr_prop']['fq']['name']) sub_i.scatter(M_mid, gc_fq, color='k', s=100, lw=0, label='Group Catalog') sub_i.set_xlim([9.0, 12.0]) sub_i.set_ylim([0.0, 1.0]) sub_i.set_xlabel(r'Mass $\mathtt{M_*}$') sub_i.set_ylabel(r'Quiescent Fraction $\mathtt{f_Q}$', fontsize=20) sub_i.legend(loc='upper left', frameon=False, scatterpoints=1, markerscale=0.75) plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) fig_name = ''.join([ 'figure/test/', 'QAplot.', '.nsnap', str(nsnap_descendant), '.'.join((sfinherit_file.rsplit('/')[-1]).rsplit('.')[:-1]), '.png']) fig.savefig(fig_name, bbox_inches='tight') plt.close() return None
def plot(self, mass=None, ssfr=None, SSFRdist=None, sfms_prop=None, z=None, **pltkwargs): ''' Plot the sSFR distriubiton ''' if self.kwargs == {}: kwargs = pltkwargs.copy() else: kwargs = (self.kwargs).copy() kwargs.update(pltkwargs) if SSFRdist is not None: ssfr_bin_mid, ssfr_dist = SSFRdist else: if mass is None or ssfr is None: raise ValueError else: Ssfr_obj = Ssfr() ssfr_bin_mid, ssfr_dist = Ssfr_obj.Calculate(mass, ssfr) # loop through mass bin for i_mass, panel_mass in enumerate(self.panel_mass_bins): # plot configuration if 'label' in kwargs: # label hist_label = kwargs['label'] else: hist_label = None # line color if 'line_color' in kwargs: if isinstance(kwargs['line_color'], str): line_color = kwargs['line_color'] elif isinstance(kwargs['line_color'], int): line_color = self.pretty_colors[kwargs['line_color']] else: line_color = 'black' # line style if 'line_style' in kwargs: line_style = kwargs['line_style'] else: line_style = '-' # line width if 'lw' in kwargs: line_width = kwargs['lw'] else: line_width = 4 if 'alpha' in kwargs: alpha = kwargs['alpha'] else: alpha = 1 self.subs[i_mass].plot( ssfr_bin_mid[i_mass], ssfr_dist[i_mass], color=line_color, lw=line_width, ls=line_style, label=hist_label, alpha=alpha ) if sfms_prop is not None: if z is None: raise ValueError qf = Fq() self.subs[i_mass].vlines( qf.SFRcut(np.array([np.mean(panel_mass)]), z, sfms_prop=sfms_prop )-np.mean(panel_mass), 0., 100., lw=3, linestyle='--', color='k') if i_mass == 2: #plt.sca(self.subs[i_mass]) self.subs[i_mass].set_xticks([-13, -12, -11, -10, -9, -8]) self.subs[i_mass].set_yticks([0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4]) return None
def PlotObservedSSFR(observable, isedfit=False, Peak=False): ''' ''' prettyplot() if Peak and 'groupcat' not in observable: raise ValeuError mass_bins = [[9.7, 10.1], [10.1, 10.5], [10.5, 10.9], [10.9, 11.3]] if 'groupcat' in observable: zbins = [0.03] elif observable == 'sdssprimus': zbins = [0.1, 0.3, 0.5, 0.7, 0.9] qf = Fq() for i_z, z in enumerate(zbins): fig = plt.figure(figsize=(16, 16)) fig.subplots_adjust(hspace=0., wspace=0.) subs = [fig.add_subplot(2, 2, i_mass + 1) for i_mass in xrange(4)] # preset kwargs for group and SDSS+PRIMUS catalogs if 'groupcat' in observable: if 'sat' in observable: obs_str = 'Group Catalog Satellites' censat = 'satellite' elif 'cen' in observable: obs_str = 'Group Catalog Centrals' censat = 'central' file_flag = observable if not isedfit: kwargs = {'Mrcut': 18, 'position': censat} file_flag += '' else: kwargs = {'Mrcut': 18, 'position': censat, 'isedfit': True} obs_str += ' iSEDfit' file_flag += 'isedfit' else: obs_str = 'iSEDfit z=' + str(round(z, 2)) kwargs = {'redshift': z, 'environment': 'no'} # SSFR SF peak fit if Peak: sfpeakfit = FitObservedSSFR_Peaks(observable=observable, sfq='star-forming', **kwargs) qpeakfit = FitObservedSSFR_Peaks(observable=observable, sfq='quiescent', **kwargs) print 'SF Slope ', sfpeakfit[0], ', Offset ', sfpeakfit[1] print 'Q Slope ', qpeakfit[0], ', Offset ', qpeakfit[1] ssfr_bin_mid, ssfr_dist = ObservedSSFR(observable, **kwargs) for i_mass, mbin in enumerate(mass_bins): subs[i_mass].plot(ssfr_bin_mid[i_mass], ssfr_dist[i_mass], color='k', lw=4, ls='-', label=None) if Peak: ssfr_sfpeak = sfpeakfit[0] * ( np.mean(mbin) - 10.5) + sfpeakfit[1] - np.mean(mbin) subs[i_mass].vlines(ssfr_sfpeak, 0.0, 100., lw=3, linestyle='--', color='blue') ssfr_qpeak = qpeakfit[0] * (np.mean(mbin) - 10.5) + qpeakfit[1] - np.mean(mbin) subs[i_mass].vlines(ssfr_qpeak, 0.0, 100., lw=3, linestyle='--', color='red') subs[i_mass].vlines(qf.SFRcut(np.array([np.mean(mbin)]), z, sfms_prop={ 'name': 'kinked', 'mslope_lowmass': 0.7, 'zslope': 1.5 }) - np.mean(mbin), 0., 100., lw=3, linestyle='--', color='k') subs[i_mass].set_xlim([-13.0, -7.0]) subs[i_mass].set_ylim([0.0, 1.6]) massbin_str = ''.join([ r'$\mathtt{log \; M_{*} = [', str(mass_bins[i_mass][0]), ',\;', str(mass_bins[i_mass][1]), ']}$' ]) subs[i_mass].text(-10.5, 1.4, massbin_str, fontsize=24) if i_mass == 0: subs[i_mass].set_ylabel(r'$\mathtt{P(log \; SSFR)}$', fontsize=20) subs[i_mass].set_xticklabels([]) elif i_mass == 1: subs[i_mass].set_xticklabels([]) subs[i_mass].set_yticklabels([]) elif i_mass == 2: #sub.set_yticklabels([]) subs[i_mass].set_ylabel(r'$\mathtt{P(log \; SSFR)}$', fontsize=20) subs[i_mass].set_xlabel(r'$\mathtt{log \; SSFR \;[yr^{-1}]}$', fontsize=20) else: subs[i_mass].set_yticklabels([]) subs[i_mass].set_xlabel(r'$\mathtt{log \; SSFR \;[yr^{-1}]}$', fontsize=20) #subs[i_mass].legend(loc='lower right', frameon=False) fig_file = ''.join([ 'figure/test/' 'observedSSFR', observable, '.z', str(round(z, 2)), '.png' ]) fig.savefig(fig_file, bbox_inches='tight', dpi=150) return None
def _Evol_MshamSFR(self, nsnap_d, allwill, sf_ancestor, q_ancestor): ''' Evolve SFR of the SF galaxies while quenching some of them at the same time. Notes ----- * SF galaxies are quenched based on the following prescription: The number of galaxies that start quenching between t0 and t0+tstep is determined by first guessing, N_quenching = N_sf(t0) * (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep ''' tQ0 = self.ancestor.tQ[allwill[sf_ancestor]].copy() tQ = self.ancestor.tQ[allwill[sf_ancestor]].copy() Mq = self.ancestor.MQ[allwill[sf_ancestor]].copy() # earliest starting time (cosmic time of ancestor snapshot) t0 = self.ancestor.tsnap_genesis[allwill[sf_ancestor]].copy() t00 = t0.min() i_low = np.abs(t_snap - np.max(self.tsnap_descendants)).argmin() - 1 i_high = np.abs(t_snap - t00).argmin() + 1 t_evol = t_snap[i_low:i_high][::-1] qf = Fq() Fq_anal = qf.model M_bins = np.arange(5.5, 13., 0.5) M_mid = 0.5 * (M_bins[:-1] + M_bins[1:]) q_Mshams = self.MshamEvol[allwill[q_ancestor], :].copy() sf_Mshams = self.MshamEvol[allwill[sf_ancestor], :].copy() for i_t, tt in enumerate(t_evol[:-1]): t_step = t_evol[i_t + 1] - tt if not self.quiet: print 't_cosmic = ', tt t_one_tstep = time.time() # M_sham of the quiescent galaxies at the closest snapshot. closest_t0_snap = np.abs(t_snap - tt).argmin() - 1 Msham_q0 = q_Mshams[:, closest_t0_snap] Msham_sf0 = sf_Mshams[:, closest_t0_snap] within = np.where( (Msham_sf0 > 0.) & (t0 <= tt)) # tsnap_genesis <= t sf_within = np.where((Msham_sf0 > 0.) & (t0 <= tt) & (tQ == 999.))[ 0] # Not quenching SF galaxies Nsf_0 = len(sf_within) M_t0_sample = np.concatenate( [Msham_sf0[within], Msham_q0[np.where(Msham_q0 > 0.)]]) P_sf = np.random.uniform(0., 1., Nsf_0) # Initial estimate of quenching probability given by dFq/dt # P_q = (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep Ng0, dum = np.histogram(M_t0_sample, bins=M_bins) Nsf0, dum = np.histogram(Msham_sf0[sf_within], bins=M_bins) P_q_arr = Ng0/Nsf0 * \ dFqdt(M_mid, tt + 0.5 * t_step, lit=self.fq_prop['name']) * t_step P_q_arr[np.where(Nsf0 == 0)] = 0. if not self.quiet: print 'M* : ', M_mid[-6:] print 'P_q : ', P_q_arr[-6:] Pq_M = interpolate.interp1d(M_mid, P_q_arr, kind='linear') P_q = Pq_M(Msham_sf0[sf_within]) q_ing0 = np.where(P_q > P_sf) Nqing0 = len(q_ing0[0]) # M_sham of the quiescent galaxies at the closest snapshot. closest_t1_snap = np.abs(t_snap - t_evol[i_t + 1]).argmin() - 1 Msham_q1 = q_Mshams[:, closest_t1_snap] Msham_sf1 = sf_Mshams[:, closest_t1_snap] M_t1_sample = np.concatenate([Msham_sf1[within], Msham_q1]) # dPQ correction to the quenching to account for change in Ng(M*,t) Ngp, dum = np.histogram(M_t1_sample, bins=M_bins) dPq = (Ngp - Ng0)/Nsf0.astype('float') * \ Fq_anal(M_mid, z_of_t(tt + t_step), lit=self.fq_prop['name']) dPq[np.where(dPq < 0.)] = 0. dPq[np.where(Nsf0 == 0)] = 0. if not self.quiet: print 'dPq : ', dPq[-6:] dPq_M = interpolate.interp1d(M_mid, dPq, kind='linear') P_q += dPq_M(Msham_sf0[sf_within]) # fudge factor for P_Q fudge_factor = self.fudge_prop['slope'] * ( Msham_sf0[sf_within] - self.fudge_prop['fidmass']) + self.fudge_prop['offset'] fudge_factor[np.where(fudge_factor < 1.)] = 1. P_q *= fudge_factor if self.printPQ: # store quenching probabilities Pq_out = {} Pq_out['mass'] = M_mid fPQ = self.fudge_prop['slope'] * (M_mid - self.fudge_prop['fidmass']) + \ self.fudge_prop['offset'] fPQ[np.where(fPQ < 1.)] = 1. Pq_out['Pq'] = fPQ * (P_q_arr + dPq) Pq_out['Pq_fid'] = P_q_arr + dPq if self.PQs is None: self.PQs = {} self.PQs[str(z_of_t(tt))] = Pq_out q_ing = np.where(P_sf < P_q) if not self.quiet: print 'Initial guess ', Nqing0, ' final: ', len( q_ing[0]), ' SF gal out of ', Nsf_0, ' start quenching' print time.time() - t_one_tstep print '----------------' # assign them quenching times then actually evolve their stellar masses tQ[sf_within[q_ing]] = np.random.uniform(low=tt, high=tt + t_step, size=len(q_ing[0])) quenching = np.where((Mq == -999.) & (tQ < 999.) & (tQ > 0.))[0] Nquenching = len(quenching) closest_tQ_index = np.abs( np.tile(t_snap, (Nquenching, 1)) - np.tile(tQ[quenching].reshape(Nquenching, 1), (1, len(t_snap)))).argmin(axis=1) - 1 Mq[quenching] = sf_Mshams[quenching, closest_tQ_index] z0 = z_of_t(t0) # initial redshift gv0 = np.where(tQ0 == 0.)[0] # galaxies that were initial quenching t_f = self.descendant_dict[str(nsnap_d)].t_cosmic z_f = self.descendant_dict[str(nsnap_d)].zsnap closest_tf_snap = np.abs(t_snap - t_f).argmin() - 1 Msham_f = sf_Mshams[:, closest_tf_snap].copy() q_ed = np.where(t_f > tQ) tmp_M = Msham_f.copy() tmp_M[q_ed] = Mq[q_ed].copy() # log(SFR)_SFMS evolution from t0 logsfr_sfms = sfr_evol.AverageLogSFR_sfms(tmp_M, z0, sfms_prop=self.sfms_prop) + \ sfr_evol.DeltaLogSFR_sfms(z0, z_f, sfms_prop=self.sfms_prop) # log(SFR)_duty cycle evolution from t0 to tQ logsfr_sfduty = sfr_evol.DeltaLogSFR_dutycycle( t0, t_f, t_q=tQ, dutycycle_prop=self.dutycycle_prop) logsfr_quench = sfr_evol.DeltaLogSFR_quenching(tQ, t_f, M_q=Mq, tau_prop=self.tau_prop) logSFR = logsfr_sfms + logsfr_quench + logsfr_sfduty # correct for the galaxies that were originally in the green valley. # ultimately doesn't make a difference in the outcome, but to be meticulous logSFR[gv0] = (self.ancestor.sfr[allwill[sf_ancestor]])[gv0] + \ sfr_evol.DeltaLogSFR_sfms(z0[gv0], z_f, sfms_prop=self.sfms_prop) + \ sfr_evol.DeltaLogSFR_quenching( np.repeat(self.ancestor.t_cosmic, len(gv0)), t_f, M_q=Mq[gv0], tau_prop=self.tau_prop) return logSFR, tQ
def DescendantSFMS_composition(nsnap_descendant, abc_step=29, bovyplot=False, **sfinh_kwargs): ''' SFMS for the SF Inherited Descendant galaxy population ''' sfinherit_file = InheritSF_file(nsnap_descendant, abc_step=abc_step, **sfinh_kwargs) bloodline = Lineage(nsnap_ancestor=sfinh_kwargs['nsnap_ancestor'], subhalo_prop=sfinh_kwargs['subhalo_prop']) bloodline.Read([nsnap_descendant], filename=sfinherit_file) descendant = getattr(bloodline, 'descendant_snapshot' + str(nsnap_descendant)) if not bovyplot: sfms_plot = descendant.plotSFMS(bovyplot=False, scatter=False) # SMF composition based on their initial mass at nsnap_ancestor started_here = np.where( descendant.nsnap_genesis == sfinh_kwargs['nsnap_ancestor']) start_mass = descendant.mass_genesis[started_here] mass_bins = np.arange(7., 12.5, 0.5) mass_bin_low = mass_bins[:-1] mass_bin_high = mass_bins[1:] for i_m in range(len(mass_bin_low)): mbin = np.where((start_mass > mass_bin_low[i_m]) & (start_mass <= mass_bin_high[i_m])) sfms_plot.plot( mass=descendant.mass[started_here[0][mbin]], sfr=descendant.sfr[started_here[0][mbin]], sfr_class=descendant.sfr_class[started_here[0][mbin]], gal_class='quiescent', bovyplot=False, sigSFR=False, color=i_m, label=r"$\mathtt{M_{*,i}=}$" + str(round(mass_bin_low[i_m], 2)) + "-" + str(round(mass_bin_high[i_m], 2))) qfrac = Fq() m_arr = np.arange(9.0, 12.5, 0.5) sfms_plot.sub.plot(m_arr, qfrac.SFRcut( m_arr, descendant.zsnap, sfms_prop=(sfinh_kwargs['sfr_prop'])['sfms']), c='k', ls='--', lw=4) bovyplot_str = '' else: sfms_plot = descendant.plotSFMS(bovyplot=True) bovyplot_str = '.bovy' sfms_plot.sub.legend(loc='lower right', scatterpoints=1) fig_file = ''.join([ 'figure/test/', 'SFMS_composition.', '.'.join( (sfinherit_file.rsplit('/')[-1]).rsplit('.')[:-1]), bovyplot_str, '.png' ]) sfms_plot.save_fig(fig_file) return None
def MstarSFR_simul_evol_OBSOLETE(M0, t0, tf, t_step=0.2, ancestor_Mq=None, quiet=True, **kwargs): ''' Evolve stellar mass, SFR, and quench galaxies simultaneously. Notes ----- * SF galaxies are quenched based on the following prescription: The number of galaxies that start quenching between t0 and t0+tstep is determined by, N_quenching = N_sf(t0) * (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep ''' dutycycle_prop = kwargs['dutycycle_prop'] tau_prop = kwargs['tau_prop'] fq_prop = kwargs['fq_prop'] sfms_prop = kwargs['sfms_prop'] massevol_prop = kwargs['massevol_prop'] Mstar = M0 SFR = np.repeat(-999., len(M0)) tQ = np.repeat(999., len(M0)) Mq = np.repeat(-999., len(M0)) t00 = t0.min() # earliest starting time (cosmic time of ancestor snapshot) t_evol = np.arange(t00, tf + t_step, t_step) t_evol[-1] = tf qf = Fq() Fq_anal = qf.model for tt in t_evol: if not quiet: print 't_cosmic = ', tt within = np.where(t0 <= tt) # tsnap_genesis <= t sf_within = np.where((t0 <= tt) & (tQ == 999.))[0] # Not quenching SF galaxies Nsf_0 = len(sf_within) P_sf = np.random.uniform(0., 1., Nsf_0) # Initial estimate of P_q = (1/( 1 - fQ(t0) )) * dFq/dt(t0 + 0.5 tstep) * tstep t_offset = np.zeros(len(sf_within)) #t_offset = -2.7 * (Mstar[sf_within] - 11.5) #t_offset[np.where(t_offset < 0.)] = 0. fudge = 1. # fudge factor f_Ng = ( 1. / (1. - Fq_anal(Mstar[sf_within], z_of_t(tt), lit=fq_prop['name']))) whereinf = np.where(f_Ng == np.inf) P_q = fudge * f_Ng * dFqdt(Mstar[sf_within], tt + t_offset + 0.5 * t_step, lit=fq_prop['name']) * t_step P_q[whereinf] = 1.0 q_ing = np.where(P_q > P_sf) if not quiet: print 'P_q', P_q.min(), P_q.max(), P_q.mean() print 'Initial guess ', len( q_ing[0] ), ' SF galaxies out of ', Nsf_0, ' galaxies start quenching' # assign them quenching times tQ[sf_within[q_ing]] = np.random.uniform(low=tt, high=tt + t_step, size=len(q_ing[0])) kwargs_sfr = { 't_init': t0[within], 't_q': tQ[within], 'M_q': Mq[within], 'dutycycle_prop': dutycycle_prop, 'tau_prop': tau_prop, 'sfms_prop': sfms_prop, 'indices': within } M_evol, sfr_evol, Mq_evol = M_integrate(Mstar[within], tt, tt + t_step, massevol_prop=massevol_prop, kwargs_sfr=kwargs_sfr) Mstar[within] = M_evol SFR[within] = sfr_evol Mq[within] = Mq_evol if SFR.min() == -999.: raise ValueError return Mstar, SFR, tQ
def QAplot(descendant, sfinh_kwargs, fig_name=None, **kwargs): ''' Given galpop object and the SF Inheritance parametes, plot its SMF, ''' # Mass bins mass_bins = np.arange(7., 12.5, 0.5) mass_bin_low = mass_bins[:-1] mass_bin_high = mass_bins[1:] plt.close() prettyplot() fig = plt.figure(1, figsize=[20,12]) for i_sub in range(1,6): sub_i = fig.add_subplot(2,3,i_sub) if i_sub == 1: # SMF mf = SMF() mass, phi = mf.Obj(descendant) sub_i.plot(mass, phi, lw=4, c='r', label=r'Simulated') censub = CentralSubhalos() censub.Read(descendant.nsnap, scatter=sfinh_kwargs['subhalo_prop']['scatter'], source=sfinh_kwargs['subhalo_prop']['source'], nsnap_ancestor=sfinh_kwargs['nsnap_ancestor']) mass, phi = mf._smf(censub.mass) sub_i.plot(mass, phi, c='k', lw=4, ls='--', label='Central Subhalos') sub_i.set_ylim([10**-5, 10**-1]) sub_i.set_xlim([7.5, 12.0]) plt.xticks([8., 9., 10., 11., 12.]) sub_i.set_yscale('log') # x,y labels sub_i.set_ylabel(r'Stellar Mass ($\mathtt{log\; M_*}$)', fontsize=20) sub_i.set_ylabel(r'Stellar Mass Function $\mathtt{\Phi}$', fontsize=20) sub_i.legend(loc='upper right', frameon=False) elif i_sub == 2: # SFMS # SMF composition based on their initial mass at nsnap_ancestor # random subsample n_tot = len(descendant.mass) r_subsample = np.random.choice(n_tot, size=100000) sub_i.scatter(descendant.mass[r_subsample], descendant.sfr[r_subsample], color='b', s=0.5) qfrac = Fq() m_arr = np.arange(9.0, 12.5, 0.5) sub_i.plot( m_arr, qfrac.SFRcut(m_arr, descendant.zsnap, sfms_prop=(sfinh_kwargs['sfr_prop'])['sfms']), c='k', ls='--', lw=4) sub_i.text(10.5, -4., r'$\mathtt{z='+str(descendant.zsnap)+'}$', fontsize=25) sub_i.set_xlim([9.0, 12.0]) sub_i.set_ylim([-5.0, 2.0]) sub_i.set_ylabel(r'Stellar Mass ($\mathtt{log\; M_*}$)', fontsize=20) sub_i.set_ylabel(r'$\mathtt{log\;SFR}$', fontsize=20) elif i_sub == 3: #SMHM #corner.hist2d(descendant.halo_mass, descendant.mass, ax=sub_i, c='b', fill_contours=True, smooth=1.0) n_tot = len(descendant.mass) r_subsample = np.random.choice(n_tot, size=100000) sub_i.scatter(descendant.halo_mass[r_subsample], descendant.mass[r_subsample], color='b', s=0.5) stellarmass = descendant.mass halomass = descendant.halo_mass mbin = np.arange(halomass.min(), halomass.max(), 0.25) mlow = mbin[:-1] mhigh = mbin[1:] muMstar = np.zeros(len(mlow)) sigMstar = np.zeros(len(mlow)) for im in range(len(mlow)): mbin = np.where((halomass > mlow[im]) & (halomass <= mhigh[im])) muMstar[im] = np.mean(stellarmass[mbin]) sigMstar[im] = np.std(stellarmass[mbin]) sub_i.errorbar(0.5*(mlow+mhigh), muMstar, yerr=sigMstar, color='k', lw=3, fmt='o', capthick=2) sub_i.set_ylim([9.0, 12.0]) sub_i.set_xlim([10.0, 15.0]) sub_i.set_ylabel(r'Stellar Mass ($\mathtt{log\; M_*}$)', fontsize=20) sub_i.set_xlabel(r'Halo Mass ($\mathtt{log\;M_{Halo}}$)', fontsize=20) elif i_sub == 4: # Fq sfq = qfrac.Classify(descendant.mass, descendant.sfr, descendant.zsnap, sfms_prop=descendant.sfr_prop['sfms']) gc = GroupCat(Mrcut=18, position='central') gc.Read() gc_sfq = qfrac.Classify(gc.mass, gc.sfr, np.mean(gc.z), sfms_prop=descendant.sfr_prop['sfms']) #sub_i.plot(mass, fq, color=pretty_colors[descendant.nsnap], lw=3, ls='--', # label=r'$\mathtt{z =} '+str(descendant.zsnap)+'$') M_bin = np.array([9.7, 10.1, 10.5, 10.9, 11.3]) M_low = M_bin[:-1] M_high = M_bin[1:] M_mid = 0.5 * (M_low + M_high) fq = np.zeros(len(M_low)) gc_fq = np.zeros(len(M_low)) for i_m in xrange(len(M_low)): mlim = np.where((descendant.mass > M_low[i_m]) & (descendant.mass <= M_high[i_m])) gc_mlim = np.where((gc.mass > M_low[i_m]) & (gc.mass <= M_high[i_m])) ngal = np.float(len(mlim[0])) gc_ngal = np.float(len(gc_mlim[0])) if ngal != 0: # no galaxy in mass bin ngal_q = np.float(len(np.where(sfq[mlim] == 'quiescent')[0])) fq[i_m] = ngal_q/ngal if gc_ngal != 0: gc_ngal_q = np.float(len(np.where(gc_sfq[gc_mlim] == 'quiescent')[0])) gc_fq[i_m] = gc_ngal_q/gc_ngal sub_i.plot(M_mid, fq, color='r', lw=3, label=r'Simulated') # fQ of the Group Catalog sub_i.scatter(M_mid, gc_fq, color='k', s=100, lw=0, label='Group Catalog') # fQ of the model (input) fQ fq_model = qfrac.model(M_bin, descendant.zsnap, lit=sfinh_kwargs['sfr_prop']['fq']['name']) sub_i.plot(M_bin, fq_model, color='k', lw=4, ls='--', label=sfinh_kwargs['sfr_prop']['fq']['name'].replace('_', ' ').title() ) sub_i.set_xlim([9.0, 12.0]) sub_i.set_ylim([0.0, 1.0]) sub_i.set_ylabel(r'Stellar Mass ($\mathtt{log\; M_*}$)', fontsize=20) sub_i.set_ylabel(r'Quiescent Fraction $\mathtt{f_Q}$', fontsize=20) sub_i.legend(loc='upper left', frameon=False, scatterpoints=1, markerscale=0.75) elif i_sub == 5: # Tau_Q(M*) mass_bin = np.arange(9.0, 12.0, 0.1) tau_m = getTauQ(mass_bin, tau_prop=sfinh_kwargs['evol_prop']['tau']) sub_i.plot(10**mass_bin, tau_m, color='r', lw=4, label='Simulated') if 'taus' in kwargs: tau_slopes, tau_offsets = kwargs['taus'] i_tau_ms = np.zeros((len(mass_bin), len(tau_slopes))) for i_tau in range(len(tau_slopes)): i_tau_prop = sfinh_kwargs['evol_prop']['tau'].copy() i_tau_prop['slope'] = tau_slopes[i_tau] i_tau_prop['yint'] = tau_offsets[i_tau] i_tau_m = getTauQ(mass_bin, tau_prop=i_tau_prop) #sub_i.plot(10**mass_bin, i_tau_m, color='r', alpha=0.1, lw=2) i_tau_ms[:,i_tau] = i_tau_m sig_tau = np.zeros(len(mass_bin)) for im in range(len(mass_bin)): sig_tau[im] = np.std(i_tau_ms[im,:]) sub_i.errorbar(10**mass_bin, tau_m, yerr=sig_tau, color='r', lw=4) # satellite quenching fraction for comparison tau_sat = getTauQ(mass_bin, tau_prop={'name': 'satellite'}) sub_i.plot(10**mass_bin, tau_sat, color='black', lw=4, ls='--', label=r'Satellite (Wetzel+ 2013)') sub_i.set_xlim([10**9.5, 10**11.75]) sub_i.set_ylim([0.0, 2.0]) sub_i.set_xscale('log') sub_i.set_xlabel(r'Stellar Mass $[\mathtt{M_\odot}]$',fontsize=20) sub_i.legend(loc='upper right') sub_i.set_ylabel(r'Quenching Timescales $(\tau_\mathtt{Q})$ [Gyr]',fontsize=20) plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) if fig_name is None: plt.show() plt.close() else: fig.savefig(fig_name, bbox_inches='tight') plt.close() return None