galform_analysis
Python tools for reading the galaxies.hdf5 files written by the
GALFORM galaxy
formation model and measuring things from them: mass and luminosity functions,
halo occupation, dust attenuation and clustering.
Install
pip install galform_analysis
This is enough for reading data, mass functions, luminosity functions and dust. Two extras add the rest:
| Extra | Adds | For |
|---|---|---|
clustering |
Corrfunc | correlation functions, w_p, bias, RSD multipoles |
science |
hmf, astropy, CAMB, colossus, SciPy | theoretical halo mass functions, linear matter ξ(r) |
all |
both | everything |
pip install "galform_analysis[all]"
Corrfunc is compiled during installation, so clustering needs a C compiler
with OpenMP and the GSL headers (sudo apt-get install libgsl-dev,
brew install gsl, or module load gsl on a cluster). If an extra is
missing, only the functions that need it fail, with an error saying which
extra to install.
Python 3.10 to 3.14 is supported.
Before you start
GALFORM writes one directory per snapshot, with one or more subvolumes in each:
<base_dir>/iz<NNN>/ivol<M>/galaxies.hdf5
Each ivol is an independent realisation of the whole simulation box, not a
piece of it.
Tell the package where your output is, once per session:
import galform_analysis
galform_analysis.set_base_dir("/path/to/Galform_Out/L800/model")
or set the GALFORM_BASE_DIR environment variable. Functions that take a
snapshot number, such as 271 for iz271, look inside this directory.
Functions that take a path, such as ".../iz271", do not need it.
Units. Masses are in M☉/h and lengths in Mpc/h, as GALFORM writes them. Number densities φ are per (Mpc/h)³ per dex (mass functions) or per magnitude (luminosity functions). Absolute magnitudes are M − 5 log₁₀ h.
How to
Read one subvolume
from galform_analysis import close_snapshot, read_snapshot_data
data = read_snapshot_data("/path/to/Galform_Out/L800/model/iz271", ivol=0)
mstar = data["mstar"] # stellar mass, disk + bulge
mhalo = data["mhalo"] # halo mass
print(data["z"], data["V_ivol"])
close_snapshot(data) # close the HDF5 file
For a table with positions and other fields, use
galform_analysis.utils.read_galaxies.read_galaxies_dataframe.
Measure a stellar mass function
from galform_analysis import (
avg_smf_given_redshift_and_subvolumes,
smf_given_redshift_and_subvolume,
)
# One subvolume
smf = smf_given_redshift_and_subvolume("/path/to/Galform_Out/L800/model/iz271", ivol=0)
smf["centers"], smf["phi"] # log10(M*) bin centres and phi
# Mean and scatter over subvolumes 0-7 of iz271
avg = avg_smf_given_redshift_and_subvolumes(271, ivols=list(range(8)))
avg["phi"], avg["phi_std"]
Halo mass functions work the same way (hmf_given_redshift_and_subvolume,
avg_hmf_given_redshift_and_subvolumes), as does the halo occupation
distribution (hod_given_redshift_and_subvolume in
galform_analysis.analysis). Pass bins= to change the bins.
Measure a luminosity function
GALFORM stores a luminosity for every galaxy in every band listed in its run parameters. To see which bands a run has:
from galform_analysis import list_bands
list_bands("/path/to/Galform_Out/L800/model/iz271")
Pick a band by its label, which is the first word of the GALFORM band name,
such as "SDSS-r", "UKIRT-K" or "Bj". Labels are case-sensitive: "R" is
Cousins R and "SDSS-r" is SDSS r.
from galform_analysis import (
avg_lf_given_redshift_and_subvolumes,
lf_given_redshift_and_subvolume,
)
# r band, one subvolume
lf = lf_given_redshift_and_subvolume(
"/path/to/Galform_Out/L800/model/iz271", ivol=0, band="SDSS-r"
)
lf["centers"], lf["phi"] # magnitude bin centres and phi
# K band in Vega magnitudes, averaged over subvolumes 0-7
avg = avg_lf_given_redshift_and_subvolumes(
271, ivols=list(range(8)), band="UKIRT-K", system="Vega"
)
Other options: frame="observer" for observer-frame magnitudes, and
component="disk" or "bulge" for the light of one component only.
Add dust
By default luminosities are intrinsic, with no dust. Pass dust="lacey16" to
apply GALFORM's dust model with the parameters of Lacey et al. (2016).
GALFORM is not public, so this package does not contain its dust model.
Instead it runs the dust code in your own GALFORM checkout. Point
GALFORM_DIR at a checkout that you have built with CMake:
export GALFORM_DIR=/path/to/galform # build expected in /path/to/galform/build
If the build is somewhere else, also set GALFORM_BUILD_DIR. The first time
you use dust, a small program is compiled against your GALFORM build, using
the same compiler, and kept in ~/.cache/galform_analysis for later.
from galform_analysis import (
avg_lf_given_redshift_and_subvolumes,
read_band_magnitudes,
)
# bJ luminosity function with dust
avg = avg_lf_given_redshift_and_subvolumes(
271, ivols=list(range(8)), band="Bj", system="Vega", dust="lacey16"
)
# Magnitudes of every galaxy in one subvolume, with and without dust
iz = "/path/to/Galform_Out/L800/model/iz271"
intrinsic = read_band_magnitudes(iz, 0, "SDSS-r")["mag"]
attenuated = read_band_magnitudes(iz, 0, "SDSS-r", dust="lacey16")["mag"]
Each galaxy gets a random orientation, the same in every band, so colours
are consistent. Use inclination="face-on", "average" or an angle in
degrees to change this, and seed= to change the random draw.
Not included: the extra dimming of very young stars (under 1 Myr old) inside
their birth clouds. GALFORM needs extra tables for this that are not in
galaxies.hdf5. It mostly affects the far-UV.
Measure a correlation function (needs clustering)
import numpy as np
from galform_analysis import compute_xi_corrfunc
rng = np.random.default_rng(1)
positions = rng.uniform(0, 100.0, size=(20_000, 3)) # (N, 3) array in Mpc/h
rbins = np.logspace(0, 1.5, 11) # 1 to 32 Mpc/h
xi = compute_xi_corrfunc(positions, boxsize=100.0, rbins=rbins, nthreads=4)
xi["r"], xi["xi"] # a polars DataFrame; xi is close to zero for random points
To go straight from a subvolume, use correlation_given_redshift_and_subvolume.
On a shared machine, set nthreads (and OMP_NUM_THREADS) to the number of
cores you have been given.
Look up a simulation
from galform_analysis import SimulationConfig, find_snapshot_at_redshift
sim = SimulationConfig("L800")
print(sim.box_size, sim.omega_m, sim.h0, sim.n_subvolumes)
find_snapshot_at_redshift(1.0, "L800") # the snapshot nearest z = 1
Simulations included: L800, Millennium I and II, EAGLE, COLIBRE, FLAMINGO, Dove and nIFTy. Their settings come from the galform_execution package, so analysis and runs use the same values.
Example notebooks
The examples/
folder has one notebook per topic, each run on the L800 simulation:
| Topic | Notebook |
|---|---|
| Reading a snapshot | load_snapshot |
| Galaxy tables and positions | read_galaxies |
| Stacking all subvolumes | aggregation |
| Stellar mass function | smf |
| Halo mass function | hmf |
| Halo occupation | hod |
| Luminosity functions | lf |
| Dust attenuation | dust_attenuation |
| Correlation function | correlation |
| Galaxy bias | bias |
| Satellite–central cross-correlation | cross_correlation |
| Using only some subvolumes | subvol_weighted |
| Redshift-space multipoles | multipoles |
The figures use the k.wang style from
oh-mpl-paper, which sizes them for
an MNRAS column.
Development
git clone https://github.com/OscarHickman/galform_analysis.git
cd galform_analysis
pip install -e ".[all,dev]"
pytest tests --cov # tests and coverage (CI needs 80% or more)
ruff check galform_analysis tests # lint
ruff format galform_analysis tests # format
The tests make small fake galaxies.hdf5 files with the same layout as real
ones, so no simulation data is needed. Tests for an extra are skipped if it is
not installed. The tests that run GALFORM's dust code
need GALFORM_DIR (a built GALFORM checkout) and are skipped without it.
Citation
If you use galform_analysis in published work, please cite it
(CITATION.cff):
@software{galform_analysis,
author = {Hickman, Oscar},
title = {galform_analysis: Python tools for analysing GALFORM galaxy formation model outputs},
version = {0.4.1},
url = {https://github.com/OscarHickman/galform_analysis}
}
License
MIT. See LICENSE.
Metadata
Release files for galform-analysis 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| galform_analysis-0.4.1.tar.gz | 178.2 kB | With provenance | Details for galform_analysis-0.4.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| galform_analysis-0.4.1-py3-none-any.whl | Python 3 | none | any | Details for galform_analysis-0.4.1-py3-none-any.whl |
Total release size: 269.6 kB
Release files / galform_analysis-0.4.1.tar.gz
| Download URL | galform_analysis-0.4.1.tar.gz |
|---|---|
| Size | 178.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1bcaef995fb487f8c33b90e1c1e100b27e74c22509b81272a24e31123e639d34
|
|
BLAKE2b-256 checksum How to use checksums |
115bd06c7fcf5df23f78bebd5eaf6afb99a99f5a0dee7e44e264fce705dbec56
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logRelease files / galform_analysis-0.4.1-py3-none-any.whl
| Download URL | galform_analysis-0.4.1-py3-none-any.whl |
|---|---|
| Size | 91.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8b66a6f65c903837647206e352334776c9a0a7204978e0bdcb3c86e5bd5a43ca
|
|
BLAKE2b-256 checksum How to use checksums |
c974b86210e4fe304121af88744bad91a6904e9df22f265033cc98af312015aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logSecurity for galform-analysis 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for galform_analysis-0.4.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.