Esempio n. 1
0
	def integrate_sub_hf(self,sub_id,num_t_step=int(1e4),dt=None):
		""" Integrate the path of a subhalo assuming an NFW potential for the
		main host and accounting for the hubble flow.

		Args:
			sub_id (int): The id of the subhalo to integrate forward in the
				potential.
			num_t_step (int): The number of integration steps to use between
				redshift of accretion and redshift 0.
			dt (float): The timestep to use in the integration. This will
				overwrite num_t_step.

		Returns:
			((np.array,np.array)): A tuple containing two numpy arrays, the
				first with the position vector at each time step and the
				second with the velocity vector at each time step.

		Notes:
			Integration begins at the first snapshot where the subhalo is
			within the virial radius of the host.
		"""

		self.load_subhalo(sub_id,num_t_step,dt)

		# For simplicity, ignore subhalos that appear before the host or do not
		# survive until redshift 0.
		if (np.max(self.sub_snaps) < np.max(self.host_snaps) or
			np.min(self.sub_snaps) < np.min(self.host_snaps) or
			len(self.sub_snaps)<2):
			return None,None

		# Set up that arrays that will contain the integration outputs
		save_pos_array = np.zeros((self._num_t_step+1,3))
		save_vel_array = np.zeros((self._num_t_step+1,3))

		# Set up the array of hubble flow values at each integration time
		hf_int =  conversion.convert_units_kms(self.cosmo.Hz(
			1/self.scales_int-1))/conversion.convert_unit_Mpc(1)

		# Integrate the subhalo. The save_pos_array/save_vel_array are modified
		# in place.
		integrator.leapfrog_int_nfw_hf(self.sub_pos_int[self.int_start],
			self.sub_vel_int[self.int_start],self.rho_0_array,
			self.r_scale_array,self.pos_nfw_array,hf_int,self.dt,save_pos_array,
			save_vel_array,box_length_array=self.box_length_array)

		# Transform back into comoving Mpc/h units and km/s.
		save_pos_comv = (save_pos_array[:-1].T * self.cosmo.h /
			self.scales_int*0.3).T
		save_vel_comv = save_vel_array[:-1]*400

		return save_pos_comv, save_vel_comv
