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 cosmology_get_lookback_time_from_a(self, a, is_flat=True): if not hasattr(self, "cosmo"): from areposnap.gadget import gadget_readsnap s = gadget_readsnap(127 if self.level == 4 else 63, snappath=self.rundir + "/output/", onlyHeader=True) s.cosmology_init() self.cosmo = s.cosmo return self.cosmo.LookbackTime_a_in_Gyr(a, is_flat=is_flat)
def load_header(self, snapnr=None, redshift=None, tlookback=None, 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])) from areposnap.gadget_subfind import load_subfind from areposnap.gadget import gadget_readsnap sf = load_subfind(snapnr, dir=self.rundir + "/output/") s = gadget_readsnap(snapnr, snappath=self.rundir + "/output/", subfind=sf, onlyHeader=True) # Sneak some more info into the s instance s.halo_number = self.halo s.level = self.level s.snapnr = snapnr s.name = self.name if verbose: print("\n{0}".format(s.name)) print("redshift: {0}".format(s.redshift)) print("time : {0}".format(s.time)) print("center : {0}\n".format(s.center)) return s, sf
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 eat_snap_and_fof(level, halo_number, snapnr, snappath, run=None, loadonlytype=[4], haloid=0, galradfac=0.1, remove_bulk_vel=True, rotate=True, verbose=True): """ Method to eat an Auriga snapshot, given a level/halo_number/snapnr. Subfind has been executed 'on-the-fly', during the simulation run. @param level: level of the Auriga simulation (3=high, 4='normal' or 5=low). Level 3/5 only for halo 6, 16 and 24. See Grand+ 2017 for details. Careful when level != 4 because directories may have different names. @param halo_number: which Auriga galaxy? See Grand+ 2017 for details. Should be an integer in range(1, 31) @param snapnr: which snapshot number? This is an integer, in most cases in range(1, 128) depending on the number of timesteps of the run. The last snapshot would then be 127. Snapshots are written at a certain time, but careful because the variable called time is actually the cosmological expansion factor a = 1/(1+z). For example, snapnr=127 has s.time = 1, which corresponds to a redshift of ~0. This makes sense because this is the last snapshot and the last snapshot is written at redshift zero @param snappath: full path to the level/halo directory that contains all of the simulation snapshots @param loadonlytype: which particle types should be loaded? This should be a list of integers. If I'm not mistaken, the options are: 0 (gas), 1 (dark matter), 2 (unused), 3 (tracers), 4 (stars & wind; age > 0. --> stars; age < 0. --> wind), 5 (black holes). @param haloid: the ID of the SubFind halo. In case you are interested in the main galaxy in the simulation run: set haloid to zero. This was a bit confusing to me at first because a zoom-simulation run of one Auriga galaxy is also referred to as 'halo', see halo_number. @param galradfac: the radius of the galaxy is often used to make cuts in the (star) particles. It seems that in general galrad is set to 10% of the virial radius R200 of the DM halo that the galaxy sits in. The disk does seem to 'end' at 0.1R200. @param remove_bulk_vel: boolean to subtract bulk velocity [default True] @param rotate: boolean to toggle between rotate / not rotate [default True] @param verbose: boolean to print some information @return: two-tuple (s, sf) where s is an instance of the gadget_snapshot class, and sf is an instance of the subfind class. See Arepo-snap-util, gadget_snap.py respectively gadget_subfind.py """ # Eat the subfind friend of friends output if "highfreqstars_" in str(snapnr): snapnr = int(snapnr.split("highfreqstars_")[1]) snapbase = "snapshot_highfreqstars_" snapdirbase = "snapdir_highfreqstars_" loadonlytype = [4] if not hasattr(run, "redshifts"): run.get_snapshot_spacing(verbose=verbose) if not hasattr(run, "redshifts_highfreqstars"): run.get_snapshot_spacing_highfreqstars(verbose=verbose) # Well, since we do not have sf for highfreqstars, we cheat. Find the # regular snapshot that does have subfind outputs, and then glean the # relevant information from there and sneak it in here. redshift = run.redshifts_highfreqstars[ snapnr if snapnr != 2764 else 2763] snapnr_with_sf_closest_to_snapnr_highfreqstars = ( numpy.abs(run.redshifts - redshift)).argmin() print("{0} / {1} --> {2:.6f}".format(snapnr, run.nhighfreqstars - 1, redshift)) s, sf = run.load_header(verbose=verbose, redshift=float(redshift)) sf.snapnr = snapnr_with_sf_closest_to_snapnr_highfreqstars print(" --> {0} / {1} --> {2:.6f}".format(s.snapnr, run.nsnaps - 1, s.redshift)) else: from areposnap.gadget_subfind import load_subfind sf = load_subfind(snapnr, dir=snappath) sf.snapnr = snapnr snapbase = "snapshot_" snapdirbase = "snapdir_" # Eat the Gadget snapshot from areposnap.gadget import gadget_readsnap s = gadget_readsnap(snapnr, snappath=snappath, snapbase=snapbase, snapdirbase=snapdirbase, lazy_load=True, subfind=sf, loadonlytype=loadonlytype) if "highfreqstars_" not in str(snapnr): sf.redshift = s.redshift s.subfind = sf if sf is None: # for highfreqstars has_sf_indizes = False else: try: # Sets s.(sub)halo. This allows selecting the halo, e.g. 0 (main 'Galaxy') s.calc_sf_indizes(s.subfind) has_sf_indizes = True except KeyError as e: # for example, Au5-24: snapnr 0-3 has empty sf.data; snapnr 4-6 has no stars and no cold-gas spin print("WARNING: KeyError encountered in s.calc_sf_indizes") if str(e) == "'flty'": print( "WARNING: KeyError arised because 'flty' was not found in sf.data" ) # print(" sf.data.keys(): {0}".format(sf.data.keys())) # print(" s.data.keys(): {0}".format(s.data.keys())) has_sf_indizes = False else: raise # for example, Au5-24: snapnr 7-14 breaks due to lack of stars s.galrad = None if has_sf_indizes: # Note that selecting the halo now rotates the disk using the principal axis. # rotate_disk is a general switch which has to be set to True to rotate. # To then actually do the rotation, do_rotation has to be True as well. # Within rotate_disk there are three methods to handle the rotation. Choose # one of them, but see the select_halo method for details. try: matrix = s.select_halo(s.subfind, haloid=haloid, galradfac=galradfac, rotate_disk=True, use_principal_axis=True, euler_rotation=False, use_cold_gas_spin=False, do_rotation=rotate, remove_bulk_vel=remove_bulk_vel, verbose=verbose) s.rotmat = matrix.transpose() # To use: value_rotated = numpy.dot(value, s.rotmat) except KeyError as e: # for example, Au5-24: snapnr 0-3 has empty sf.data; snapnr 4-6 has no stars and no cold-gas spin print("WARNING: KeyError encountered in s.select_halo") print(str(e)) if str(e) == "'svel'": print( "WARNING: KeyError arised because 'svel' was not found in s.data" ) elif str(e) == "'pos'": print("WARNING: this particular snapshot has no positions.") else: raise except IndexError as e: # for example, Au5-24: snapnr 0-3 has empty sf.data; snapnr 4-6 has no stars and no cold-gas spin print("WARNING: IndexError encountered in s.select_halo") if str(e) == "index 0 is out of bounds for axis 0 with size 0": print( "WARNING: IndexError arised possibly in get_principal_axis because there are no stars (yet)" ) else: raise # This means that galrad is 10 % of R200 (200*rho_crit definition) # frc2 = Group_R_Crit200 s.galrad = numpy.maximum(galradfac * sf.data['frc2'][haloid], 0.005) # I find it somewhat annoying that age has different shape than other properties... # So let's just force age to be of same shape.. by shoving a bunch of zeros in-between # I mean, memory is cheap anyway right? if "age" in s.data.keys(): age = numpy.zeros(s.npartall) st = s.nparticlesall[:4].sum() en = st + s.nparticlesall[4] age[st:en] = s.age s.data['age'] = age del age if "gmet" in s.data.keys(): # Clean negative and zero values of gmet to avoid RuntimeErrors s.gmet = numpy.maximum(s.gmet, 1e-40) # Sneak some more info into the s instance s.halo_number = halo_number s.level = level s.snapnr = snapnr s.haloid = haloid s.name = "Au{0}-{1}".format(s.level, s.halo_number) if verbose: print("\n{0}".format(s.name)) print("galrad : {0}".format(s.galrad)) print("redshift: {0}".format(s.redshift)) print("time : {0}".format(s.time)) print("center : {0}\n".format(s.center)) return s, sf