Loading, Using, and Saving Merger-trees

The Arbor class is responsible for loading and providing access to merger-tree data. Below, we discuss how to load in data and what one can do with it.

Loading Merger-tree data

ytree can load merger-tree data from multiple sources using the ~ytree.arbor.load command. This command will guess the correct format and read in the data appropriately. For examples of loading each format, see below.

Consistent Trees

The consistent-trees format is typically one or a few files with a naming convention like “tree_0_0_0.dat”. To load these files, just give the filename

import ytree
a = ytree.load("tree_0_0_0.dat")

Rockstar Catalogs

Rockstar catalogs with the naming convention “out_*.list” will contain information on the descendent ID of each halo and can be loaded independently of consistent-trees. This can be useful when your simulation has very few halos, such as in a zoom-in simulation. To load in this format, simply provide the path to one of these files.

import ytree
a = ytree.load("rockstar_halos/out_0.list")

TreeFarm

Merger-trees created with the TreeFarm method can be loaded in by providing the path to one of the catalogs created during the calculation.

import ytree
a = ytree.load("all_halos/fof_subhalo_tab_016.0.hdf5.0.h5")

Arbor

Once merger-tree data has been loaded, it can be saved to a universal format. This can be loaded by providing the file created.

import ytree
a = ytree.load("arbor.h5")

Working with Merger-trees

Once merger-tree data has been loaded into an Arbor, the individual trees will be stored in a list in the trees attribute.

>>> import ytree
>>> a = ytree.load("tree_0_0_0.dat")
yt : [INFO     ] 2016-09-26 15:35:57,279 Loading tree data from tree_0_0_0.dat.
Loading trees: 100%|████████████████████████| 327/327 [00:00<00:00, 4602.07it/s]
yt : [INFO     ] 2016-09-26 15:35:57,666 Arbor contains 327 trees with 10405 total nodes.
>>> print (len(a.trees))
327
>>> print (a.trees[0])
TreeNode[0,0]

A TreeNode is one halo in a merger-tree. The numbers correspond to the halo ID and the level in the tree. Like with yt data containers, fields can be queried in dictionary fashion.

>>> my_tree = a.trees[0]
>>> print (my_tree["mvir"])
1.147e+13 Msun/h
>>> print (my_tree["redshift"])
0.0
>>> print (my_tree["position"])
[ 69.95449  60.33949  50.64586] Mpc/h
>>> print (my_tree["velocity"])
[ -789.51  1089.31  1089.31] km/s

A halo’s ancestors are stored as a list in the ancestors attribute.

>>> print my_tree.ancestors
[TreeNode[1,0]]

Iterating over a Tree

The twalk function provides an iterator that allows you to loop over all halos in the tree. This will iterate over all ancestors in a recursive fashion.

>>> for my_node in my_tree.twalk():
...     print (my_node)

Accessing the Trunk of the Tree

The line function allows one to query fields for the main trunk of the tree. By default, the “main trunk” follows the most massive progenitor.

>>> print my_tree.line("mvir")
[  1.14700000e+13   1.20700000e+13   1.23700000e+13   1.23700000e+13, ...,
   6.64000000e+12   5.13100000e+12   3.32000000e+12   1.20700000e+12
   2.71600000e+12] Msun/h

The selection method used by the line function can be changed by calling the set_selector function on the Arbor. For information on creating new selection methods, see the example, ~tree.tree_node_selector.max_field_value.

>>> a.set_selector("min_field_value", "mvir")

Similar to twalk, the lwalk function provide an iterator over the trunk of a tree.

>>> for my_node in my_tree.lwalk():
...     print (my_node)

Similar to the line function, the tree function provides field access to the whole tree. However, since this is for all ancestors, note that these are not necessarily in chronological order.

>>> print my_tree.tree("mvir")

Saving Arbors and Trees

Arbors of any type can be saved to a universal file format which can be reloaded in the same way.

>>> a.save_arbor("my_arbor.h5")
yt : [INFO     ] 2016-09-26 16:45:40,064 Saving field data to yt dataset: my_arbor.h5.
>>> a2 = ytree.load("my_arbor.h5")
Loading trees: 100%|████████████████████████| 327/327 [00:00<00:00, 1086.22it/s]
yt : [INFO     ] 2016-09-26 16:46:26,383 Arbor contains 327 trees with 10405 total nodes.

Individual trees can be saved and reloaded in the same manner.

>>> fn = my_tree.save_tree()
yt : [INFO     ] 2016-09-26 16:47:09,931 Saving field data to yt dataset: tree_0_0.h5.
>>> atree = ytree.load(fn)
Loading trees: 100%|█████████████████████████████| 1/1 [00:00<00:00, 669.38it/s]
yt : [INFO     ] 2016-09-26 16:47:32,441 Arbor contains 1 trees with 45 total nodes.