Esempio n. 2
0
	def test_leapfrog_int_nfw_hf(self):
		# Compare the results of our code to a reworking of the universe machine
		# code. This ensures consistency when we present universe machine
		# equivalent results.

		# First set the time range for our integration
		dt = 0.00001
		dt_um = dt/conversion.convert_unit_gigayear(1)*1e3
		num_dt = int(3e4)

		# We want the time in units of Myr.
		times = (np.linspace(0,dt*num_dt,num_dt)[::-1]/
			conversion.convert_unit_gigayear(1)*1e3)
		cosmo = cosmology.setCosmology('bolshoi')
		scale_factor = 1/(1+cosmo.lookbackTime(times/1e3,inverse=True))

		# Some of the fundamental units being used by UM
		vel_dt = dt_um * 1.02268944e-6 * cosmo.h / scale_factor  # Mpc/Myr/h
		H = cosmo.Hz(cosmo.lookbackTime(times/1e3,inverse=True))  # km/s/Mpc
		h_drag = -H*1.02269032e-6
		# h_drag = -2*H*scale_factor*1.02269032e-6
		acc_dt2 = dt_um**2/2 * 1.02268944e-6 * cosmo.h / scale_factor
		conv_const = scale_factor**2 / cosmo.h**2
		acc = np.zeros(3)
		Gc = 4.39877036e-15  # In Mpc^2 / Myr / Msun * km/s

		# Some units we need for avocet
		hf_int =  (conversion.convert_units_kms(cosmo.Hz(1/scale_factor-1))/
			conversion.convert_unit_Mpc(1))

		# Now we have to define the mass and nfw position in our units and
		# UM units.
		pos_nfw_array = np.zeros((num_dt,3))  # 300 kpc
		pos_nfw_array_um = np.zeros((num_dt,3))  # comoving Mpc/h

		rho_0_array = np.ones(num_dt)  # 1e13 M_Sun / (300 kpc)^3
		rho_0_array_um = (rho_0_array/conversion.convert_unit_M_sun(1)*
			conversion.convert_unit_Mpc(1)**3/cosmo.h**3)  # M_sun / (Mpc/h)^3
		# Convert rho_0_array_um to comoving
		rho_0_array_um = (rho_0_array_um.T * scale_factor**3).T

		r_scale_array = np.ones(num_dt)  # 300 kpc
		r_scale_array_um = (r_scale_array.T/conversion.convert_unit_Mpc(1)*
			cosmo.h/scale_factor).T  # comoving Mpc/h

		# We'll save our results here
		save_pos = np.zeros((num_dt+1,3))
		save_vel = np.zeros((num_dt+1,3))
		save_pos_um = np.zeros((num_dt+1,3))
		save_vel_um = np.zeros((num_dt+1,3))

		# The initial position and velocity
		pos_init = np.array([1,0,0],dtype=np.float)  # 300 kpc
		vel_init = np.array([0.001,1,0],dtype=np.float)  # 400 km/s
		pos_um = (pos_init/conversion.convert_unit_Mpc(1)*
			cosmo.h/scale_factor[0])  # comoving Mpc/h
		vel_um = vel_init/conversion.convert_units_kms(1)

		# Universe machine integration
		save_pos_um[0] += pos_um
		save_vel_um[0] += vel_um
		for ti in range(num_dt):

			# If we're not at the first step
			vel_um += acc*dt_um*0.5

			dr = pos_nfw_array_um[ti]-pos_um
			r = np.sqrt(np.sum(np.square(dr)))
			r3 = r**3 * conv_const[ti]
			rs = r_scale_array_um[ti]
			m_um = 4 * np.pi * rho_0_array_um[ti]*rs**3
			m_um *= np.log(1+r/rs)+1/(1+r/rs)-1
			accel = Gc*m_um/r3

			acc = accel*dr + h_drag[ti]*vel_um

			vel_um += acc*dt_um*0.5

			pos_um += vel_um*vel_dt[ti] + acc*acc_dt2[ti]

			save_pos_um[ti+1] += pos_um
			save_vel_um[ti+1] += vel_um

		# Do the same integration in avocet
		integrator.leapfrog_int_nfw_hf(pos_init,vel_init,rho_0_array,
			r_scale_array,pos_nfw_array,hf_int,dt,save_pos,save_vel)

		# Convert save_pos into comoving units
		save_pos = (save_pos[:-1].T/conversion.convert_unit_Mpc(1)*cosmo.h/
			scale_factor).T
		save_vel = (save_vel[:-1].T/conversion.convert_units_kms(1)).T

		np.testing.assert_almost_equal((save_pos+1e-12)/(save_pos_um[:-1]+1e-12),
			np.ones(save_pos.shape),decimal=2)
		# This weird check is to deal with the fact that the z axis is 0 and
		# that for very small velocities the differences in the code are more
		# noticable (although clearly not relevant given the position match.)
		np.testing.assert_almost_equal((save_vel[300:]+1e-12)/(
			save_vel_um[300:-1]+1e-12),np.ones(save_vel[300:].shape),decimal=2)

		# As a final test of the code consistency, pass no growth to our code
		# and make sure it yields the same results as the code without the
		# hubble flow.
		pos_init = np.array([1,0,0],dtype=np.float)  # 300 kpc
		vel_init = np.array([0.001,1,0],dtype=np.float)  # 400 km/s
		save_pos = np.zeros((num_dt+1,3))
		save_vel = np.zeros((num_dt+1,3))
		box_length_array = np.ones(num_dt)*2
		force_softening = np.ones(num_dt)*1e-3/conversion.convert_unit_Mpc(1)
		hf_int *= 0
		integrator.leapfrog_int_nfw_hf(pos_init,vel_init,rho_0_array,
			r_scale_array,pos_nfw_array,hf_int,dt,save_pos,save_vel,
			force_softening=force_softening,
			box_length_array=box_length_array)

		pos_init = np.array([1,0,0],dtype=np.float)  # 300 kpc
		vel_init = np.array([0.001,1,0],dtype=np.float)  # 400 km/s
		save_pos_nhf = np.zeros((num_dt+1,3))
		save_vel_nhf = np.zeros((num_dt+1,3))
		integrator.leapfrog_int_nfw(pos_init,vel_init,rho_0_array,
			r_scale_array,pos_nfw_array,dt,save_pos_nhf,save_vel_nhf,
			force_softening=force_softening,
			box_length_array=box_length_array)

		np.testing.assert_almost_equal(save_pos,save_pos_nhf)
		np.testing.assert_almost_equal(save_vel,save_vel_nhf)
