Dealing with Fragments

During a simulation run, halos sometimes come within the FoF linking length (i.e. merge), but later disassociate again. Since we generally assume that halos don’t split, these “wrongly” merged halos are disentangled in a post-processing step, and labeled as fragments during the time they were part of a “combined” FoF group.

However, some of the halo properties are only calculated once for each FoF group on-the-fly during the simulation, e.g. the SOD properties. Therefore, the SOD property is only known for the “major” fragment in a split FoF group, and not for the “minor” fragments. It is important to keep this in mind whenever dealing with properties that are not aware of the fragment status.

HaccyTrees includes some functionality that attempts to correct those properties for minor fragments, discussed further below.

Identifying Fragments

The fragment status is encoded in the fof_halo_tag, which is composed of the original FoF tag that was assigned on-the-fly, as well as the fragment index. Index 0 corresponds to the “main” or “major” fragment, for which we can assume that the SOD properties are correct. Minor fragments will have a fragment index larger than 0.

The fof_halo_tag for fragments is constructed with the following scheme:

\[-1 \cdot \Big[ \text{fragment index (16 bit)} \; \Big| \; \text{parent fof tag (48 bit} \Big]\]

The two components can be extracted with the function split_fragment_tag(), which can be applied to all negative fof_halo_tag to find the original FoF tag as well as the fragment index.

Note

Since the merger-tree forests for large simulations are split among multiple files, determined by the positions of the root halos at z=0, it is not guaranteed that the main fragment is in the same file as the minor fragments, in case belong to distinct trees (i.e. they don’t share the same root halo / they never merge). The affected fragments will all be located at the boundary of the file extent, i.e. their main fragment can be found in the file that covers the neighboring subvolume.

Properties of Minor Fragments

As previously noted, some quantities are only computed once per FoF group and normally only apply for the main fragment in a split FoF halo (fragment index 0). However, minor fragments will be assigned the same value, which generally is not correct.

One can either mask out these affected branches by identifying the minor fragments (see previous section) or attempt to “correct” the properties by looking at the properties before and after the halo became a minor fragment and doing some sort of interplolation inbetween. The function fix_fragment_properties() provides two kind of corrections that can be applied to all minor fragments in a forest, either by linearly interpolating between the starting and ending value, or by setting the properties to a constant value.

As an example, here is how one would “correct” the SOD mass, radius, and concentration:

%%time
forest, progenitor_array = haccytrees.mergertrees.read_forest(
    "/data/a/cpac/mbuehlmann/LastJourney/forest/m000p.forest.000.hdf5",
    'LastJourney', nchunks=20, chunknum=0)
CPU times: user 558 ms, sys: 1.04 s, total: 1.6 s
Wall time: 1.6 s
%%time
haccytrees.mergertrees.fix_fragment_properties(
    forest,
    ['sod_halo_mass', 'sod_halo_radius', 'sod_halo_cdelta'],
    inplace=False, suffix='_fragfix_const', interpolation='constant_reverse',
    mask_negative=False
)
haccytrees.mergertrees.fix_fragment_properties(
    forest,
    ['sod_halo_mass', 'sod_halo_radius', 'sod_halo_cdelta'],
    inplace=False,
    suffix='_fragfix_lin',
    interpolation='linear',
    mask_negative=True
)
CPU times: user 817 ms, sys: 80.3 ms, total: 898 ms
Wall time: 896 ms

After these function calls, additional arrays are added to the forest, suffixed with _fragfix_lin and _fragfix_const. For the following figure, we pick a halo in the Last Journey simulation that is fragmented at snapshot number 95 and plot the evolution of the tree_node_mass, sod_halo_mass, sod_halo_radius, and sod_halo_cdelta for the major fragment and a minor fragment:

../../_images/fragment_treatment.svg

Evolution of the tree-node mass, SOD mass, SOD radius, and SOD concentration (from top to bottom) of the major and a minor fragment branch. The time where the two halos share the same FoF group is highlighted in grey. Blue and orange lines show the constant and linear corrections for the minor fragment.

Node that in the original catalog, the SOD properties of the minor fragment have the same value as the ones of the major fragment, by construction. After applying the corrections, the SOD mass and SOD radius are either linearly interpolated or set to a constant value (the quantities that the halo has once it becomes the major fragment or an independant halo). Since cdelta == -1 when the minor fragment becomes independant, no interpolation is done (since we set mask_negative=True), but instead cdelta is set to -1 throughout the minor-fragment phase.

Not that the minor and major fragments eventually merge.

References

haccytrees.mergertrees.split_fragment_tag(tag)[source]

Extracting the original fof_tag and fragment index from fragments

Parameters:

tag (int) – the fof_tag of the fragment, has to be negative by definition

Returns:

  • fof_tag – the original fof_tag of the FoF halo the fragment is associated with

  • fragment_idx – the index / enumeration of the fragment (0 == main fragment)

Return type:

Tuple[int, int]

Notes

This function can also be used with numpy arrays directly

haccytrees.mergertrees.fix_fragment_properties(forest, keys, *, inplace=True, suffix='_fragfix', interpolation='constant_reverse', mask_negative=False)[source]

Correct properties of minor fragments

The SOD data stored in the merger tree forest files will be wrong for fragmented FoF groups, if the halo is not the major fragment of this group. This function attempts to fix those values by either linearly interpolate or setting the SOD properties to a constant value during the times when a halo is a minor fragment.

Parameters:
  • forest (Mapping[str, ndarray]) – the full merger tree forest data

  • keys (List[str]) – list of the columns to which the correction should be applied

  • inplace (bool) – if True, the column will be updated in-place, otherwise, a new array will be created with the original name and suffix appended

  • suffix (str) – if not in-place, the new array will be named old_column + suffix

  • interpolation (str) –

    the type of correction to apply. Currently supported are:

    • "constant_reverse": set the properties to the value the halo has when becoming a non-minor-fragment or independent (“reverse” in time)

    • "linear": linearly interpolate (in snapshot-space) the property values from before and after being a minor fragment

  • mask_negative (bool) – if True, will not attempt to do a linear interpolation if either the starting or ending value is negative, e.g. for an invalid concentration parameter. Instead, the property will be set to the negative value during the minor-fragment phase.

Return type:

None

Examples

>>> haccytrees.mergertrees.fix_fragment_properties(forest,
...     ['sod_halo_mass', 'sod_halo_radius', 'sod_halo_cdelta'],
...     inplace=False,
...     suffix='_fragfix_const',
...     interpolation='constant_reverse')
>>> haccytrees.mergertrees.fix_fragment_properties(forest,
...     ['sod_halo_mass', 'sod_halo_radius', 'sod_halo_cdelta'],
...     inplace=False,
...     suffix='_fragfix_lin',
...     interpolation='linear',
...     mask_negative=True)