def _load_gas_data(self): """If gas is present loads gas SFR/Metallicity/Temperatures.""" if self.obj.simulation.ngas == 0: return sfr_unit = '%s/%s' % (self.obj.units['mass'], self.obj.units['time']) dustmass_unit = '%s' % (self.obj.units['mass']) sfr = self.obj.yt_dataset.arr(np.zeros(self.obj.simulation.ngas), sfr_unit) gZ = self.obj.yt_dataset.arr(np.zeros(self.obj.simulation.ngas), '') gT = self.obj.yt_dataset.arr(np.zeros(self.obj.simulation.ngas), self.obj.units['temperature']) dustmass = self.obj.yt_dataset.arr(np.zeros(self.obj.simulation.ngas),'') #dustmass = self.obj.yt_dataset.arr(np.zeros(self.obj.simulation.ngas), '')#dustmass_unit) if has_property(self.obj, 'gas', 'sfr'): sfr = get_property(self.obj, 'sfr', 'gas').to(sfr_unit) if has_property(self.obj, 'gas', 'metallicity'): gZ = get_property(self.obj, 'metallicity', 'gas') if has_property(self.obj, 'gas', 'temperature'): gT = get_property(self.obj, 'temperature', 'gas').to(self.obj.units['temperature']) if has_property(self.obj, 'gas', 'dustmass'): dustmass = get_property(self.obj,'dustmass','gas') #dustmass = get_property(self.obj,'dustmass','gas'))#.to(dustmass_unit) self.gsfr = sfr self.gZ = gZ self.gT = gT self.dustmass = self.obj.yt_dataset.arr(dustmass,'code_mass').in_units('Msun')
def _photometry_init(self): """Collect particle information for photometry""" from caesar.property_manager import get_property, ptype_ints memlog('Loading gas and star particles for photometry') self._determine_ptypes() self.pos = np.empty((0, 3), dtype=MY_DTYPE) self.vel = np.empty((0, 3), dtype=MY_DTYPE) self.mass = np.empty(0, dtype=MY_DTYPE) self.ptype = np.empty(0, dtype=np.int32) for ip, p in enumerate(['gas', 'star']): data = get_property(self.obj, 'pos', p).to(self.obj.units['length']) self.pos = np.append(self.pos, data.d, axis=0) data = get_property(self.obj, 'vel', p).to(self.obj.units['velocity']) self.vel = np.append(self.vel, data.d, axis=0) data = get_property(self.obj, 'mass', p).to(self.obj.units['mass']) self.mass = np.append(self.mass, data.d, axis=0) self.ptype = np.append(self.ptype, np.full(len(data), ptype_ints[p], dtype=np.int32), axis=0) self._assign_local_lists() self._assign_particle_counts() memlog('Loaded particle data') self._load_gas_data() self._load_star_data() memlog('Loaded gas and star data')
def _load_bh_data(self, select='all'): """If blackholes are present, loads BH_Mdot""" if select is 'all': flag = [True]*self.obj.simulation.nbh else: flag = (select>=0) if has_property(self.obj, 'bh', 'bhmass'): self.bhmass = self.obj.yt_dataset.arr(get_property(self.obj, 'bhmass', 'bh').d[flag]*1e10, 'Msun/h').to(self.obj.units['mass']) # I don't know how to convert this automatically self.use_bhmass = True else: mylog.warning('No black holes found') self.use_bhmass = False if has_property(self.obj, 'bh', 'bhmdot') and self.use_bhmass: #units mutlitplied by ((All.UnitMass_in_g / SOLAR_MASS) / (All.UnitTime_in_s / SEC_PER_YEAR)) bhmdot_unit = '10.22465727143273*Msun/h/yr' #bhmdot_unit = '15.036260693283424*Msun/yr' #bhmdot_unit = '%s/%s' %(self.obj.units['mass'], self.obj.units['time']) bhmdot = get_property(self.obj, 'bhmdot', 'bh').d[flag] #of course it is dimentionless bhmdot = self.obj.yt_dataset.arr(bhmdot, bhmdot_unit).to('%s/%s' %(self.obj.units['mass'], self.obj.units['time'])) self.bhmdot = bhmdot #mylog.info('BH_Mdot available, units=%s'%bhmdot_unit) else: if self.use_bhmass: mylog.warning('Black holes are there, but BH_Mdot not available!')
def _load_star_data(self, select='all'): """If star is present load Metallicity if present""" if self.obj.simulation.nstar == 0: return if select is 'all': flag = [True]*self.obj.simulation.nstar else: flag = (select>=0) if has_property(self.obj, 'star', 'metallicity'): self.sZ = get_property(self.obj, 'metallicity', 'star')[flag] elif has_property(self.obj, 'star', 'met_tng'): # try Illustris/TNG alias self.sZ = get_property(self.obj, 'met_tng', 'star')[flag] #self.sZ = np.sum(self.sZ.T[2:],axis=0) # first two are H,He; the rest sum to give metallicity #self.sZ[self.sZ<0] = 0. # some (very small) negative values, set to 0 else: mylog.warning('Metallicity not found: setting all stars to solar=0.0134') self.sZ = 0.0134*np.ones(self.obj.simulation.nstar,dtype=MY_DTYPE) ds = self.obj.yt_dataset if has_property(self.obj, 'star', 'aform'): self.age = get_property(self.obj, 'aform', 'star')[flag] # a_exp at time of formation elif has_property(self.obj, 'star', 'aform_tng'): # try Illustris/TNG alias self.age = get_property(self.obj, 'aform_tng', 'star')[flag] self.age = abs(self.age) # some negative values here too; not sure what to do? else: self.age = np.zeros(self.obj.simulation.nstar,dtype=MY_DTYPE) mylog.warning('Stellar age not found -- photometry will be incorrect!') if ds.cosmological_simulation: from yt.utilities.cosmology import Cosmology co = Cosmology(hubble_constant=ds.hubble_constant, omega_matter=ds.omega_matter, omega_lambda=ds.omega_lambda) self.age = (ds.current_time - co.t_from_z(1./self.age-1.)).in_units('Gyr').astype(MY_DTYPE) # age at time of snapshot
def _load_star_data(self): """If star is present load Metallicity if present""" if self.obj.simulation.nstar == 0: return if has_property(self.obj, 'star', 'metallicity'): self.sZ = get_property(self.obj, 'metallicity', 'star')
def reset_global_particle_IDs(obj): ''' Maps particle lists from currently loaded ID's to the ID's corresponding to the full snapshot ''' # determine full particle numbers in snapshot from caesar.property_manager import has_ptype, get_property offset = np.zeros(len(obj.data_manager.ptypes) + 1, dtype=np.int64) for ip, p in enumerate(obj.data_manager.ptypes): if not has_ptype(obj, p): continue count = len(get_property(obj, 'mass', p)) if p == 'gas': offset[ip + 1] = offset[ip] + obj.simulation.ngas obj.simulation.ngas = count elif p == 'star': offset[ip + 1] = offset[ip] + obj.simulation.nstar obj.simulation.nstar = count elif p == 'bh': offset[ip + 1] = offset[ip] + obj.simulation.nbh obj.simulation.nbh = count elif p == 'dust': offset[ip + 1] = offset[ip] + obj.simulation.ndust obj.simulation.ndust = count elif p == 'dm': offset[ip + 1] = offset[ip] + obj.simulation.ndm obj.simulation.ndm = count elif p == 'dm2': offset[ip + 1] = offset[ip] + obj.simulation.ndm2 obj.simulation.ndm2 = count elif p == 'dm3': offset[ip + 1] = offset[ip] + obj.simulation.ndm3 obj.simulation.ndm3 = count # reset lists for group_type in obj.group_types: group_list = 'obj.%s_list' % group_type for ip, p in enumerate(obj.data_manager.ptypes): if not has_ptype(obj, p): continue for group in eval(group_list): part_list = 'group.%s' % plist_dict[p] mylist = eval(part_list) mylist = obj.data_manager.indexes[mylist + offset[ip]] if p == 'gas': group.glist = mylist if p == 'star': group.slist = mylist if p == 'bh': group.bhlist = mylist if p == 'dust': group.dlist = mylist if p == 'dm': group.dmlist = mylist if p == 'dm2': group.dm2list = mylist if p == 'dm3': group.dm3list = mylist return
def _load_bh_data(self): """If blackholes are present, loads BH_Mdot""" from yt.funcs import mylog if has_property(self.obj, 'bh', 'bhmass'): self.bhmass = self.obj.yt_dataset.arr(get_property(self.obj, 'bhmass', 'bh').d*1e10, 'Msun/h').to(self.obj.units['mass'])#I don't know how to convert this automatically self.use_bhmass = True mylog.info('BH_Mass available, units=1e10 Msun/h') mylog.info('Using BH_Mass instead of BH particle masses') else: mylog.info('Using BH particle mass') if has_property(self.obj, 'bh', 'bhmdot'): #units mutlitplied by ((All.UnitMass_in_g / SOLAR_MASS) / (All.UnitTime_in_s / SEC_PER_YEAR)) bhmdot_unit = '10.22465727143273*Msun/h/yr' #bhmdot_unit = '15.036260693283424*Msun/yr' #bhmdot_unit = '%s/%s' %(self.obj.units['mass'], self.obj.units['time']) bhmdot = get_property(self.obj, 'bhmdot', 'bh').d #of course it is dimentionless bhmdot = self.obj.yt_dataset.arr(bhmdot, bhmdot_unit).to('%s/%s' %(self.obj.units['mass'], self.obj.units['time'])) self.bhmdot = bhmdot mylog.info('BH_Mdot available, units=%s'%bhmdot_unit) else: mylog.warning('BH_Mdot not available')
def get_mean_interparticle_separation(obj): """Calculate the mean interparticle separation and Omega Baryon. Parameters ---------- obj : :class:`main.CAESAR` Main caesar object. Returns ------- mips : float Mean inter-particle separation used for calculating FOF's b parameter. """ if hasattr(obj.simulation, 'mean_interparticle_separation'): return obj.simulation.mean_interparticle_separation if obj.yt_dataset.cosmological_simulation == 0: mylog.info( 'Non-cosmological data set detected -- setting units as specified in fubar.py' ) UT = obj.yt_dataset.current_time.to('s/h') UL = obj.yt_dataset.length_unit.to('cm/h') GRAV = obj.yt_dataset.quan(6.672e-8, 'cm**3/(g*s**2)') else: UT = obj.yt_dataset.time_unit.to('s/h') / obj.yt_dataset.scale_factor UL = obj.yt_dataset.length_unit.to('cmcm/h') GRAV = obj.yt_dataset.quan(6.672e-8, 'cmcm**3/(g*s**2)') UM = obj.yt_dataset.mass_unit.to('g/h') G = GRAV / UL**3 * UM * UT**2 ## to system units Hubble = obj.yt_dataset.quan(3.2407789e-18, 'h/s') * UT dmmass = get_property(obj, 'mass', 'dm').to('code_mass') ndm = len(dmmass) dmmass = np.sum(dmmass) # Only need this when the second family (not low res one!) of dark matter particles is presented. # if 'dm2' in obj.data_manager.ptypes: # dmmass2 = get_property(obj, 'mass', 'dm2').to('code_mass') # ndm += len(dmmass2) # dmmass += np.sum(dmmass2) gmass = obj.yt_dataset.arr(np.array([0.0]), 'code_mass') smass = obj.yt_dataset.arr(np.array([0.0]), 'code_mass') bhmass = obj.yt_dataset.arr(np.array([0.0]), 'code_mass') dustmass = obj.yt_dataset.arr(np.array([0.0]), 'code_mass') from caesar.property_manager import has_ptype if has_ptype(obj, 'gas'): gmass = get_property(obj, 'mass', 'gas').to('code_mass') if has_ptype(obj, 'star'): smass = get_property(obj, 'mass', 'star').to('code_mass') if obj.data_manager.blackholes and has_ptype(obj, 'bh'): bhmass = get_property(obj, 'mass', 'bh').to('code_mass') if obj.data_manager.dust and has_ptype(obj, 'dust'): dustmass = get_property(obj, 'mass', 'dust').to('code_mass') bmass = np.sum(gmass) + np.sum(smass) + np.sum(bhmass) + np.sum(dustmass) """ DM = obj.data_manager dmmass = DM.mass[DM.dmlist] gmass = DM.mass[DM.glist] smass = DM.mass[DM.slist] bhmass = DM.mass[DM.bhlist] ndm = len(dmmass) dmmass = obj.yt_dataset.quan(np.sum(dmmass), obj.units['mass']).to('code_mass') bmass = obj.yt_dataset.quan(np.sum(gmass) + np.sum(smass) + np.sum(bhmass), obj.units['mass']).to('code_mass') """ #if its an idealized simulation, then there's no cosmology and we just take z=0 Planck15 values if obj.yt_dataset.cosmological_simulation == 0: from astropy.cosmology import Planck15 Om = Planck15.Om0 Ob = Planck15.Ob0 else: Om = obj.yt_dataset.cosmology.omega_matter Ob = (bmass / (bmass + dmmass) * Om).d rhodm = ((Om - Ob) * 3.0 * Hubble**2 / (8.0 * np.pi * G)).d rhodm = obj.yt_dataset.quan(rhodm, 'code_mass/code_length**3') mips = ((dmmass / ndm / rhodm)**(1. / 3.)).to(obj.units['length']) efres = int(obj.simulation.boxsize.d / mips.d) obj.simulation.omega_baryon = float(Ob) obj.simulation.effective_resolution = efres obj.simulation.mean_interparticle_separation = mips mylog.info('Calculated Omega_Baryon=%g and %d^3 effective resolution' % (Ob, efres)) return obj.simulation.mean_interparticle_separation
def _load_gas_data(self, select='all'): """If gas is present loads gas SFR, metallicities, temperatures, nH. If select is not 'all', return all particles with select>=0 """ if self.obj.simulation.ngas == 0: return sfr_unit = '%s/%s' % (self.obj.units['mass'], self.obj.units['time']) dustmass_unit = '%s' % (self.obj.units['mass']) gnh_unit = '1/%s**3' % (self.obj.units['length']) sfr = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), sfr_unit) gZ = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), '') gT = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), self.obj.units['temperature']) gnh = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), gnh_unit) dustmass = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), '') gfHI = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), '') gfH2 = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), '') ghsml = self.obj.yt_dataset.arr( np.zeros(self.obj.simulation.ngas, dtype=MY_DTYPE), self.obj.units['length']) #dustmass = self.obj.yt_dataset.arr(np.zeros(self.obj.simulation.ngas), '')#dustmass_unit) if isinstance(select, str) and select == 'all': flag = [True] * self.obj.simulation.ngas else: flag = (select >= 0) if has_property(self.obj, 'gas', 'sfr'): sfr = get_property(self.obj, 'sfr', 'gas')[flag].to(sfr_unit) if has_property(self.obj, 'gas', 'metallicity'): gZ = get_property(self.obj, 'metallicity', 'gas')[flag] elif has_property(self.obj, 'gas', 'met_tng'): gZ = get_property(self.obj, 'met_tng', 'gas')[flag] # for Illustris, array of mets else: mylog.warning( 'Metallicity not found: setting all gas to solar=0.0134') gZ = 0.0134 * np.ones(self.obj.simulation.nstar, dtype=MY_DTYPE) if has_property(self.obj, 'gas', 'nh'): gfHI = get_property(self.obj, 'nh', 'gas')[flag] else: mylog.warning( 'HI fractions not found in snapshot, will compute later') if has_property(self.obj, 'gas', 'fh2'): gfH2 = get_property(self.obj, 'fh2', 'gas')[flag] else: mylog.warning( 'H2 fractions not found in snapshot, will compute later') if has_property(self.obj, 'gas', 'temperature'): gT = get_property(self.obj, 'temperature', 'gas')[flag].to(self.obj.units['temperature']) if has_property(self.obj, 'gas', 'hsml'): ghsml = get_property(self.obj, 'hsml', 'gas')[flag].to(self.obj.units['length']) if has_property(self.obj, 'gas', 'rho'): from astropy import constants as const from yt import YTQuantity redshift = self.obj.simulation.redshift m_p = YTQuantity.from_astropy(const.m_p) gnh = get_property(self.obj, 'rho', 'gas')[flag].in_cgs() * 0.76 / m_p.in_cgs() if has_property(self.obj, 'gas', 'dustmass'): dustmass = get_property(self.obj, 'dustmass', 'gas')[flag] else: mylog.warning('Dust masses not found in snapshot') self.gsfr = sfr self.gZ = gZ self.gT = gT self.gnh = gnh self.gfHI = gfHI self.gfH2 = gfH2 self.hsml = ghsml self.dustmass = self.obj.yt_dataset.arr(dustmass, 'code_mass').in_units('Msun') self.dustmass.dtype = MY_DTYPE
def get_IC_pos(group, ic_ds, radius_type, search_factor=2.5, return_mask=False): """Get the initial dark matter positions of a ``CAESAR`` halo. If called on a galaxy, it will return the IC DM positions of the parent halo. Parameters ---------- group : :class:`group.Group` Group we are querying. ic_ds : yt dataset The initial condition dataset via ``yt.load()`` search_factor : float, optional How far from the center to select DM particles (defaults to 2.5). return_mask : bool, optional Return initial condition positions from 0-->1 rather than raw data. Useful for writing a MUSIC mask file. Returns ------- ic_dmpos : np.ndarray DM positions of this object in the initial condition file. """ from caesar.property_manager import ptype_aliases, get_property, DatasetType from caesar.periodic_kdtree import PeriodicCKDTree ic_ds_type = ic_ds.__class__.__name__ if ic_ds_type not in ptype_aliases: raise NotImplementedError('%s not yet supported' % ic_ds_type) if group.obj.yt_dataset.domain_width[0].d != ic_ds.domain_width[0].d: raise Exception( 'IC and SNAP boxes do not match! (%f vs %f)' % (ic_ds.domain_width[0].d, group.obj.yt_dataset.domain_width[0].d)) if str(ic_ds.length_unit) != str(group.obj.yt_dataset.length_unit): raise Exception('LENGTH UNIT MISMATCH! '\ 'This may arise from loading the snap/IC '\ 'incorrectly and WILL cause problems with '\ 'the matching process. (%s vs %s)' % (str(ic_ds.length_unit), str(group.obj.yt_dataset.length_unit))) if group.obj_type == 'halo': obj = group elif group.obj_type == 'galaxy': if group.halo is None: mylog.warning('Galaxy %d has no halo!' % group.GroupID) return obj = group.halo search_params = dict( pos=obj.pos.in_units('code_length').d, r=obj.radii[radius_type].in_units('code_length').d * search_factor, ) box = ic_ds.domain_width[0].d bounds = np.array([box, box, box]) dmpids = get_property(obj.obj, 'pid', 'dm').d dmpos = get_property(obj.obj, 'pos', 'dm').d dm_TREE = PeriodicCKDTree(bounds, dmpos) valid = dm_TREE.query_ball_point(search_params['pos'], search_params['r']) search_params['ids'] = dmpids[valid] ic_ds_type = DatasetType(ic_ds) ic_dmpos = ic_ds_type.get_property('dm', 'pos').d ic_dmpids = ic_ds_type.get_property('dm', 'pid').d matches = np.in1d(ic_dmpids, search_params['ids'], assume_unique=True) nmatches = len(np.where(matches)[0]) nvalid = len(valid) if nmatches != nvalid: raise Exception('Could not match all particles! '\ 'Only %0.2f%% particles matched.' % (float(nmatches)/float(nvalid) * 100.0)) mylog.info('MATCHED %d particles from %s %d in %s' % (nmatches, obj.obj_type, obj.GroupID, ic_ds.basename)) mylog.info('Returning %0.2f%% of the total DM from the sim' % (float(nmatches) / float(len(ic_dmpids)) * 100.0)) matched_pos = ic_dmpos[matches] if return_mask: matched_pos /= box return matched_pos