def calculate_masses(self, snapnr=None, gc_max_age=10, gc_max_radius=250, print_header=True): with suppress_stdout(): # snapnr=None --> redshift zero s, sf = self.load_snapshot(snapnr=snapnr, loadonlytype=range(6)) M200 = sf.data["fmc2"][0] # 1e10 Msun r200 = sf.data["frc2"][0] * 1e3 # kpc istars, = numpy.where( # stars within 10% of R200 (s.type == 4) & (s.age > 0.) & (s.r() > 0.) & (s.r() < 0.1 * r200 / 1e3) & (s.halo == 0) & (s.subhalo == 0)) Mstars_tenpercent_r200 = s.mass[istars].sum() # Gas fraction within 0.1*R200 igas, = numpy.where( # gas within 10% of R200 (s.type == 0) & (s.r() > 0.) & (s.r() < 0.1 * r200 / 1e3) & (s.halo == 0) & (s.subhalo == 0)) Mgas_tenpercent_r200 = s.mass[igas].sum() fgas = Mgas_tenpercent_r200 / (Mgas_tenpercent_r200 + Mstars_tenpercent_r200) from investigate_auriga_gcs import GlobularClusterSystem with suppress_stdout(): GCS = GlobularClusterSystem(None, self.level, self.halo, radius=gc_max_radius, age=gc_max_age) GCS.set_FeH_allstars(s, sf) GCS.set_age_allstars(s, sf) GCS.set_FeH_oldstars(s, sf) Mgcs_red = s.mass[GCS.oldstars][GCS.old_red].sum() Mgcs_blue = s.mass[GCS.oldstars][GCS.old_blue].sum() Mgc = Mgcs_red + Mgcs_blue istellarhalo, = numpy.where( # stars within (s.type == 4) & (s.age > 0.) & (s.r() > 0.) & (s.r() < GCS.radius / 1000.) & (s.halo == 0) & (s.subhalo == 0)) Mstellarhalo = s.mass[istellarhalo].sum() if print_header: header = ["Run", "M200", "R200", "Mstar", "M*halo", "Mgc", "fgas"] print("{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}{:<10s}".format( *header)) info = [ self.name, M200, r200, Mstars_tenpercent_r200, Mstellarhalo, Mgc, fgas ] print("{:<10s}{:<10.2f}{:<10.2f}{:<10.2f}{:<10.2f}{:<10.2f}{:<10.2f}". format(*info)) del s, sf, GCS return info if not print_header else [header, info]
def get_snapshot_spacing(self, verbose=False): if not hasattr(self, "nsnaps"): self.find_all_snapshots(verbose=verbose) from areposnap.gadget import gadget_readsnap times = numpy.zeros(self.nsnaps) redshifts = numpy.zeros(self.nsnaps) for i, snapnr in enumerate(range(self.nsnaps)): # CAUTION, reruns seem to complain "couldnt find units in file" for each snapshot :o with suppress_stdout(): s = gadget_readsnap(snapnr, snappath=self.rundir + "/output/", onlyHeader=True) s.cosmology_init() redshifts[i] = s.redshift times[i] = s.cosmology_get_lookback_time_from_a( s.time.astype('float64'), is_flat=True) if verbose: print( "snapnr = {0:03d},\tz = {1:.5f},\ta = {2:.5f},\ttime = {3:.2f} Gyr" .format(snapnr, s.redshift, s.time, times[i])) self.cosmo = s.cosmo del s # s.time is actually scalefactor a which can be computed as a = 1/(1+z) self.times, self.redshifts = times, redshifts
def figure_1_bottom(MW_h96e10, M31_cr16_scaled_to_MW, MW_v13, MW_rvir, M31_rvir): fname = "figures/MW_M31_Rgc_Histogram.png" fig, ax = pyplot.subplots(figsize=(12, 9)) with suppress_stdout(): add_Rgc_MWandM31_to_ax( ax, MW_h96e10, M31_cr16_scaled_to_MW, M31_c11=None, MW_v13=MW_v13, show_cr16_age_subset=True, density=False, MW_rvir=MW_rvir, M31_rvir=M31_rvir, ) ax.set_xlim(0.15, 260) ax.set_xscale("log") ax.legend(loc="upper left", frameon=False, fontsize=18) fig.savefig(fname) pyplot.close(fig) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
def plot_harris1996_figure1_7_th(part2): fig, ax = pyplot.subplots(figsize=(12, 9)) with suppress_stdout(): # invalid value encountered in < and/or > red, = numpy.where((part2["FeH"] < -1) & numpy.isfinite(part2["FeH"])) blue, = numpy.where((part2["FeH"] >= -1) & numpy.isfinite(part2["FeH"])) bins, edges = numpy.histogram(part2["FeH"][red], bins=30, range=(-2.5, 0.5)) pyplot.plot((edges[1:] + edges[:-1]) / 2, bins, drawstyle="steps-mid", c="r") ax.fill_between(edges[:-1], bins, lw=0.0, hatch="/", step="post", edgecolor="red", facecolor="none") bins, edges = numpy.histogram(part2["FeH"][blue], bins=30, range=(-2.5, 0.5)) ax.fill_between(edges[:-1], bins, lw=0.0, hatch="/", step="post", edgecolor="blue", facecolor="none") pyplot.plot((edges[1:] + edges[:-1]) / 2, bins, drawstyle="steps-mid", c="b") FeH_range = numpy.arange(-2.8, 0.5, 0.01) ax.plot(FeH_range, 7.5 * g(FeH_range, -1.6, 0.3), c="k", ls="dashed") ax.plot(FeH_range, 3 * g(FeH_range, -0.6, 0.2), c="k", ls="dashed") ax.text(0.7, 0.7, "N = {0}".format(len(red) + len(blue)), transform=ax.transAxes) ax.set_xticks(numpy.arange(-2.5, 0.5, 0.5)) ax.set_xticks(numpy.arange(-2.8, 0.5, 0.1), minor=True) ax.set_yticks(numpy.arange(0, 25, 5)) ax.set_yticks(numpy.arange(0, 25, 1), minor=True) pyplot.xlim(-2.8, 0.4) pyplot.ylim(0, 20) pyplot.xlabel("Cluster Metallicity [Fe/H]") pyplot.ylabel("Number per Bin") pyplot.show()
def figure_4(auriga, MW_h96e10, M31_cr16, age_min): fname = "figures/FeH_mu_sigma_{:.1f}.png".format(age_min) with suppress_stdout(): fig, mu_insituold_minus_mu_accreted_old = plot_FeH_mean_vs_std( auriga, MW_h96e10, M31_cr16, age_min=args.age_min, debug=False) fig.savefig(fname) pyplot.close(fig) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
def figure_1_top(MW_v13, M31_cr16): fname = "figures/MW_M31_Age_Histogram.png" fig, ax = pyplot.subplots(figsize=(12, 9)) with suppress_stdout(): add_age_MWandM31_to_ax(ax, MW_v13, M31_cr16) ax.set_xlim(4, 14) ax.set_yscale("log") fig.savefig(fname) pyplot.close(fig) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
def figure_3(auriga, MW_h96e10, M31_cr16, age_min): fname = "figures/FeH_obs_Au4-4_Au4-10_Au4-21_{:.1f}.png".format(age_min) with suppress_stdout(): fig = plot_FeH_obs_and_4_and_10_and_21(auriga, MW_h96e10, M31_cr16, age_min=age_min) fig.savefig(fname) pyplot.close(fig) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
def figure_6(auriga, MWRgc, MW_h96e10, M31Rgc, age_min): fname = "figures/LogRgc_mu_sigma_{:.1f}.png".format(age_min) with suppress_stdout(): fig = plot_rgal_mean_vs_std(auriga, numpy.log10(MWRgc), MW_h96e10, numpy.log10(M31Rgc), age_min=age_min) fig.savefig(fname) pyplot.close(fig) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
def figure_5(auriga, MW_h96e10, M31_cr16, age_min): fname = "figures/logMFeH_withRatios_{:.1f}.png".format(age_min) with suppress_stdout(): fig = plot_FeH_ratios(auriga, ["istars", "iold", "insitu_old", "accreted_old"], MW_h96e10, M31_cr16, age_min=age_min) fig.savefig(fname) pyplot.close(fig) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
def load_snapshot(self, snapnr=None, redshift=None, tlookback=None, loadonlytype=[4], rotate=True, verbose=True): # Give snapnr to load a certain snapshot. If not given, use z=0 if snapnr is None: snapnr = self.nsnaps - 1 # If redshift is given, find the snapshot closest to this redshift if redshift is not None and type(redshift) is float: if not hasattr(self, "redshifts"): self.get_snapshot_spacing(verbose=verbose) snapnr = (numpy.abs(self.redshifts - redshift)).argmin() print("Loading snapshot closest to z = {0}".format(redshift)) print("The closest snapshot is {0} (z = {1:.2f})".format( snapnr, self.redshifts[snapnr])) # If tlookback given, find the snapshot closest ot this tlookback if tlookback is not None and type(tlookback) is float or type( tlookback) is int: if not hasattr(self, "times"): self.get_snapshot_spacing(verbose=verbose) snapnr = (numpy.abs(self.times - tlookback)).argmin() print("Loading snapshot closest to tlookback = {0}".format( tlookback)) print("The closest snapshot is {0} (tlookback = {1:.2f})".format( snapnr, self.times[snapnr])) if verbose: return eat_snap_and_fof(self.level, self.halo, snapnr, verbose=verbose, run=self, snappath=self.rundir + "/output/", loadonlytype=loadonlytype, rotate=rotate) else: with suppress_stdout(): return eat_snap_and_fof(self.level, self.halo, snapnr, verbose=verbose, run=self, snappath=self.rundir + "/output/", loadonlytype=loadonlytype)
def plot_GCS_level345(self, halo, gc_max_age=10, gc_max_radius=250): print("plot_GCS_level345") print(" halo = {0}".format(halo)) print(" gc_max_age = {0} Gyr".format(gc_max_age)) print(" gc_max_radius = {0} kpc\n".format(gc_max_radius)) from investigate_auriga_gcs import GlobularClusterSystem with suppress_stdout(): GCS = GlobularClusterSystem(self, None, halo, radius=gc_max_radius, age=gc_max_age) GCS.plot_diagnostics_level345(self, halo)
def get_snapshot_spacing_highfreqstars(self, verbose=False, from_snapshots=False): if not hasattr(self, "highfreqstars"): self.find_all_highfreqstars(verbose=verbose) times = numpy.zeros(self.nhighfreqstars) redshifts = numpy.zeros(self.nhighfreqstars) output_list = self.rundir + "/output_list_high_freq_stars.txt" if os.path.exists(output_list) and os.path.isfile( output_list) and not from_snapshots: a = numpy.zeros(self.nhighfreqstars) with open(output_list) as w: for i, line in enumerate(w.readlines()): a[i] = line # a = 1/(1+z) redshifts[i] = 1 / a[i] - 1 times[i] = self.cosmology_get_lookback_time_from_a( a[i].astype('float64'), is_flat=True) self.times_highfreqstars, self.redshifts_highfreqstars = times, redshifts return from tlrh_util import print_progressbar from areposnap.gadget import gadget_readsnap print("Setting redshifts for highfreqstars") for i, snapnr in enumerate(range(self.nhighfreqstars)): print_progressbar(snapnr, self.nhighfreqstars, whitespace=" ") # CAUTION, reruns seem to complain "couldnt find units in file" for each snapshot :o with suppress_stdout(): # What's up with 2763?? O_o ... 000, 001, ..., 2761, 2762, 6764 s = gadget_readsnap(snapnr if snapnr != 2763 else 2764, snappath=self.rundir + "/output/", snapbase="snapshot_highfreqstars_", snapdirbase="snapdir_highfreqstars_", onlyHeader=True) s.cosmology_init() redshifts[i] = s.redshift times[i] = s.cosmology_get_lookback_time_from_a( s.time.astype('float64'), is_flat=True) if verbose: print( "snapnr = {0:03d},\tz = {1:.5f},\ta = {2:.5f},\ttime = {3:.2f} Gyr" .format(snapnr, s.redshift, s.time, times[i])) self.cosmo = s.cosmo del s # s.time is actually scalefactor a which can be computed as a = 1/(1+z) self.times_highfreqstars, self.redshifts_highfreqstars = times, redshifts
def figure_2_bottom(M31_cr16_scaled_to_MW, plot_values_skip): fname = "figures/M31_RgcFeH_HistogramMassWeighted_CaldwellRomanowsky2016data.png" fig, ax = pyplot.subplots(figsize=(12, 9)) with suppress_stdout(): add_CaldwellRomanowsky_FeH_Rgc_logM_M31_to_ax( ax, M31_cr16_scaled_to_MW, do_scatter=False, plot_values_skip=plot_values_skip, debug=False, ) fig.suptitle("Andromeda GCS") fig.savefig(fname) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
def plot_caldwell2011_figure23(data): fig, (ax1, ax2) = pyplot.subplots(2, 1, figsize=(10, 11)) finite, = numpy.where(numpy.isfinite(data["[Fe/H]"])) X, Y, Rproj = calculate_M31_Rgc_Wang2019(data["SkyCoord"], deproject=False, debug=False) ax1.plot(numpy.log10(Rproj[finite]), data["[Fe/H]"][finite], "ko", ms=6) with suppress_stdout( ): # RuntimeWarning: invalid value encountered in log10 ax2.plot(numpy.log10(Y[finite]), data["[Fe/H]"][finite], "ko", ms=6) # Sanity check: calculate Rproj with the given X and Y in the dataset # ax1.plot(numpy.log10(numpy.sqrt(data["X"][finite]**2 + data["Y"][finite]**2)), # data["[Fe/H]"][finite], "ro", ms=6) # Sanity check: plot the given Y in the dataset # ax2.plot(numpy.log10(data["Y"][finite]), data["[Fe/H]"][finite], "ro", ms=6) # Sanity check: compare the given X in the dataset with the calculated X # ax2.plot(numpy.log10(X[finite]), data["[Fe/H]"][finite], "ko", ms=6) # ax2.plot(numpy.log10(data["X"][finite]), data["[Fe/H]"][finite], "ro", ms=6) ax2.axhline(-0.4, ls="--", c="k") for ax in [ax1, ax2]: ax.set_ylabel("[Fe/H]") ax.set_yticks(numpy.arange(-3, 2, 1)) ax.set_yticks(numpy.arange(-3.2, 1.2, 0.2), minor=True) ax.set_ylim(-3, 1) ax1.set_xlabel("log(radius) (kpc)") ax1.set_xticks(numpy.arange(0, 3, 1)) ax1.set_xticks(numpy.arange(-1, 2.2, 0.2), minor=True) ax1.set_xlim(-0.8, 2.2) ax2.set_xlabel("log(minor axis distance) (kpc)") ax2.set_xticks(numpy.arange(-2, 3, 1)) ax2.set_xticks(numpy.arange(-2.2, 2.4, 0.2), minor=True) ax2.set_xlim(-2.1, 2.1) pyplot.tight_layout() pyplot.show()
def get_total_stellar_mass_versus_time(self, verbose=False): if verbose: print("\nRunning get_total_stellar_mass_versus_time") if not hasattr(self, "nsnaps"): self.find_all_snapshots(verbose=verbose) binary_file = "../out/{0}/{0}_total_stellar_mass".format(self.name) if os.path.exists(binary_file): self.total_stellar_mass = numpy.fromfile(binary_file) else: self.total_stellar_mass = numpy.zeros(self.nsnaps) # TODO move insitu_fraction from RenaudOgertGieles2017 to here? # self.insitu_fraction = numpy.zeros(self.nsnaps) for snapnr in range(self.nsnaps): if verbose: print(" Eating snapshot: {0}/{1}".format( snapnr, self.nsnaps - 1)) s, sf = self.load_snapshot(snapnr=snapnr, loadonlytype=[4], verbose=True) required = ["pos", "halo", "subhalo", "mass"] if not all(x in s.data.keys() for x in required): missing = [x for x in required if x not in s.data.keys()] if not verbose: print(" Eating snapshot: {0}/{1}".format( snapnr, self.nsnaps - 1)) print(" WARNING: not all required data is available!") print(" required: {0}".format(required)) print(" missing: {0}\n".format(missing)) continue with suppress_stdout(): sr = s.r() stars_in_main_galaxy, = numpy.where((s.halo == 0) & (s.subhalo == 0) & (s.type == 4) & (s.age > 0.)) self.total_stellar_mass[ snapnr] = s.mass[stars_in_main_galaxy].sum() * 1e10 if verbose: print(" Success!\n") self.total_stellar_mass.tofile(binary_file) del s, sf
def figure_2_top(MW_h96e10, plot_values_skip): fname = "figures/MW_RgcFeH_HistogramMassWeighted_Harris1996ed2010data.png" fig, ax = pyplot.subplots(figsize=(12, 9)) with suppress_stdout(): add_Harris_FeH_Rgc_logM_MW_to_ax( ax, MW_h96e10, do_scatter=False, plot_values_skip=plot_values_skip, debug=False, ) fig.suptitle("Milky Way GCS") fig.savefig(fname) pyplot.close(fig) os.system("convert -trim {} {}".format(fname, fname.replace(".png", "-trim.png"))) os.remove(fname) print("Saved {}".format(fname))
if __name__ == "__main__": pyplot.style.use("tlrh") data = read_caldwell_romanowsky_2016_data() print("There are {0: >3d} globular clusters in total".format(len(data))) i_has_vel, = numpy.where(numpy.isfinite(data["RVel"])) print( "There are {0: >3d} globular clusters /w velocity measurement".format( len(i_has_vel))) i_has_logM, = numpy.where(numpy.isfinite(data["LogM"])) print("There are {0: >3d} globular clusters /w logM measurement".format( len(i_has_logM))) with suppress_stdout(): i_has_FeH, = numpy.where((data["[Fe/H]"] > -6) & (data["[Fe/H]"] < 4)) print("There are {0: >3d} globular clusters /w [Fe/H] measurement".format( len(i_has_FeH))) with suppress_stdout(): i_has_FeH_and_logM, = numpy.where( numpy.isfinite(data["[Fe/H]"]) & (data["[Fe/H]"] > -6) & (data["[Fe/H]"] < 4) & numpy.isfinite(data["LogM"])) print( "There are {0: >3d} globular clusters /w [Fe/H] and logM measurement". format(len(i_has_FeH_and_logM))) with suppress_stdout(): i_has_age, = numpy.where((data["Age"] < 13.99))
def get_insitu_for_snapnr(run, snapnr, insitu_def, verbose=False, debug=False): previous_redshift = run.redshifts[snapnr - 1] previous_time = run.times[snapnr - 1] previous_a = 1 / (previous_redshift + 1) current_redshift = run.redshifts[snapnr] current_time = run.times[snapnr] current_a = 1 / (current_redshift + 1) if snapnr is 0: previous_redshift = 1000 # should be infinity # perhaps calculate lookbacktime for a=0 and see what happens? previous_time = current_time previous_a = 0 if verbose: print("\nEating snapshot: {0}/{1}".format(snapnr, run.nsnaps - 1)) print(" previous redshift: {0}".format(previous_redshift)) print(" current redshift: {0}".format(current_redshift)) print(" previous time: {0}".format(previous_time)) print(" current time: {0}".format(current_time)) print(" previous a: {0}".format(previous_a)) print(" current a: {0}".format(current_a)) with suppress_stdout(): s, sf = run.load_snapshot(snapnr=snapnr, loadonlytype=[4], verbose=True) required = ["id", "pos", "age", "halo", "subhalo"] if not all(x in s.data.keys() for x in required): missing = [x for x in required if x not in s.data.keys()] if verbose: print( "WARNING: s does not have all required info. Saving empty file." ) print("required: {0}".format(required)) print("missing: {0}\n".format(missing)) if not os.path.exists("../out/{0}/insitu".format(s.name)): os.mkdir("../out/{0}/insitu".format(s.name)) numpy.savetxt( "../out/{0}/insitu/{0}_insitu_{1}_{2}.txt".format( s.name, snapnr, insitu_def), numpy.array([], dtype=numpy.uint64), fmt='%d', ) numpy.savetxt( "../out/{0}/insitu/{0}_satellite_{1}.txt".format(s.name, snapnr), numpy.array([], dtype=numpy.uint64), fmt='%d', ) # optional istars = numpy.array([], dtype=numpy.uint64) insitu = numpy.array([], dtype=numpy.uint64) isatellite = numpy.array([], dtype=numpy.uint64) igalaxy = numpy.array([], dtype=numpy.uint64) igalaxy_10percentr200 = numpy.array([], dtype=numpy.uint64) else: # s.age is actually scalefactor, so redshift z = (1/a -1) # born is the snapshot in which a particle first appeared s_redshifts = (1 / s.age - 1) istars, = numpy.where((s.type == 4) & (s.age > 0.)) igalaxy, = numpy.where((s.type == 4) & (s.age > 0.) & (s.halo == 0) & (s.subhalo == 0)) igalaxy_10percentr200, = numpy.where((s.type == 4) & (s.age > 0.) & (s.halo == 0) & (s.subhalo == 0) & (s.r() < s.galrad)) # To find accreted stars we look for stars born outside of halo 0 subhalo 0 # Stars in this subset that live within r200 at z=0 can then be classified # as accreted. isatellite, = numpy.where((s.type == 4) & (s.age > 0.) & ((s.halo != 0) | ( (s.halo == 0) & (s.subhalo != 0)))) # TODO: perhaps not fixed def, but function of galradfrac? if insitu_def == "galrad": if verbose: print("\nInsitu requires r < galrad (=10% of virial radius)") insitu, = numpy.where( # Stars in the main halo + main subhalo, # within 10% of the virial radius (--> disk) (s.type == 4) & (s.halo == 0) & (s.subhalo == 0) & (s.r() < s.galrad) # only look at stars that have formed in the timespan from last # snapshot until now the condition s.age < current_a should not # make a difference because no star can be older of course & (s.age > 0.) & (s.age > previous_a) & (s.age < current_a)) elif insitu_def == "virial": if verbose: print("\nInsitu requires r < 10*galrad (= virial radius)") insitu, = numpy.where( # Stars in the main halo + main subhalo, # within 10% of the virial radius (--> disk) (s.type == 4) & (s.halo == 0) & (s.subhalo == 0) & (s.r() < 10 * s.galrad) # galrad is 10% of virial radius # only look at stars that have formed in the timespan from last # snapshot until now the condition s.age < current_a should not # make a difference because no star can be older of course & (s.age > 0.) & (s.age > previous_a) & (s.age < current_a)) elif insitu_def == "30kpc": if verbose: print("\nInsitu requires r < 30 kpc") insitu, = numpy.where( # Stars in the main halo + main subhalo, # within 10% of the virial radius (--> disk) (s.type == 4) & (s.halo == 0) & (s.subhalo == 0) & (s.r() < float(30) / 1000) # galrad is 10% of virial radius # only look at stars that have formed in the timespan from last # snapshot until now the condition s.age < current_a should not # make a difference because no star can be older of course & (s.age > 0.) & (s.age > previous_a) & (s.age < current_a)) if not os.path.exists("../out/{0}/insitu".format(s.name)): os.mkdir("../out/{0}/insitu".format(s.name)) numpy.savetxt("../out/{0}/insitu/{0}_insitu_{1}_{2}.txt".format( s.name, snapnr, insitu_def), s.id[insitu], fmt='%d') numpy.savetxt("../out/{0}/insitu/{0}_satellite_{1}.txt".format( s.name, snapnr), s.id[isatellite], fmt='%d') if verbose: print(" len(istars): {0}".format(len(istars))) print(" len(insitu): {0}".format(len(insitu))) print(" len(isatellite): {0}".format(len(isatellite))) print(" len(igalaxy): {0}".format(len(igalaxy))) print(" len(igalaxy_10percentr200): {0}".format( len(igalaxy_10percentr200))) print("") # At end of function we delete s and sf del s, sf
def plot_caldwell2011_figure24(M31_c11, MW_h96e10, debug=False): fig, (ax1, ax2) = pyplot.subplots(1, 2, figsize=(16, 8), sharey=True) Ryz = numpy.log10(numpy.sqrt(MW_h96e10["Y"]**2 + MW_h96e10["Z"]**2)) Rproj = numpy.log10(M31_c11["Rproj"]) # RuntimeWarning: invalid value encountered in less with suppress_stdout(): FeH_high, = numpy.where((M31_c11["[Fe/H]"] > -0.4)) FeH_med, = numpy.where((M31_c11["[Fe/H]"] < -0.4) & (M31_c11["[Fe/H]"] > -0.9)) FeH_low, = numpy.where((M31_c11["[Fe/H]"] < -0.9)) r_ana = numpy.linspace(-0.2, 1.3, 9) for rmin, rmax in zip(r_ana[:-1], r_ana[1:]): rmid = (rmin + rmax) / 2 area = numpy.pi * (10**rmid)**2 Nmw = len(numpy.where((Ryz > rmin) & (Ryz < rmax))[0]) Nm31 = len(numpy.where((Rproj > rmin) & (Rproj < rmax))[0]) if debug: print("{:7.3f}{:7.3f}{:10.3f}{:7d}{:7.3f}{:7d}{:7.3f}".format( rmin, rmax, area, Nmw, numpy.log10(Nmw / area), Nm31, numpy.log10(Nm31 / area))) # TODO: calculate the errorbars mw = ax1.errorbar(rmid, numpy.log10(Nmw / area), yerr=0.2 * numpy.log10(numpy.sqrt(Nmw)), ls="none", marker="+", c="r", ms=10, capsize=4) for ax in [ax1, ax2]: m31 = ax.errorbar( rmid, numpy.log10(Nm31 / area), yerr=0.2 * numpy.log10(numpy.sqrt(Nm31)), ls="none", marker="o", c="k", ms=10, capsize=4, ) # [Fe/H] > -0.4 --> 'high' Nm31_high = len( numpy.where((Rproj[FeH_high] > rmin) & (Rproj[FeH_high] < rmax))[0]) with suppress_stdout( ): # RuntimeWarning: divide by zero encountered in log10 m31_high = ax.errorbar( rmid, numpy.log10(Nm31_high / area), yerr=0.2 * numpy.log10(numpy.sqrt(Nm31_high)), ls="none", marker="X", c="r", ms=10, capsize=4, ) # -0.9 < [Fe/H] < -0.4 --> 'med' Nm31_med = len( numpy.where((Rproj[FeH_med] > rmin) & (Rproj[FeH_med] < rmax))[0]) m31_med = ax.errorbar( rmid, numpy.log10(Nm31_med / area), yerr=0.2 * numpy.log10(numpy.sqrt(Nm31_med)), ls="none", marker="o", c="orange", ms=10, mfc="none", capsize=4, ) # [Fe/H] < -0.9 --> 'low' Nm31_low = len( numpy.where((Rproj[FeH_low] > rmin) & (Rproj[FeH_low] < rmax))[0]) m31_low = ax.errorbar( rmid, numpy.log10(Nm31_low / area), yerr=0.2 * numpy.log10(numpy.sqrt(Nm31_low)), ls="none", marker="o", c="b", ms=8, capsize=4, ) # Add powerlaw with slope -2.5 r_ana = numpy.linspace(0, 1, 64) ax1.plot(r_ana, -2.5 * r_ana, c="r") for ax in [ax1, ax2]: ax.set_xticks(numpy.arange(-0.5, 2.5, 0.5)) ax.set_xticks(numpy.arange(-0.25, 1.75, 0.25), minor=True) ax.set_yticks(numpy.arange(-2.5, 1.5, 0.5)) ax.set_yticks(numpy.arange(-3, 1.25, 0.25), minor=True) ax.set_xlim(-0.2, 1.4) ax.set_ylim(-2.8, 1.2) ax.set_xlabel("log R (kpc)") ax1.legend([m31, mw], ["M31", "MW"], frameon=True, fontsize=16) ax1.set_ylabel(r"log (Clusters kpc$^{-2}$)") ax2.legend([m31, m31_high, m31_med, m31_low], [ "M31", "[Fe/H]$>$-0.4 ({})".format( len(FeH_high)), "-0.9$<$[Fe/H]$<$-0.4 ({})".format(len(FeH_med)), "[Fe/H]$<$-0.9 ({})".format(len(FeH_low)) ], frameon=True, fontsize=16) # pyplot.tight_layout() pyplot.subplots_adjust(wspace=0, hspace=0) pyplot.show()
def plot_caldwell_mass_metallicity_relation(data, do_fit=True): fig, ax = pyplot.subplots(figsize=(12, 9)) # RuntimeWarning: invalid value encountered in less_equal with suppress_stdout(): rich, = numpy.where( numpy.isfinite(data["[Fe/H]"]) & numpy.isfinite(data["logM"]) & (data["[Fe/H]"] > -0.8)) poor, = numpy.where( numpy.isfinite(data["[Fe/H]"]) & numpy.isfinite(data["logM"]) & (data["[Fe/H]"] <= -0.8)) ax.plot(data["[Fe/H]"][rich], data["logM"][rich], "ko", ms=8) ax.plot(data["[Fe/H]"][poor], data["logM"][poor], "ko", ms=8, mfc="none") finite = numpy.union1d(rich, poor) print("Sample size: {0}".format(len(finite))) # First, calculate Pearson correlation coefficient # Here -1 (negative correlation) or +1 (positive correlation) # imply an exact linear relationship. 0 means no correlation. # The p value is the 2-tailed p-value that an uncorrelated system produces # two datasets that have a Pearson correlation at least as extreme as # computed from these datasets. Assumes both datasets are normally distributed r, p = scipy.stats.pearsonr(data["[Fe/H]"][finite], data["logM"][finite]) print("Pearson r: {0:.5f} (p = {1:.5f})".format(r, p)) # Does not assume normal distribution in both data sets. rho, p = scipy.stats.spearmanr(data["[Fe/H]"][finite], data["logM"][finite]) print("Spearman rho: {0:.5f} (p = {1:.5f})".format(rho, p)) # https://www.statisticshowto.datasciencecentral.com/ # spearman-rank-correlation-definition-calculate/ FeHrank = scipy.stats.rankdata(data["[Fe/H]"][finite]) massrank = scipy.stats.rankdata(data["logM"][finite]) sxy = numpy.sum( (FeHrank - numpy.mean(FeHrank)) * (massrank - numpy.mean(massrank))) sxy /= len(FeHrank) sx = numpy.sum((FeHrank - numpy.mean(FeHrank))**2) / len(FeHrank) sy = numpy.sum((massrank - numpy.mean(massrank))**2) / len(massrank) rho = sxy / numpy.sqrt(sx * sy) # Fit to y|x mmr_mean, edges, binnumbers = scipy.stats.binned_statistic( data["[Fe/H]"][finite], data["logM"][finite], statistic="mean") mmr_sem, edges, binnumbers = scipy.stats.binned_statistic( data["[Fe/H]"][finite], data["logM"][finite], statistic=lambda array: scipy.stats.sem(array)) mmr_std, edges, binnumbers = scipy.stats.binned_statistic( data["[Fe/H]"][finite], data["logM"][finite], statistic=lambda array: numpy.std(array)) ax.errorbar((edges[1:] + edges[:-1]) / 2, mmr_mean, yerr=mmr_sem, ls="none", marker="o", c="r", ms=8) if do_fit: from tlrh_statistics import fit_to_data fitfunc = lambda p, x: p[0] * x + p[1] x = (edges[1:] + edges[:-1]) / 2 x_ana = numpy.linspace(-3.2, 1.4, 128) popt, perr = fit_to_data(ax, x, mmr_mean, mmr_std, fitfunc, [0, 5.5], x_ana=x_ana) # Fit to x|y mmr_mean_inv, edges_inv, binnumbers_inv = scipy.stats.binned_statistic( data["logM"][finite], data["[Fe/H]"][finite], statistic="mean") mmr_sem_inv, edges_inv, binnumbers_inv = scipy.stats.binned_statistic( data["logM"][finite], data["[Fe/H]"][finite], statistic=lambda array: scipy.stats.sem(array)) mmr_std_inv, edges_inv, binnumbers_inv = scipy.stats.binned_statistic( data["logM"][finite], data["[Fe/H]"][finite], statistic=lambda array: numpy.std(array)) ax.errorbar(mmr_mean_inv, (edges_inv[1:] + edges_inv[:-1]) / 2, xerr=mmr_sem_inv, ls="none", marker="o", c="b", ms=8) # TODO: do the fit? ax.set_xlabel("[Fe/H]") ax.set_ylabel(r"log$_{10}(\rm M/\rm M_{\odot})$") ax.set_xticks(numpy.arange(-3.5, 1.5, 0.5)) ax.set_xticks(numpy.arange(-3.2, 1.5, 0.1), minor=True) ax.set_yticks(numpy.arange(3, 9, 1)) ax.set_yticks(numpy.arange(3, 8.2, 0.2), minor=True) pyplot.xlim(-3.2, 1.4) pyplot.ylim(4, 7.5) pyplot.show()
def read_caldwell2011_data_from_vizier(fname="../data/Caldwell2011/table1.dat", verbose=False, debug=False): dirname = os.path.dirname(__file__) fname = os.path.join(dirname, fname) Ncols = 13 + 2 + 2 Nrows = sum(1 for line in open(fname, "r")) # Default to float in column, but change for known strings formats = [numpy.float for i in range(Ncols)] formats[0] = "S10" formats[1] = "S1" formats[2] = "S13" formats[3] = "S13" formats[5] = "S1" formats[12] = "S1" formats[13] = "object" formats[14] = "object" formats[15] = "f8" formats[16] = "f8" # Name columns to access 'm by later-on names = [ "Name ", "n_Name", "RA", "DEC", "E(B-V)", ")", "Vel", "e_Vel", "logM", "[Fe/H]", "e_[Fe/H]", "Age", "Notes", "SkyCoord", "ICRS", "Rproj", "Rdeproj" ] # Pack it all up, and initialise empty array dtype = {"names": names, "formats": formats} data = numpy.empty(Nrows, dtype=dtype) # Start and end indices from catalog's ReadMe file cs = [1, 11, 13, 23, 35, 39, 41, 48, 51, 55, 60, 64, 69] ce = [10, 12, 22, 33, 38, 40, 46, 49, 53, 58, 62, 67, 81] with open(fname, "rb") as f: for i, row in enumerate(f.readlines()): # SkyCoord, ICRS, Rproj, Rdeproj not in data for j in range(Ncols - 4): value = row[cs[j] - 1:ce[j]].strip() if formats[j] == numpy.float: if len(value) is 0: value = numpy.nan else: value = float(value) if formats[j] == numpy.bytes_: if len(value) is 0: value = "" data[names[j]][i] = value for x in range(Nrows): data["SkyCoord"][x] = coord.SkyCoord(data["RA"][x].decode("ascii"), data["DEC"][x].decode("ascii"), frame="icrs", equinox="J2000", unit=(u.hourangle, u.deg)) # Here we follow sec 4.1 from Wang, Ma & Liu (2019, sec 4.1). arXiv 1901.11229v1 # However, what they call deprojected galactocentric radius does not have units # kpc, so this must be an angle in units of radian. So we convert this angle # on the sky to kpc by using the distance to Andromeda galaxy. X, Y, Rproj = calculate_M31_Rgc_Wang2019(data["SkyCoord"], deproject=False, debug=False) data["Rproj"] = Rproj X, Y, Rdeproj = calculate_M31_Rgc_Wang2019(data["SkyCoord"], deproject=True, debug=False) data["Rdeproj"] = Rdeproj with suppress_stdout(): has_no_age, = numpy.where(data["Age"] == 14.00) data["Age"][has_no_age] = numpy.nan if verbose: print("\nWARNING: {0} GC ages were changed".format(len(has_no_age)), end="") print(" from 14.00 to numpy.nan (b/c no age estimate available)\n") print("Succesfully read: '{0}'".format(fname)) print("Usage: data = read_caldwell2011_data() ") print("You can then access rows using data[0]") print("You can access columns using data['colname']") print("To find all column names, use 'data.dtype.names'") print_caldwell2011_data(data, example=True) return data
def plot_harris1996_figure1_8(part1, part2): fig, (ax1, ax2) = pyplot.subplots(2, 1, figsize=(9, 14)) # RuntimeWarning: invalid value encountered in greater with suppress_stdout(): rich, = numpy.where( numpy.isfinite(part2["FeH"]) & (part2["FeH"] > -1.0)) poor, = numpy.where( numpy.isfinite(part2["FeH"]) & (part2["FeH"] <= -1.0)) ax1.plot(numpy.log10(part1["R_gc"][rich]), part2["FeH"][rich], "ko", ms=8) ax1.plot(numpy.log10(part1["R_gc"][poor]), part2["FeH"][poor], "ko", ms=8, mfc="none") FeH_mean, edges, binnumbers = scipy.stats.binned_statistic( numpy.log10(part1["R_gc"][rich]), part2["FeH"][rich], bins=5) FeH_sem, edges, binnumbers = scipy.stats.binned_statistic( numpy.log10(part1["R_gc"][rich]), part2["FeH"][rich], statistic=lambda x: scipy.stats.sem(x), bins=5) ax2.errorbar((edges[1:] + edges[:-1]) / 2, FeH_mean, yerr=FeH_sem, ls="none", marker="o", c="k", ms=8) FeH_mean, edges, binnumbers = scipy.stats.binned_statistic( numpy.log10(part1["R_gc"][poor]), part2["FeH"][poor], statistic="mean") # CAUTION, using std err as errorbar in the mean FeH_sem, edges, binnumbers = scipy.stats.binned_statistic( numpy.log10(part1["R_gc"][poor]), part2["FeH"][poor], statistic=lambda x: scipy.stats.sem(x)) ax2.errorbar((edges[1:] + edges[:-1]) / 2, FeH_mean, yerr=FeH_sem, ls="none", marker="o", c="k", ms=8, mfc="none") # Harris' trend line Delta [Fe/H] / Delta log(Rgc) = -0.30 radii = numpy.power(10, numpy.linspace(0.0001, 1, 42)) ax2.plot(numpy.log10(radii), numpy.log10(radii**(-0.30)) - 0.4, c="k") ax2.plot(numpy.log10(radii), numpy.log10(radii**(-0.30)) - 1.2, c="k") for ax in [ax1, ax2]: ax.set_xticks(numpy.arange(0, 3, 0.5)) ax.set_xticks(numpy.arange(-0.4, 2.6, 0.1), minor=True) ax.set_yticks(numpy.arange(-2.0, 1, 1)) ax.set_yticks(numpy.arange(-2.4, 0.6, 0.2), minor=True) ax.set_xlim(-0.3, 2.5) ax.set_ylim(-2.8, 0.4) ax1.set_ylabel("[Fe/H]") ax2.set_xlabel(r"log R$_{\text{GC}}$ (kpc)") ax2.set_ylabel(r"$<$[Fe/H]$>$") pyplot.show()
def plot_harris1996_figure1_3_th(part1, part2, use_2d=False): fig, ax = pyplot.subplots(figsize=(9, 9)) ax.text(0.5, 1.02, "Space Distribution (Milky Way)", transform=ax.transAxes, ha="center", va="bottom") # RuntimeWarning: invalid value encountered in greater with suppress_stdout(): red, = numpy.where(numpy.isfinite(part2["FeH"]) & (part2["FeH"] > -1)) blue, = numpy.where( numpy.isfinite(part2["FeH"]) & (part2["FeH"] <= -1)) rmax = 10**2.5 radii = numpy.power(10, numpy.linspace(numpy.log10(1), numpy.log10(rmax), 7)) volume = 4 / 3 * numpy.pi * radii**3 NredOld = numpy.zeros(radii.shape, dtype="i8") NblueOld = numpy.zeros(radii.shape, dtype="i8") for i, (r1, r2) in enumerate(zip(radii[:-1], radii[1:])): nRedOld, = numpy.where((part1["R_gc"][red] > r1) & (part1["R_gc"][red] < r2)) nBlueOld, = numpy.where((part1["R_gc"][blue] > r1) & (part1["R_gc"][blue] < r2)) NredOld[i] = len(nRedOld) NblueOld[i] = len(nBlueOld) if use_2d: volume[i] = 4 * numpy.pi * ((r1 + r2) / 2)**2 * (r2 - r1) with suppress_stdout(): # divide by zero encountered in log10 pyplot.plot(numpy.log10(radii), numpy.log10(NblueOld / volume), "bo", ms=5, label=r"[Fe/H] $\leq$ -1, N = {0}".format(len(blue))) pyplot.plot(numpy.log10(radii), numpy.log10(NredOld / volume), "ro", ms=5, label=r"[Fe/H] $>$ -1, N = {0}".format(len(red))) radii_red = numpy.power(10, numpy.linspace(0.5, 2.2, 42)) radii_blue = numpy.power(10, numpy.linspace(0.0001, 0.7, 42)) pyplot.plot(numpy.log10(radii_red), numpy.log10(radii_red**(-3.5)), c="k") pyplot.plot(numpy.log10(radii_blue), numpy.log10(radii_blue**(-2)) - 0.75, c="k", ls="--") ax.text(0.7, 0.2, r"$\phi \sim $R$^{-3.5}$", transform=ax.transAxes, fontsize=22) ax.set_xticks(numpy.arange(0, 3, 0.5)) ax.set_xticks(numpy.arange(0, 2.6, 0.1), minor=True) ax.set_yticks(range(0, -8, -2)) ax.set_yticks(numpy.arange(0.5, -8, -0.5), minor=True) ax.set_xlim(0, 2.5) ax.set_ylim(-7.5, 1) pyplot.xlabel(r"log R$_{\text{GC}}$ (kpc)") pyplot.ylabel(r"log $\phi$ (number per kpc$^3$)") ax.grid(color='grey', ls=":", lw=1, alpha=0.2, which="minor") ax.grid(color='grey', ls=":", lw=1, alpha=0.5, which="major") pyplot.legend(loc="lower left", frameon=False, fontsize=16) # pyplot.tight_layout() pyplot.savefig("../out/MilkyWay_GlobularClusterSystem_phi-vs-Rgc_th.png") pyplot.show()
pyplot.ylim(3, 7) pyplot.show() if __name__ == "__main__": pyplot.switch_backend("agg") pyplot.style.use("tlrh") part1, part2, part3 = read_harris1996_data() print_harris1996_data(part1, part2, part3, example=True) print("There are {0: >3d} globular clusters in total".format(len(part2))) i_has_M_vt, = numpy.where(numpy.isfinite(part2["M_Vt"])) print("There are {0: >3d} globular clusters /w M_Vt measurement".format( len(i_has_M_vt))) with suppress_stdout(): # invalid value encountered in < and/or > i_has_FeH, = numpy.where((part2["FeH"] > -6) & (part2["FeH"] < 4)) print("There are {0: >3d} globular clusters /w FeH measurement".format( len(i_has_FeH))) # plot_harris1996_figure1_2(part1) # plot_harris1996_figure1_2_th(part1, part2) # plot_harris1996_figure1_3(part1, part2) # plot_harris1996_figure1_3_th(part1, part2) # plot_harris1996_figure1_7(part2) # plot_harris1996_figure1_7_th(part2) # plot_MW_mass_distribution(part2)