Extracting minor mergers from TNG

Claire Ye
  • 8 Jul

Hi TNG Team!

I have a few questions regarding extracting full merger trees from the TNG simulations. I've been following the Python tutorial to extract the mass and snapshot number of minor mergers in TNG50, along with the mass of the subhalo they merge into. To do this, I modified the numMergers function from sublink.py.

As this is my first time working with the TNG data, I wanted to check whether my extraction approach is correct. I’ve attached the Python code I'm using--would you mind taking a quick look? Specifically, is fpMass = maxPastMass(tree, fpIndex, massPartType) always the stellar mass of the current FirstProgenitor subhalo (when massPartType=4)? I'm also wondering if I matched the IDs, masses, and snapshot numbers of the subhalos when I added them to a python dictionary since I'm unsure about the fpIndex and npIndex and where they're pointing to.

In addition, is it possible to extract the distance between the center of mass of the NextProgenitor subhalos and the center of mass of the FirstProgenitor subhalo from the merger tree or snapshots before they merge?

#Find the massive halos
basePath = '../sims.TNG/TNG50-1/output/'
ste_mass_min = 5*10**10/mass_unit_TNG

groupfields = ['GroupFirstSub', 'GroupMassType'] 
GroupFirstSub = il.groupcat.loadHalos(basePath,99,fields=groupfields)
groupids = GroupFirstSub['GroupFirstSub'] 
groupmass_star = GroupFirstSub['GroupMassType'][:,4]

selected_ids = groupids[groupmass_star>=ste_mass_min]
selected_m_star = groupmass_star[groupmass_star>=ste_mass_min]

#Using one id (selected_ids[3]) as an example
fields = ['SubhaloMass','SubfindID','SnapNum','SubhaloID','NextProgenitorID','SubhaloMassType', 'MainLeafProgenitorID','FirstProgenitorID',]
tree = il.sublink.loadTree(basePath, 99, selected_ids[3],fields=fields)

def Merger_Histories(tree, minMassRatio=1e-10, massPartType='stars',index=0, alongFullTree=True):  #copy from sublink.py
   """ Calculate the number of mergers, along the main progenitor branch, in this sub-tree (optionally above some mass ratio threshold). If alongFullTree, count across the full
   sub-tree and not only along the MPB. """
   # verify the input sub-tree has the required fields
   reqFields = ['SubhaloID', 'NextProgenitorID', 'MainLeafProgenitorID',
                'FirstProgenitorID', 'SubhaloMassType']

   if not set(reqFields).issubset(tree.keys()):
       raise Exception('Error: Input tree needs to have loaded fields: '+','.join(reqFields))

   num = 0
   #invMassRatio = 1.0 / minMassRatio
   dictTree = {}

   # walk back main progenitor branch
   rootID = tree['SubhaloID'][index]
   fpID   = tree['FirstProgenitorID'][index]

   while fpID != -1:
       fpIndex = index + (fpID - rootID)
       fpMass  = maxPastMass(tree, fpIndex, massPartType)

       if fpMass<10**10/mass_unit_TNG:
           break

       dictTree[str(fpID)] = {'Mstar': fpMass, 'Progen_ID':[fpID], 'Progen_Mass':[tree['SubhaloMassType'][fpIndex][partTypeNum('star')]],
                               'Progen_SnapNum':[tree['SnapNum'][fpIndex]]}

       # explore breadth
       npID = tree['NextProgenitorID'][fpIndex]

       while npID != -1:
           npIndex = index + (npID - rootID)
           npMass  = maxPastMass(tree, npIndex, massPartType)

           # count if both masses are non-zero, and ratio exceeds threshold
           if fpMass > 0.0 and npMass > 0.0:
               ratio = npMass / fpMass

               #if ratio >= minMassRatio and ratio <= invMassRatio:
               #    num += 1

               if npMass>=5*10**6/mass_unit_TNG and ratio <= 0.1:
                   num+=1

                   dictTree[str(fpID)]['Progen_ID'].append(npID)
                   dictTree[str(fpID)]['Progen_Mass'].append(npMass)

                   dictTree[str(fpID)]['Progen_SnapNum'].append(tree['SnapNum'][npIndex])

           npID = tree['NextProgenitorID'][npIndex]

           # count along full tree instead of just along the MPB? (non-standard)
           if alongFullTree:
               if tree['FirstProgenitorID'][npIndex] != -1:
                   numSubtree, dictSubtree = Merger_Histories(tree, minMassRatio=minMassRatio, massPartType=massPartType, index=npIndex, alongFullTree=True)
                   num += numSubtree
                   dictTree.update(dictSubtree)

       fpID = tree['FirstProgenitorID'][fpIndex]

   return num, dictTree

Thank you so much for you help!

Best,
Claire

Dylan Nelson
  • 13 Jul

You can see the code of maxPastMass(), it is very simple, and can also be changed if you need to.

The first and next progenitor indices are shown schematically on the merger tree diagram.

You can certainly save the SubhaloPos of all the relevant subhalos in your dict as well, and then calculate distances between these positions.

Claire Ye
  • 15 Jul

Hi Dylan,

Thank you for your reply. After re-staring at the merger tree diagram, I have some follow-up questions. There are subhalos from different fof groups that merge into the main branch the diagram is showing (i.e., 5-7). Do these subhalos that belonging to a different fof group merge with the main branch because of galaxy flybys? In addition, how is a subhalo merger defined (e.g., by distance)?

Thank you again,
Claire

Dylan Nelson
  • 15 Jul

A subhalo merger is the event that occurs because a subhalo ceases to exist (in the Subfind catalog). Meaning, it existed in the previous snapshot, but in the current snapshot it no longer exists (its particles have been given to another subhalo, the merger descendant).

A flyby, where by definition the subhalo still exists after the event, is not a merger. In fact, such events are not captured in the merger trees. To find them, you would have to do a separate analysis.

The merger of a subhalo from a different FoF group is the normal picture you should have in mind. In general, two (massive) galaxies originally each sit in their own FoF groups. When these two halos come together, the FoF groups combine. If there are enough snapshots, you may then see one of the two galaxies as a second subhalo of this FoF, and then it would eventually merge. If there aren't enough snapshots, or the merger is quick enough, you may never see this phase, i.e. it will look like a central subhalo of a separate FoF merges into the central subhalo of a different FoF.

  • Page 1 of 1