Fields in ytree¶
ytree supports multiple types of fields, each representing numerical
values associated with each halo in the Arbor
. These include the
native fields stored on disk, alias fields, derived fields, and
analysis fields.
The Field Info Container¶
Each Arbor
contains a dictionary,
called field_info
,
with relevant information for each available field. This information
can include the units, type of field, any dependencies or aliases, and
things relevant to reading the data from disk.
>>> import ytree
>>> a = ytree.load("tree_0_0_0.dat")
>>> print (a.field_info["Rvir"])
{'description': 'Halo radius (kpc/h comoving).', 'units': 'kpc/h ', 'column': 11,
'aliases': ['virial_radius']}
>>> print (a.field_info["mass"])
{'type': 'alias', 'units': 'Msun', 'dependencies': ['Mvir']}
Fields on Disk¶
Every field stored in the dataset’s files should be available within
the Arbor
. The field_list
contains a list of all fields on disk
with their native names.
>>> print (a.field_list)
['scale', 'id', 'desc_scale', 'desc_id', 'num_prog', ...]
Alias Fields¶
Because the various dataset formats use different naming conventions for
similar fields, ytree allows fields to be referred to by aliases. This
allows for a universal set of names for the most common fields. Many are
added by default, including “mass”, “virial_radius”, “position_<xyz>”,
and “velocity_<xyz>”. The list of available alias and derived fields
can be found in the derived_field_list
.
print (a.derived_field_list)
['uid', 'desc_uid', 'scale_factor', 'mass', 'virial_mass', ...]
Additional aliases can be added with
add_alias_field
.
>>> a.add_alias_field("amount_of_stuff", "mass", units="kg")
>>> print (a["amount_of_stuff"])
[ 1.30720461e+45, 1.05085632e+45, 1.03025691e+45, ...
1.72691772e+42, 1.72691772e+42, 1.72691772e+42]) kg
Derived Fields¶
Derived fields are functions of existing fields, including other
derived and alias fields. New derived fields are created by
providing a defining function and calling
add_derived_field
.
>>> def potential_field(data):
... # data.arbor points to the parent Arbor
... return data["mass"] / data["virial_radius"]
...
>>> a.add_derived_field("potential", potential_field, units="Msun/Mpc")
[ 2.88624262e+14 2.49542426e+14 2.46280488e+14, ...
3.47503685e+12 3.47503685e+12 3.47503685e+12] Msun/Mpc
Field functions should only take a single argument, representing
the entity for which the field is defined. This argument will
also have access to the parent Arbor
.
Analysis Fields¶
Analysis fields provide a means for saving the results of complicated
analysis for any halo in the Arbor
. This would be operations
beyond derived fields, for example, things that might require loading
the original simulation snapshots. New analysis fields are created
with add_analysis_field
and are
initialized to zero.
>>> a.add_analysis_field("saucer_sections", units="m**2")
>>> print (a[0]["tree", "saucer_sections"])
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0.,] m**2
>>> import numpy as np
>>> for t in a[0]["tree"]:
... t["saucer_sections"] = np.random.random() # complicated analysis
...
>>> print (a[0]["tree", "saucer_sections"])
[ 0.33919263 0.79557815 0.38264336 0.53073945 0.09634924 0.6035886, ...
0.9506636 0.9094426 0.85436984 0.66779632 0.58816873] m**2
Analysis fields will be automatically saved when the Arbor
is saved
with save_arbor
.