Esempio n. 3
0
	def __init__(self,trj_host,cosmo,use_um=False):

		# Store the boolean on universe machine
		self.use_um = use_um

		# Store the trajectory and cosmology objects
		self.trj_host = trj_host
		self.cosmo = cosmo

		# Grab the host
		self.host = trj_host.get_host()

		# Grab the snapshots where the host is identified
		self.host_snaps = self.host['snap'][self.host['mvir']>0]

		# Get the the host redshifts and corresponding times.
		self.host_scales = trj_host.scale[self.host_snaps]
		zs = 1/self.host_scales-1
		# Convert from Gyr to 2.31425819e16 seconds. See note at top of file.
		self.host_times = conversion.convert_unit_gigayear(
			cosmo.lookbackTime(zs))

		# Extract all of the host information for all of the snapshots.
		self.host_pos = self.host['x'][self.host_snaps]  # comoving Mpc/h
		self.host_mass = self.host['mvir'][self.host_snaps]  # Msun/h
		self.host_vmax = self.host['vmax'][self.host_snaps]  # km/s
		self.host_vel = self.host['v'][self.host_snaps]  # km/s
		self.host_r_s_rockstar = (self.host['rs'][self.host_snaps]/1e3*
			self.host_scales)  # Mpc / h

		# Now calculate the NFW amplitude, scale factor, and concentration for
		# the host.
		self.host_rho = np.zeros(self.host_mass.shape)  # M_sun / kpc^3 * h^2
		self.host_r_s = np.zeros(self.host_mass.shape)  # Mpc / h
		self.host_c = np.zeros(self.host_mass.shape)
		self.host_r_vir = np.zeros(self.host_mass.shape)  # Mpc / h

		# Populate the array of NFW parameters.
		for i in range(len(self.host_mass)):
			if use_um:
				self.host_r_s[i] = self.host_r_s_rockstar[i]
				c, rho = self._convert_m_r_s(self.host_mass[i],
					self.host_r_s[i],zs[i])
				self.host_c[i] = c
				self.host_rho[i] = rho
			else:
				c, rho, r_s, v_vir, r_vir = self._convert_m_vmax(
					self.host_mass[i],self.host_vmax[i],zs[i])
				self.host_c[i] = c
				self.host_rho[i] = rho
				self.host_r_s[i] = r_s

		# Calculate the virial radius
		self.host_r_vir = self.host_r_s*self.host_c  # Mpc/h

		# Convert to the units of our integration code.
		self.host_rho_int = conversion.convert_units_density(
			self.host_rho*cosmo.h**2)
		self.host_r_s_int = conversion.convert_unit_Mpc(
			self.host_r_s/cosmo.h)
		self.host_pos_int = conversion.convert_unit_Mpc(
			(self.host_pos.T / cosmo.h *self.host_scales).T)
Esempio n. 4
0
	def integrate_sub_rf(self,sub_id,num_t_step=int(1e4),dt=None):
		""" Integrate the path of a subhalo assuming an NFW potential for the
		main host and integrating in the host's frame of reference.

		Args:
			sub_id (int): The id of the subhalo to integrate forward in the
				potential.
			num_t_step (int): The number of integration steps to use between
				redshift of accretion and redshift 0.
			dt (float): The timestep to use in the integration. This will
				overwrite num_t_step.

		Returns:
			((np.array,np.array)): A tuple containing two numpy arrays, the
				first with the position vector at each time step and the
				second with the velocity vector at each time step.

		Notes:
			Integration begins at the first snapshot where the subhalo is
			within the virial radius of the host.
		"""

		self.load_subhalo(sub_id,num_t_step,dt)

		# For simplicity, ignore subhalos that appear before the host or do not
		# survive until redshift 0.
		if (np.max(self.sub_snaps) < np.max(self.host_snaps) or
			np.min(self.sub_snaps) < np.min(self.host_snaps) or
			len(self.sub_snaps)<2):
			return None,None

		# Set up that arrays that will contain the integration outputs
		save_pos_array = np.zeros((self._num_t_step+1,3))
		save_vel_array = np.zeros((self._num_t_step+1,3))

		# We need slightly different integration variables
		self.sub_pos_int = conversion.convert_unit_Mpc(((self.sub_pos.T -
			self.host_pos[self.host_sub_ind].T)/ self.cosmo.h *
			self.sub_scales).T)
		self.sub_vel_int = conversion.convert_units_kms(self.sub_vel -
			self.host_vel[self.host_sub_ind])

		# Interpolate the subhalo properties for integation
		self.pos_nfw_array = np.zeros((self._num_t_step,3))  # Keep this at 0.

		# Integrate the subhalo. The save_pos_array/save_vel_array are modified
		# in place.
		integrator.leapfrog_int_nfw(self.sub_pos_int[self.int_start],
			self.sub_vel_int[self.int_start],self.rho_0_array,
			self.r_scale_array,self.pos_nfw_array,self.dt,save_pos_array,
			save_vel_array,box_length_array=None)

		# Transform back into comoving Mpc/h units
		save_pos_comv = (save_pos_array[:-1].T * self.cosmo.h /
			self.scales_int*0.3).T
		for i in range(3):
			save_pos_comv[:,i] += interp1d(self.host_times,
				self.host_pos[:,i],kind='cubic')(self.times_int)
		save_vel_comv = save_vel_array[:-1]*400
		for i in range(3):
			save_vel_comv[:,i] += interp1d(self.host_times,
				self.host_vel[:,i],kind='cubic')(self.times_int)

		return save_pos_comv, save_vel_comv
