def caustic_stack(self,Rdata,Vdata,HaloID,HaloData,stack_num, ens_shiftgap=True,edge_int_remove=True,gal_reduce=True,stack_raw=False,est_v_center=False, feed_mags=True,G_Mags=None,R_Mags=None,I_Mags=None,clus_z=0): """ -- Takes an array of individual phase spaces and stacks them, then runs a caustic technique over the ensemble and/or individual phase spaces. -- Returns a dictionary -- Relies on a few parameters to be defined outside of the function: self.gal_num - Equivalent to Ngal: number of galaxies to take per cluster to then be stacked self.line_num - Equivalent to Nclus: number of clusters to stack into one ensemble cluster self.scale_data - Scale r data by R200 while stacking, then un-scale by BinR200 self.run_los - run caustic technique over individual cluster (aka line-of-sight) self.avg_meth - method by which averaging of Bin Properties should be, 'mean' or 'median' or 'biweight' etc.. self.mirror - mirror phase space before solving for caustic? Including others... see RunningTheCode.pdf for a list * These parameters should be fed to initialization of Stack() class as a dictionary, for ex: variables = {'run_los':False, ...... } S = Stack(variables) "rdata" - should be a 2 dimensional array with individual phase spaces as rows "vdata" - should be a 2 dimensional array with individual phase spaces as rows ex. rdata[0] => 0th phase space data 'HaloID' : 1 dimensional array containing Halo Identification Numbers, len(HaloID) == len(rdata) 'HaloData' : 2 dimensional array containing M200, R200, HVD, Z of Halos, with unique halos as columns 'stack_num' : number of individual clusters to stack into the one ensemble 'ens_shiftgap' - do a shiftgapper over final ensemble phase space? 'gal_reduce' - before caustic run, reduce ensemble phase space to Ngal gals within R200? 'stack_raw' - don't worry about limiting or building the phase space, just stack the Rdata and Vdata together as is 'est_v_center' - take median of Vdata for new velocity center 'feed_gal_mags' - feed magnitudes for individual galaxies, must feed all three mags if True -- 'ens' stands for ensemble cluster -- 'ind' stands for individual cluster -- Uppercase arrays contain data for multiple clusters, lowercase arrays contain data for 1 cluster """ # Define a container for holding stacked data, D D = Data() # Assign some parameters to Class scope self.__dict__.update(ez.create(['stack_raw','feed_mags','gal_reduce','ens_shiftgap','edge_int_remove'],locals())) # New Velocity Center if est_v_center == True: v_offset = astats.biweight_location(vdata[np.where(rdata < 1.0)]) vdata -= v_offset # Unpack HaloData if HaloData == None: self.fed_halo_data = False # Estimate R200 R200 = [] HVD = [] Z = [] for i in range(stack_num): R200.append(np.exp(-1.86)*len(np.where((R_Mags[i] < -19.55) & (Rdata[i] < 1.0) & (np.abs(Vdata[i]) < 3500))[0])**0.51) HVD.append(astats.biweight_midvariance(Vdata[i][np.where((Rdata[i] < 1.0)&(np.abs(Vdata[i])<4000))])) R200 = np.array(R200) HVD = np.array(HVD) Z = np.array([0.05]*len(R200)) if self.avg_meth == 'mean': BinR200 = np.mean(R200); BinHVD = np.mean(HVD); BinZ = np.mean(Z) elif self.avg_meth == 'median': BinR200 = np.median(R200); BinHVD = np.median(HVD); BinZ = np.median(Z) D.add({'BinR200':BinR200,'BinHVD':BinHVD,'BinZ':BinZ,'R200':R200,'HVD':HVD,'Z':Z}) else: self.fed_halo_data = True M200,R200,HVD,Z = HaloData if self.avg_meth == 'mean': BinM200 = np.mean(M200) BinR200 = np.mean(R200) BinHVD = np.mean(HVD) BinZ = np.mean(Z) elif self.avg_meth == 'median': BinM200 = np.median(M200) BinR200 = np.median(R200) BinHVD = np.median(HVD) BinZ = np.median(Z) # Append to Data D.add({'BinM200':BinM200,'BinR200':BinR200,'BinHVD':BinHVD,'BinZ':BinZ}) # Create Dummy Variables for Magnitudes if necessary if self.feed_mags == False: G_Mags,R_Mags,I_Mags = [],[],[] for i in range(stack_num): G_Mags.append([None]*len(Rdata[i])) R_Mags.append([None]*len(Rdata[i])) I_Mags.append([None]*len(Rdata[i])) G_Mags,R_Mags,I_Mags = np.array(G_Mags),np.array(R_Mags),np.array(I_Mags) # Create galaxy identification arrays ENS_gal_id,ENS_clus_id,IND_gal_id = [],[],[] gal_count = 0 for i in range(stack_num): ENS_gal_id.append(np.arange(gal_count,gal_count+len(Rdata[i]))) ENS_clus_id.append(np.array([HaloID[i]]*len(Rdata[i]),int)) IND_gal_id.append(np.arange(len(Rdata[i]))) ENS_gal_id,ENS_clus_id,ENS_gal_id = np.array(ENS_gal_id),np.array(ENS_clus_id),np.array(IND_gal_id) # Iterate through phase spaces for self.l in range(stack_num): # Limit Phase Space if self.stack_raw == False: r,v,ens_gal_id,ens_clus_id,ind_gal_id,gmags,rmags,imags,samp_size = self.U.limit_gals(Rdata[self.l],Vdata[self.l],ENS_gal_id[self.l],ENS_clus_id[self.l],IND_gal_id[self.l],G_Mags[self.l],R_Mags[self.l],I_Mags[self.l],R200[self.l]) # Build Ensemble and LOS Phase Spaces if self.stack_raw == False: ens_r,ens_v,ens_gal_id,ens_clus_id,ens_gmags,ens_rmags,ens_imags,ind_r,ind_v,ind_gal_id,ind_gmags,ind_rmags,ind_imags = self.U.build(r,v,ens_gal_id,ens_clus_id,ind_gal_id,gmags,rmags,imags,R200[self.l]) # If Scale data before stack is desired if self.scale_data == True: ens_r /= R200[self.l] # Stack Ensemble Data by extending to Data() container names = ['ens_r','ens_v','ens_gmags','ens_rmags','ens_imags','ens_gal_id','ens_clus_id'] D.extend(ez.create(names,locals())) if self.run_los == True: # Create Data Block ind_data = np.vstack([ind_r,ind_v,ind_gal_id,ind_gmags,ind_rmags,ind_imags]) # Sort by Rmag bright = np.argsort(ind_rmags) ind_data = ind_data.T[bright].T ind_r,ind_v,ind_gal_id,ind_gmags,ind_rmags,ind_imags = ind_data # Reduce phase space if self.stack_raw == False and self.gal_reduce == True: within = np.where(ind_r <= R200[self.l])[0] end = within[:self.gal_num + 1][-1] ind_data = ind_data.T[:end].T ind_r,ind_v,ind_gal_id,ind_gmags,ind_rmags,ind_imags = ind_data # Calculate individual HVD # Pick out gals within r200 within = np.where(ind_r <= R200[self.l])[0] gal_count = len(within) if gal_count <= 3: '''biweightScale can't take less than 4 elements''' # Calculate hvd with numpy std of galaxies within r200 (b/c this is quoted richness) ind_hvd = np.std(np.copy(ind_v)[within]) else: # Calculate hvd with astStats biweightScale (see Beers 1990) try: ind_hvd = astats.biweight_midvariance(np.copy(ind_v)[within]) # Sometimes divide by zero error in biweight function for low gal_num except ZeroDivisionError: print 'ZeroDivisionError in biweightfunction' print 'ind_v[within]=',ind_v[within] ind_hvd = np.std(np.copy(ind_v)[within]) # If run_los == True, run Caustic Technique on individual cluster self.U.print_separation('# Running Caustic for LOS '+str(self.l),type=2) self.run_caustic(ind_r,ind_v,R200[self.l],ind_hvd,clus_z=Z[self.l],mirror=self.mirror) ind_caumass = np.array([self.C.M200_fbeta]) ind_caumass_est = np.array([self.C.Mass2.M200_est]) ind_edgemass = np.array([self.C.M200_edge]) ind_edgemass_est = np.array([self.C.MassE.M200_est]) ind_causurf = np.array(self.C.caustic_profile) ind_nfwsurf = np.array(self.C.caustic_fit) ind_edgesurf = np.array(self.C.caustic_edge) # Append Individual Cluster Data names = ['ind_r','ind_v','ind_gal_id','ind_gmags','ind_rmags','ind_imags', 'ind_hvd','ind_caumass','ind_caumass_est','ind_edgemass','ind_edgemass_est', 'ind_causurf','ind_nfwsurf'] D.append(ez.create(names,locals())) # Turn Ensemble into Arrays names = ['ens_r','ens_v','ens_gal_id','ens_clus_id','ens_gmags','ens_rmags','ens_imags','ens_caumass','ens_caumass_est','ens_edgemass','ens_edgemass_est','ens_causurf','ens_nfwsurf','ens_edgesurf'] D.to_array(names,ravel=True) # Re-scale data if scale_data == True: if self.scale_data == True: D.ens_r *= BinR200 # Create Ensemble Data Block D.ens_data = np.vstack([D.ens_r,D.ens_v,D.ens_gal_id,D.ens_clus_id,D.ens_gmags,D.ens_rmags,D.ens_imags]) # Shiftgapper for Interloper Treatment if self.stack_raw == False and self.ens_shiftgap == True: self.D = D try: D.ens_data = self.C.shiftgapper(D.ens_data.T).T D.ens_r,D.ens_v,D.ens_gal_id,D.ens_clus_id,D.ens_gmags,D.ens_rmags,D.ens_imags = D.ens_data except UnboundLocalError: # A couple or no galaxies within RVIR print '-'*40 print 'UnboundLocalError raised on Ensemble Shiftgapper' print '-'*40 D.ens_r,D.ens_v,D.ens_gal_id,D.ens_clus_id,D.ens_gmags,D.ens_rmags,D.ens_imags = D.ens_data # Sort by R_Mag bright = np.argsort(D.ens_rmags) D.ens_data = D.ens_data.T[bright].T D.ens_r,D.ens_v,D.ens_gal_id,D.ens_clus_id,D.ens_gmags,D.ens_rmags,D.ens_imags = D.ens_data # Reduce System Down to gal_num richness within BinR200 if self.stack_raw and self.gal_reduce == True: within = np.where(D.ens_r <= BinR200)[0] print 'len(within)',len(within) print 'gal_num,line_num',self.gal_num,self.line_num end = within[:self.gal_num*self.line_num + 1][-1] D.ens_data = D.ens_data.T[:end].T D.ens_r,D.ens_v,D.ens_gal_id,D.ens_clus_id,D.ens_gmags,D.ens_rmags,D.ens_imags = D.ens_data # Calculate Ensemble Velocity Dispersion for galaxies within R200 ens_hvd = astats.biweight_midvariance(np.copy(D.ens_v)[np.where(D.ens_r<=BinR200)]) # Run Caustic Technique! try: self.U.print_separation('# Running Caustic on Ensemble '+str(self.j),type=2) except: pass try: self.run_caustic(D.ens_r,D.ens_v,BinR200,ens_hvd,clus_z=BinZ,mirror=self.mirror,shiftgap=self.ens_shiftgap,edge_int_remove=self.edge_int_remove) ens_caumass = np.array([self.C.M200_fbeta]) ens_caumass_est = np.array([self.C.Mass2.M200_est]) ens_edgemass = np.array([self.C.M200_edge]) ens_edgemass_est = np.array([self.C.MassE.M200_est]) ens_causurf = np.array(self.C.caustic_profile) ens_nfwsurf = np.array(self.C.caustic_fit) ens_edgesurf = np.array(self.C.caustic_edge) ens_caumass500_est = np.array(self.C.Mass2.M500_est) ens_edgemass500_est = np.array(self.C.MassE.M500_est) ens_r200_est = np.array(self.C.r200_est_fbeta) ens_r500_est = np.array(self.C.r500_est_fbeta) ens_r200_est_edge = np.array(self.C.r200_est_edge) except: print '' print '-'*45 print 'CAUSTIC TECHNIQUE FAILED ON THIS CLUSTER' print '-'*45 print '' ens_caumass = np.array([0]) ens_caumass_est = np.array([0]) ens_edgemass = np.array([0]) ens_edgemass_est = np.array([0]) ens_causurf = np.array([0]*len(self.C.x_range)) ens_nfwsurf = np.array([0]*len(self.C.x_range)) ens_edgesurf = np.array([0]*len(self.C.x_range)) ens_caumass500_est = np.array([0]) ens_edgemass500_est = np.array([0]) ens_r200_est = np.array([0]) ens_r500_est = np.array([0]) ens_r200_est_edge = np.array([0]) # Other Arrays x_range = self.C.x_range # Append Data names = ['ens_caumass','ens_hvd','ens_caumass_est','ens_edgemass','ens_edgemass_est','ens_causurf','ens_nfwsurf','ens_edgesurf','x_range','ens_caumass500_est','ens_edgemass500_est','ens_r200_est','ens_r500_est','ens_r200_est_edge'] D.add(ez.create(names,locals())) # Turn Individual Data into Arrays if self.run_los == True: names = ['ind_caumass','ind_caumass_est','ind_edgemass','ind_edgemass_est','ind_hvd'] D.to_array(names,ravel=True) names = ['ind_r','ind_v','ind_gal_id','ind_gmags','ind_rmags','ind_imags','ind_causurf','ind_nfwsurf','ind_edgesurf'] D.to_array(names) # Output Data return D.__dict__
def stat_calc(self, MASS_EST, MASS_TRUE, HVD_EST, HVD_TRUE, data_set='full', ens=True): ''' Does bias and scatter calculations ''' # Cut data set if necessary if data_set == 'cut_low_mass': '''Cutting all 'true' mass estimates below 1e14 off''' cut = np.where(MASS_TRUE > 1e14)[0] MASS_EST = MASS_EST[cut] MASS_TRUE = MASS_TRUE[cut] HVD_EST = HVD_EST[cut] HVD_TRUE = HVD_TRUE[cut] # Define a Masked array for sometimes zero terms epsilon = 10.0 use_est = False # Use MassCalc estimated r200 mass values if true maMASS_EST = ma.masked_array( MASS_EST, mask=MASS_EST < epsilon) # Mask essentially zero values maHVD_EST = ma.masked_array(HVD_EST, mask=HVD_EST < epsilon) # Mass / HVD Fractions if ens == True: # Ensemble Arrays MFRAC = np.log(maMASS_EST / MASS_TRUE) VFRAC = np.log(maHVD_EST / HVD_TRUE) else: # LOS Mass Fraction Arrays: 0th axis is halo number, 1st axis is line of sight number MFRAC, VFRAC = [], [] for a in range(len(MASS_EST)): MFRAC.append(ma.log(maMASS_EST[a] / MASS_TRUE[a])) VFRAC.append(ma.log(maHVD_EST[a] / HVD_TRUE[a])) MFRAC, VFRAC = np.array(MFRAC), np.array(VFRAC) if ens == True: mbias, mscat = astrostats.biweight_location( MFRAC, 6.0), astrostats.biweight_midvariance(MFRAC, 9.0) vbias, vscat = astrostats.biweight_location( VFRAC, 6.0), astrostats.biweight_midvariance(VFRAC, 9.0) return MFRAC, mbias, mscat, VFRAC, vbias, vscat else: if self.ss: # Create vertically averaged (by halo averaged) arrays, with line_num elements # biweightLocation takes only arrays with 4 or more elements HORZ_MFRAC, HORZ_VFRAC = [], [] VERT_MFRAC, VERT_VFRAC = [], [] for a in range(self.line_num): if len(ma.compressed(MFRAC[:, a])) > 4: VERT_MFRAC.append( astrostats.biweight_location( ma.compressed(MFRAC[:, a]), 6.0)) VERT_VFRAC.append( astrostats.biweight_location( ma.compressed(VFRAC[:, a]), 6.0)) else: VERT_MFRAC.append(np.median(ma.compressed(MFRAC[:, a]))) VERT_VFRAC.append(np.median(ma.compressed(VFRAC[:, a]))) VERT_MFRAC, VERT_VFRAC = np.array(VERT_MFRAC), np.array( VERT_VFRAC) # Create horizontally averaged (by line of sight) arrays, with halo_num elements for a in self.halo_range: if len(ma.compressed(MFRAC[a])) > 4: HORZ_MFRAC.append( astrostats.biweight_location( ma.compressed(MFRAC[a]), 6.0)) HORZ_VFRAC.append( astrostats.biweight_location( ma.compressed(VFRAC[a]), 6.0)) else: HORZ_MFRAC.append(np.median(ma.compressed(MFRAC[a]))) HORZ_VFRAC.append(np.median(ma.compressed(VFRAC[a]))) HORZ_MFRAC, HORZ_VFRAC = np.array(HORZ_MFRAC), np.array( HORZ_VFRAC) # Bias and Scatter Calculations mbias, mscat = astrostats.biweight_location( VERT_MFRAC, 6.0), astrostats.biweight_midvariance(VERT_MFRAC, 9.0) vbias, vscat = astrostats.biweight_location( VERT_VFRAC, 6.0), astrostats.biweight_midvariance(VERT_VFRAC, 9.0) else: # Bin stack LOS systems need only one average mbias, mscat = astrostats.biweight_location( MFRAC, 6.0), astrostats.biweight_midvariance(MFRAC, 9.0) vbias, vscat = astrostats.biweight_location( VFRAC, 6.0), astrostats.biweight_midvariance(VFRAC, 9.0) return MFRAC, mbias, mscat, VFRAC, vbias, vscat
def stat_calc(self,MASS_EST,MASS_TRUE,HVD_EST,HVD_TRUE,data_set='full',ens=True): ''' Does bias and scatter calculations ''' # Cut data set if necessary if data_set == 'cut_low_mass': '''Cutting all 'true' mass estimates below 1e14 off''' cut = np.where(MASS_TRUE>1e14)[0] MASS_EST = MASS_EST[cut] MASS_TRUE = MASS_TRUE[cut] HVD_EST = HVD_EST[cut] HVD_TRUE = HVD_TRUE[cut] # Define a Masked array for sometimes zero terms epsilon = 10.0 use_est = False # Use MassCalc estimated r200 mass values if true maMASS_EST = ma.masked_array(MASS_EST,mask=MASS_EST<epsilon) # Mask essentially zero values maHVD_EST = ma.masked_array(HVD_EST,mask=HVD_EST<epsilon) # Mass / HVD Fractions if ens == True: # Ensemble Arrays MFRAC = np.log(maMASS_EST/MASS_TRUE) VFRAC = np.log(maHVD_EST/HVD_TRUE) else: # LOS Mass Fraction Arrays: 0th axis is halo number, 1st axis is line of sight number MFRAC,VFRAC = [],[] for a in range(len(MASS_EST)): MFRAC.append( ma.log( maMASS_EST[a]/MASS_TRUE[a] ) ) VFRAC.append( ma.log( maHVD_EST[a]/HVD_TRUE[a] ) ) MFRAC,VFRAC = np.array(MFRAC),np.array(VFRAC) if ens == True: mbias,mscat = astrostats.biweight_location(MFRAC,6.0),astrostats.biweight_midvariance(MFRAC,9.0) vbias,vscat = astrostats.biweight_location(VFRAC,6.0),astrostats.biweight_midvariance(VFRAC,9.0) return MFRAC,mbias,mscat,VFRAC,vbias,vscat else: if self.ss: # Create vertically averaged (by halo averaged) arrays, with line_num elements # biweightLocation takes only arrays with 4 or more elements HORZ_MFRAC,HORZ_VFRAC = [],[] VERT_MFRAC,VERT_VFRAC = [],[] for a in range(self.line_num): if len(ma.compressed(MFRAC[:,a])) > 4: VERT_MFRAC.append( astrostats.biweight_location( ma.compressed( MFRAC[:,a] ), 6.0 ) ) VERT_VFRAC.append( astrostats.biweight_location( ma.compressed( VFRAC[:,a] ), 6.0 ) ) else: VERT_MFRAC.append( np.median( ma.compressed( MFRAC[:,a] ) ) ) VERT_VFRAC.append( np.median( ma.compressed( VFRAC[:,a] ) ) ) VERT_MFRAC,VERT_VFRAC = np.array(VERT_MFRAC),np.array(VERT_VFRAC) # Create horizontally averaged (by line of sight) arrays, with halo_num elements for a in self.halo_range: if len(ma.compressed(MFRAC[a])) > 4: HORZ_MFRAC.append( astrostats.biweight_location( ma.compressed( MFRAC[a] ), 6.0 ) ) HORZ_VFRAC.append( astrostats.biweight_location( ma.compressed( VFRAC[a] ), 6.0 ) ) else: HORZ_MFRAC.append( np.median( ma.compressed( MFRAC[a] ) ) ) HORZ_VFRAC.append( np.median( ma.compressed( VFRAC[a] ) ) ) HORZ_MFRAC,HORZ_VFRAC = np.array(HORZ_MFRAC),np.array(HORZ_VFRAC) # Bias and Scatter Calculations mbias,mscat = astrostats.biweight_location(VERT_MFRAC,6.0),astrostats.biweight_midvariance(VERT_MFRAC,9.0) vbias,vscat = astrostats.biweight_location(VERT_VFRAC,6.0),astrostats.biweight_midvariance(VERT_VFRAC,9.0) else: # Bin stack LOS systems need only one average mbias,mscat = astrostats.biweight_location(MFRAC,6.0),astrostats.biweight_midvariance(MFRAC,9.0) vbias,vscat = astrostats.biweight_location(VFRAC,6.0),astrostats.biweight_midvariance(VFRAC,9.0) return MFRAC,mbias,mscat,VFRAC,vbias,vscat
def richness_est(self, ra, dec, z, pz, gmags, rmags, imags, abs_rmags, haloid, clus_ra, clus_dec, clus_z, clus_rvir=None, gr_slope=None, gr_width=None, gr_inter=None, shiftgap=True, use_specs=False, use_bcg=False, fit_rs=False, spec_list=None, fixed_aperture=False, fixed_vdisp=False, plot_gr=False, plot_sky=False, plot_phase=False, find_pairs=True): ''' Richness estimator, magnitudes should be apparent mags except for abs_rmag z : spectroscopic redshift pz : photometric redshift gr_slope : if fed color-mag (g-r vs. r) slope of fit to red sequence gr_width : if fed color-mag (g-r vs. r) width of fit to red sequence gr_inter : if red color-mag (g-r vs. r) intercept of fit to red sequence spec_list : indexing array specifying gals w/ spectroscopic redshifts, preferably fed as boolean numpy array fixed_aperture : clus_rvir = 1 Mpc fixed_vdisp : clus_vdisp = 1000 km/s (members < clus_vdisp*2) use_specs : includes all spectro members in richness regardless of their color, subject to counting twice use_bcg : use bcg RS_color as cluster RS_color fit_rs : fit a line to the member galaxy RS relationship, as of now this does not work and we take a flat RS relationship plot_gr : plot r vs g-r color diagram with RS fits plot_sky : plot RA and DEC of gals with signal and background annuli plot_phase : plot rdata and vdata phase space find_pairs : run c4 cluster pair identifier on phase spaces - If at least one quarter of the outer annuli doesn't have any galaxies (perhaps because it has run over the observation edge), it will return -99 as a richness ''' # Put Into Class Namespace keys = [ 'ra', 'dec', 'z', 'pz', 'gmags', 'rmags', 'imags', 'clus_ra', 'clus_dec', 'clus_z', 'clus_rvir', 'vel_disp', 'color_data', 'color_cut', 'RS_color', 'RS_sigma', 'clus_color_cut', 'signal', 'background', 'richness', 'mems', 'phot', 'spec', 'spec_mems', 'deg_per_rvir', 'SA_outer', 'SA_inner', 'outer_red_dense', 'inner_background', 'Nphot_inner', 'Nphot_outer', 'red_inner', 'red_outer', 'all', 'outer_edge', 'inner_edge', 'shift_cut', 'set', 'pair', 'Nspec', 'gr_slope', 'gr_inter', 'gr_width', 'obs_tot', 'obs_back_scaled' ] self.__dict__.update(ez.create(keys, locals())) # Take rough virial radius measurement, this method is BAD... if clus_rvir == None: clus_rvir = np.exp(-1.86) * len( np.where((rmags < -19.55) & (rdata < 1.0) & (np.abs(vdata) < 3500))[0])**0.51 self.clus_rvir = clus_rvir # Set clus_rvir = 1.0 Mpc if fixed aperture == True if fixed_aperture == True: clus_rvir = 1.0 # Magnitue Cut at 19.1 Apparent R Mag, then at -19 Absolute R Mag and sort by them bright = np.where(rmags < 19.1)[0] data = np.vstack([ra, dec, z, pz, gmags, rmags, imags, abs_rmags]) data = data.T[bright].T ra, dec, z, pz, gmags, rmags, imags, abs_rmags = data bright = np.where(abs_rmags < -19.5)[0] data = np.vstack([ra, dec, z, pz, gmags, rmags, imags, abs_rmags]) data = data.T[bright].T ra, dec, z, pz, gmags, rmags, imags, abs_rmags = data sorts = np.argsort(abs_rmags) data = np.vstack([ra, dec, z, pz, gmags, rmags, imags, abs_rmags]) data = data.T[sorts].T ra, dec, z, pz, gmags, rmags, imags, abs_rmags = data self.__dict__.update(ez.create(keys, locals())) # Separate Into Spectro Z and Photo Z DataSets # Define the Spectro Z catalogue if spec_list == None: spec_cut = np.abs(z) > 1e-4 else: if type(spec_list) == list: spec_list = np.array(spec_list) if spec_list.dtype != 'bool': spec_cut = np.array([False] * len(ra)) spec_cut[spec_list] = True all = { 'ra': ra, 'dec': dec, 'z': z, 'pz': pz, 'gmags': gmags, 'rmags': rmags, 'imags': imags, 'abs_rmags': abs_rmags } spec = { 'ra': ra[spec_cut], 'dec': dec[spec_cut], 'z': z[spec_cut], 'pz': pz[spec_cut], 'gmags': gmags[spec_cut], 'rmags': rmags[spec_cut], 'imags': imags[spec_cut], 'abs_rmags': abs_rmags[spec_cut] } phot = { 'ra': ra[~spec_cut], 'dec': dec[~spec_cut], 'z': z[~spec_cut], 'pz': pz[~spec_cut], 'gmags': gmags[~spec_cut], 'rmags': rmags[~spec_cut], 'imags': imags[~spec_cut], 'abs_rmags': abs_rmags[~spec_cut] } # Project Spectra into radius and velocity ang_d, lum_d = C.zdistance(clus_z, self.H0) angles = C.findangle(spec['ra'], spec['dec'], clus_ra, clus_dec) rdata = angles * ang_d vdata = self.c * (spec['z'] - clus_z) / (1 + clus_z) spec.update({'rdata': rdata, 'vdata': vdata}) self.__dict__.update(ez.create(keys, locals())) # Take Hard Phasespace Limits limit = np.where((rdata < 5) & (np.abs(vdata) < 5000))[0] clus_data = np.vstack([ rdata, vdata, spec['ra'], spec['dec'], spec['z'], spec['pz'], spec['gmags'], spec['rmags'], spec['imags'], spec['abs_rmags'] ]) clus_data = clus_data.T[limit].T rdata, vdata, spec['ra'], spec['dec'], spec['z'], spec['pz'], spec[ 'gmags'], spec['rmags'], spec['imags'], spec[ 'abs_rmags'] = clus_data spec.update({'rdata': rdata, 'vdata': vdata}) self.__dict__.update(ez.create(keys, locals())) # Shiftgapper for Interlopers if shiftgap == True: len_before = np.where((rdata < clus_rvir * 1.5) & (np.abs(vdata) < 4000))[0].size clus_data = np.vstack([ rdata, vdata, spec['ra'], spec['dec'], spec['z'], spec['pz'], spec['gmags'], spec['rmags'], spec['imags'], spec['abs_rmags'] ]) clus_data = C.shiftgapper(clus_data.T).T sorts = np.argsort(clus_data[-1]) clus_data = clus_data.T[sorts].T rdata, vdata, spec['ra'], spec['dec'], spec['z'], spec['pz'], spec[ 'gmags'], spec['rmags'], spec['imags'], spec[ 'abs_rmags'] = clus_data shift_cut = len_before - np.where((rdata < clus_rvir) & (np.abs(vdata) < 4000))[0].size # Measure Velocity Dispersion of all galaxies within 1 * r_vir and np.abs(vdata) < 4000 km/s spec.update({'rdata': rdata, 'vdata': vdata}) self.__dict__.update(ez.create(keys, locals())) vel_disp = astats.biweight_midvariance( vdata[np.where((rdata < clus_rvir * 1) & (np.abs(vdata) < 4000))]) if fixed_vdisp == True: vel_disp = 1000 # Run Cluster Pair Finder if find_pairs == True: pair, d1_chi, d2_chi, d3_chi, s_chi, double1, double2, double3, single, v_range, bins = pair_find( rdata, vdata) # Calculate Nspec, Nspec = # of galaxies within RVIR try: Nspec = np.where(rdata < clus_rvir)[0].size except: Nspec = 0 self.__dict__.update(ez.create(keys, locals())) # Get Members from Specta, get their red sequence color mems = np.where((spec['rdata'] < clus_rvir) & (np.abs(spec['vdata']) < 2 * vel_disp))[0] color_data = spec['gmags'] - spec['rmags'] color_cut = np.where((color_data[mems] < 1.2) & (color_data[mems] > 0.65))[0] RS_color = astats.biweight_location(color_data[mems][color_cut]) RS_shift = color_data[mems][color_cut] - RS_color RS_sigma = astats.biweight_midvariance( RS_shift[np.where(np.abs(RS_shift) < .15)]) if fit_rs == True: clf = linear_model.LinearRegression() set = np.where( np.abs(color_data[mems] - RS_color) < 3 * RS_sigma)[0] clf.fit(spec['rmags'][mems][set].reshape(set.size, 1), color_data[mems][set]) if use_bcg == True: bright = np.argsort(all['abs_rmags'][mems])[0] RS_color = color_data[mems][bright] RS_shift = color_data[mems][color_cut] - RS_color RS_sigma = astats.biweight_midvariance( RS_shift[np.where(np.abs(RS_shift) < .15)]) # spec_mems is # of members that are within 2 sigma of cluster color clus_color_cut = np.where( np.abs(color_data[mems] - RS_color) < RS_sigma * 2)[0] spec_mems = len(clus_color_cut) self.__dict__.update(ez.create(keys, locals())) # If fed gr fit if gr_slope != None: def RS_color(r_mag): return r_mag * gr_slope + gr_inter RS_sigma = gr_width / 2 clus_color_cut = np.where( np.abs(color_data[mems] - RS_color(spec['rmags'])[mems]) < RS_sigma * 2)[0] spec_mems = len(clus_color_cut) self.__dict__.update(ez.create(keys, locals())) # Get Rdata from PhotoZ & SpecZ Data Set angles = C.findangle(all['ra'], all['dec'], clus_ra, clus_dec) all['rdata'] = angles * ang_d # Get deg per RVIR proper deg_per_rvir = R.Cosmo.arcsec_per_kpc_proper( clus_z).value * 1e3 * clus_rvir / 3600 # Get Area of Virial Circle out to 1 rvir, and Area of outer annuli, which is annuli from 4rvir < R < 6rvir, or dependent on rvir if clus_rvir < 2.5: outer_edge = 6.0 inner_edge = 4.0 elif clus_rvir >= 2.5 and clus_rvir < 3: outer_edge = 5.0 inner_edge = 3.5 else: outer_edge = 3.0 inner_edge = 2.0 SA_inner = np.pi * deg_per_rvir**2 SA_outer = np.pi * ((outer_edge * deg_per_rvir)**2 - (inner_edge * deg_per_rvir)**2) # Get Number of Cluster Color Galaxies from Photo Data Set in Inner Circle and Outer Annuli RS_color_sig = 2.0 if gr_slope == None: red_inner = np.where(((all['gmags'] - all['rmags']) < RS_color + RS_color_sig * RS_sigma) & ((all['gmags'] - all['rmags']) > RS_color - RS_color_sig * RS_sigma) & (all['rdata'] < clus_rvir))[0] red_outer = np.where(( (all['gmags'] - all['rmags']) < RS_color + 1.5 * RS_sigma) & ( (all['gmags'] - all['rmags']) > RS_color - 1.5 * RS_sigma) & (all['rdata'] < outer_edge * clus_rvir) & (all['rdata'] > inner_edge * clus_rvir))[0] else: red_inner = np.where(( (all['gmags'] - all['rmags']) < RS_color(all['rmags']) + RS_color_sig * RS_sigma) & ( (all['gmags'] - all['rmags']) > RS_color(all['rmags']) - RS_color_sig * RS_sigma) & (all['rdata'] < clus_rvir))[0] red_outer = np.where(( (all['gmags'] - all['rmags']) < RS_color(all['rmags']) + 1.5 * RS_sigma) & ( (all['gmags'] - all['rmags']) > RS_color(all['rmags']) - 1.5 * RS_sigma) & (all['rdata'] < outer_edge * clus_rvir) & (all['rdata'] > inner_edge * clus_rvir))[0] Nphot_inner = len(red_inner) Nphot_outer = len(red_outer) self.__dict__.update(ez.create(keys, locals())) # Get Solid Angle Density of Outer Red Galaxies outer_red_dense = Nphot_outer / SA_outer inner_background = int(np.ceil(outer_red_dense * SA_inner)) # Define obs_tot and obs_back_scaled, where obs_back_scaled is obs_back already scaled to inner aperture (aka. inner_background) obs_tot = np.copy(Nphot_inner) obs_back_scaled = np.copy(inner_background) # If inner_background is less than Nphot_inner, then Nphot_inner -= inner_background, otherwise Nphot_inner = 0 if inner_background < Nphot_inner: Nphot_inner -= inner_background else: Nphot_inner = 0 # Richness = spec_mems + Nphot_inner or just Nphot_inner if use_specs == True: richness = spec_mems + Nphot_inner else: richness = Nphot_inner self.__dict__.update(ez.create(keys, locals())) # Plot if plot_gr == True: fig, ax = mp.subplots() ax.plot(rmags, gmags - rmags, 'ko', alpha=.8) ax.plot(spec['rmags'][mems], color_data[mems], 'co') if gr_slope == None: ax.axhline(RS_color, color='r') ax.axhline(RS_color + RS_sigma, color='b') ax.axhline(RS_color - RS_sigma, color='b') else: xdata = np.arange(spec['rmags'][mems].min(), spec['rmags'][mems].max(), .1) ax.plot(xdata, RS_color(xdata), color='r') ax.plot(xdata, RS_color(xdata) + RS_sigma, color='b') ax.plot(xdata, RS_color(xdata) - RS_sigma, color='b') ax.set_xlim(13, 19) ax.set_ylim(0, 1.3) ax.set_xlabel('Apparent R Mag', fontsize=16) ax.set_ylabel('App G Mag - App R Mag', fontsize=16) ax.set_title('Color-Mag Diagram, Cluster ' + str(haloid)) fig.savefig('colormag_' + str(haloid) + '.png', bbox_inches='tight') mp.close(fig) if plot_sky == True: fig, ax = mp.subplots() ax.plot(all['ra'], all['dec'], 'ko') ax.plot(all['ra'][red_inner], all['dec'][red_inner], 'ro') ax.plot(all['ra'][red_outer], all['dec'][red_outer], 'yo') ax.plot(clus_ra, clus_dec, 'co', markersize=9) ax.set_xlabel('RA', fontsize=15) ax.set_ylabel('Dec.', fontsize=15) ax.set_title('Richness Annuli for Halo ' + str(haloid)) fig.savefig('skyplot_' + str(haloid) + '.png', bbox_inches='tight') mp.close(fig) if plot_phase == True: fig, ax = mp.subplots() ax.plot(spec['rdata'], spec['vdata'], 'ko') ax.plot(spec['rdata'][mems], spec['vdata'][mems], 'co') bcg = np.where( spec['abs_rmags'] == spec['abs_rmags'][mems].min())[0][0] ax.plot(spec['rdata'][bcg], spec['vdata'][bcg], 'ro') ax.set_xlim(0, 5) ax.set_ylim(-5000, 5000) ax.set_xlabel('Radius (Mpc)', fontsize=15) ax.set_ylabel('Velocity (km/s)', fontsize=15) ax.set_title('phasespace haloid ' + str(haloid)) fig.savefig('phasespace_' + str(haloid) + '.png', bbox_inches='tight') mp.close(fig) # Check to make sure galaxies exist (somewhat) uniformely in outer annuli (aka. cluster isn't on edge of observation strip) # First, project all galaxies into polar coordinates centered on cluster center x = (all['ra'] - clus_ra) / np.cos( clus_dec * np.pi / 180) # x coordinate in arcsec (of dec) centered on cluster center y = (all['dec'] - clus_dec) all['radius'] = np.sqrt(x**2 + y**2) / deg_per_rvir #radius scaled by RVIR all['theta'] = np.arctan(y / x) # Add corrections to arctan function all['theta'][np.where((x < 0) & (y > 0))] += np.pi # Quadrant II all['theta'][np.where((x < 0) & (y < 0))] += np.pi # Quadrant III all['theta'][np.where((x > 0) & (y < 0))] += 2 * np.pi # Quadrant IV # Then break outer annuli into 4 sections and check if at least 1 galaxy exists in each section sizes1 = np.array([ np.where((np.abs(all['theta'] - i) <= np.pi / 2) & (all['radius'] > inner_edge) & (all['radius'] < 15))[0].size for i in np.linspace(0, 2 * np.pi, 4) ]) # Do it again but shift theta by np.pi/8 this time sizes2 = np.array([ np.where((np.abs(all['theta'] - i) <= np.pi / 2) & (all['radius'] > inner_edge) & (all['radius'] < 15))[0].size for i in np.linspace(np.pi / 8, 17 * np.pi / 8, 4) ]) if 0 in sizes1 or 0 in sizes2: p = False if p == True: mp.plot(all['radius'], all['theta'], 'ko') mp.xlabel('radius') mp.ylabel('theta') mp.savefig('rth_' + str(haloid) + '.png') mp.close() print 'sizes1=', sizes1 print 'sizes2=', sizes2 return -99 return richness