Tutorial on the algorithm for subhalo-based mock-making

This section of the documentation provides detailed notes for how the SubhaloMockFactory populates subhalo catalogs with synthetic galaxy populations. The SubhaloMockFactory uses composite models built with the SubhaloModelFactory, which is documented in the Source code notes on SubhaloModelFactory.

Outline

We will start in Basic syntax for making subhalo-based mocks with a high-level overview of the functionality of the SubhaloMockFactory class. We provide detailed notes on the source code of the mock factory in Algorithm for populating subhalo-based mocks.

Basic syntax for making subhalo-based mocks

The most common way to interact with instances of the SubhaloMockFactory is as an attribute of the composite model you are using to generate the mock. For example, the code snippet below shows how the populate_mock method creates a mock object to the composite model, which in this case will be a model based on the Behroozi et al. (2010) parameterized abundance matching model:

from halotools.empirical_models import PrebuiltSubhaloModelFactory
behroozi10_model = PrebuiltSubhaloModelFactory('behroozi10')

from halotools.sim_manager import CachedHaloCatalog
default_halocat = CachedHaloCatalog()

behroozi10_model.populate_mock(default_halocat)

The final line of code above creates the behroozi10_model.mock attribute, an instance of SubhaloMockFactory.

The SubhaloMockFactory is responsible for one task: using a Halotools composite model to populate a simulation with mock galaxies. When the SubhaloModelFactory.populate_mock method first creates a model.mock instance, the instantiation of SubhaloMockFactory triggers the pre-processing phase of mock population. Briefly, this phase does as many tasks in advance of actual mock population as possible to improve the efficiency of MCMCs (see below for details).

By default, instantiating the mock factory also triggers the SubhaloMockFactory.populate method to be called. This is the method that actually creates the galaxy population. By calling the SubhaloMockFactory.populate method, a new galaxy_table attribute is created and bound to the model.mock instance. The galaxy_table attribute stores an Astropy Table object with one row per mock galaxy and one column for every property assigned by the chosen composite model.

Algorithm for populating subhalo-based mocks

Pre-processing phase

In the preprocess_halo_catalog, new columns are added to the halo_table according to any entries in the new_haloprop_func_dict; any such columns will automatically be included in the galaxy_table. See The new_haloprop_func_dict mechanism for further details.

The pre-processing phase concludes with the call to the precompute_galprops method, which is the first function that adds columns to the galaxy_table. For SubhaloModelFactory composite models, the spatial positions and velocities of mock galaxies exactly coincide with those of (sub)halos, and so the x, y, z, vx, vy, vz columns can all be added to the galaxy_table in advance.

Mock-population phase

After pre-processing, the galaxy_table has been prepared for the assignment of properties that are computed dynamically, e.g., stellar mass and star formation rate. This phase is controlled by the populate method. Because the high-level bookkeeping has already been handled by the SubhaloModelFactory class, the source for this phase is quite compact and straightforward.

First, empty columns are added to the galaxy_table with by the _allocate_memory method. We do this by looping over every property in _galprop_dtypes_to_allocate that has not already been assigned:

Ngals = len(self.galaxy_table)

new_column_generator = (key for key in self.model._galprop_dtypes_to_allocate.names
    if key not in self._precomputed_galprop_list)

for key in new_column_generator:
    dt = self.model._galprop_dtypes_to_allocate[key]
    self.galaxy_table[key] = np.empty(Ngals, dtype = dt)

See The galprop_dtypes_to_allocate mechanism for details about this bookkeeping device.

Once memory has been allocated to the galaxy_table, we successively pass this table to each of the functions in the _mock_generation_calling_sequence:

for method in self.model._mock_generation_calling_sequence:
    func = getattr(self.model, method)
    func(table = self.galaxy_table)

See The model_feature_calling_sequence mechanism for details. Note how the use of getattr allows the SubhaloMockFactory to call the appropriate method without knowing its name. This high-level feature of python is what allows the factory work with any arbitrary set of component models.