Subhalo Mass Model

The HACC merger trees (unlike the core-catalogs) do not contain any substructure information. However, it is still possible to model the mass-loss of the merging halos, using the subhalo mass model discussed in [Sultan2020]. This model only depends on the mass of the subhalo and the host halo at infall:

\[\begin{split}m(t + \Delta t) = \begin{cases} m(t) \; \exp -\frac{\Delta t}{\tau} & \zeta = 0 \\ m(t) \left[ 1 + \zeta \left( \frac{m(t)}{M_\mathrm{host}(t)} \right)^\zeta \frac{\Delta t}{\tau} \right]^{-1 / \zeta} & \mathrm{else}, \end{cases}\end{split}\]

where \(\tau\) is the characteristic timescale of the subhalo mass loss (see paper) and \(\zeta\) and \(A\) are free model parameters. In [Sultan2020], \(\zeta=0.1\) and \(A=1.1\) have been found providing a good fit over a large range of halo masses and redshifts.

Creating subhalo data

The function create_submass_data() applies this mass-model to a merger forest and allows querying the substructure masses of any halo in the forest. It can be used as shown in this Last Journey example, where we decide to ignore subhalos below a mass of \(1 \times 10^{10} h^{-1}M_\odot\) and also generate substructure statistics for each host halo:

subhalo_data = haccytrees.mergertrees.create_submass_data(
    forest,
    'LastJourney',
    mass_threshold=1e10,
    compute_fsub_stats=True)

Setting compute_fsub_stats=True will add two columns to forest, fsubmax and fsubtot. The are defined as

\[\begin{split}f_\mathrm{sub, max} &= \frac{\max_i M_\mathrm{sub}}{M_\mathrm{host}}\\ f_\mathrm{sub, tot} &= \frac{\sum_i M_\mathrm{sub}}{M_\mathrm{host}},\end{split}\]

where \(i\) runs over all subhalos of the host above the mass threshold.

Accessing subhalos

Individual subhalo masses can be accessed using the subdata_offset and subdata_size arrays in conjunction with the subhalo_data arrays. Let’s find the subhalos of the most massive halo in our forest and plot their mass distribution relative to the host halo:

target_idx = np.argmax(forest['tree_node_mass'])
start_idx = forest['subdata_offset'][target_idx]
end_idx = start_idx + forest['subdata_size'][target_idx]
subhalo_masses = subhalo_data['mass'][start_idx:end_idx]

fig, ax = plt.subplots(figsize=(5, 3))
target_mass = forest['tree_node_mass'][target_idx]
target_tnidx = forest['tree_node_index'][target_idx]
h, e, _ = ax.hist(np.log10(subhalo_masses/target_mass), 50, histtype='step');
ax.set(yscale='log', xlim=e[[0,-1]],
       xlabel=r'$\log M_\mathrm{sub} \; / \; M_\mathrm{host}$',
       ylabel=r'$N_\mathrm{sub}$')
ax.set_title(f'Halo {target_tnidx}: {len(subhalo_masses)} subhalos')
fig.tight_layout()
../../_images/subhalo_masses.svg

Mass distribution of the subhalos belonging to the most massive halo in our sample (tree_node_index=2247296630669714101, M = 1.28e15 # h-1 Msun).

Following subhalo evolutions

It is also possible to follow the (modeled) mass evolution of a merging halo as it merges and becomes a subhalo. The following example shows how one can do this for a merger into the halo discussed above.

References

haccytrees.mergertrees.create_submass_data(forest, simulation, *, zeta=0.1, A=1.1, mass_threshold=None, compute_fsub_stats=False)[source]
Parameters:
  • zeta (float)

  • A (float)

  • mass_threshold (float | None)

  • compute_fsub_stats (bool)

[Sultan2020] (1,2)

Sultan et al. (2020) arXiv: 2012.09262