Esempio n. 5
0
	def load_subhalo(self,sub_id,num_t_step,dt=None):
		""" Load the subhalo properties for the given sub_id

		Args:
			sub_id (int): The id of the subhalo to integrate forward in the
				potential.
			num_t_step (int): The number of integration steps to use between
				redshift of accretion and redshift 0.
			dt (float): The timestep to use in the integration. This will
				overwrite num_t_step.
		"""

		# Get the subhalo we want to integrate.
		self.sub_halo = self.trj_host.get_halo(sub_id)

		# Subhalos go from smallest to largest snapshot so reverse the order to
		# agree with other conventions.
		self.sub_snaps = self.sub_halo['snap'][::-1]

		# For simplicity, ignore subhalos that appear before the host or do not
		# survive until redshift 0.
		if (np.max(self.sub_snaps) < np.max(self.host_snaps) or
			np.min(self.sub_snaps) < np.min(self.host_snaps)):
			return None,None

		# Pull out the subhalo information from the trajectory file.
		self.sub_scales = self.trj_host.scale[self.sub_snaps]
		self.sub_pos = self.sub_halo['x'][::-1]  # comoving Mpc/h
		self.sub_dx = self.sub_halo['dx'][::-1]  # comoving Mpc/h
		# Physical Mpc/h
		self.sub_dx_physical = (self.sub_scales * self.sub_dx.T).T
		self.sub_vel = self.sub_halo['v'][::-1]  # km/s

		# Get the the indices of the host to consider
		self.host_sub_ind = self.host['snap'] >= np.min(self.sub_halo['snap'])
		self.host_sub_ind = self.host_sub_ind[self.host_snaps]

		# Pick the snapshot to start integration the first time the subhalo
		# enters the virial radius
		self.int_start = np.where(np.sqrt(np.sum(np.square(
			self.sub_dx_physical),axis=-1))<self.host_r_vir[
			self.host_sub_ind])[0][0]

		# Convert the subhalo position and velocity as well
		self.sub_pos_int = conversion.convert_unit_Mpc((self.sub_pos.T /
			self.cosmo.h * self.sub_scales).T)
		self.sub_vel_int = conversion.convert_units_kms(self.sub_vel)

		# Set up the array of integration times
		self.sub_times = self.host_times[self.host_sub_ind][self.int_start:]
		self.time_end = self.host_times[self.host_sub_ind][self.int_start]
		self.time_start = np.min(self.host_times)
		# If dt is specified use it to define the number of integartion
		# steps.
		if dt is not None:
			num_t_step = int((self.time_end - self.time_start)//dt)
		self._num_t_step = num_t_step
		# Even if dt is specified, getting a integer number of integration
		# steps will not allow for that exact dt.
		self.dt = (self.time_end - self.time_start)/self._num_t_step
		self.times_int = np.linspace(self.time_start,self.time_end,
			self._num_t_step)[::-1]
		self.scales_int = 1/(1+self.cosmo.lookbackTime(
			self.times_int/conversion.convert_unit_gigayear(1),
			inverse=True))

		# Interpolate the subhalo properties for integation
		self.pos_nfw_array = np.zeros((self._num_t_step,3))
		for i in range(3):
			self.pos_nfw_array[:,i] = interp1d(self.host_times,
				self.host_pos_int[:,i],kind='cubic')(self.times_int)
		self.rho_0_array = interp1d(self.host_times,self.host_rho_int)(
			self.times_int)
		self.r_scale_array = interp1d(self.host_times,self.host_r_s_int)(
			self.times_int)

		# Get the box length and convert it to physical coordinates
		self.box_length_array = conversion.convert_unit_Mpc(self.trj_host.L/
			self.cosmo.h * self.scales_int)