Analysing GW150914 with the CLI¤
This tutorial walks through a complete parameter-estimation run on GW150914 — the first gravitational-wave detection — using the jim-run command. By the end you will have a posterior sample file and know how to inspect the results.
Prerequisites¤
- Jim installed:
pip install jimgw(oruv syncin the repository) - Internet access to fetch strain and PSD data from GWOSC
- A GPU is strongly recommended; CPU runs are possible but slow
1. Generate a template config¤
jim-run --init gw150914.toml
This writes a GW150914-style template config to gw150914.toml and exits. Open it in any text editor — the sections below explain each piece.
2. Walk through the config¤
Seed¤
seed = 0
JAX random seed. Change this to run independent realisations.
[data]¤
[data]
type = "gwosc"
detectors = ["H1", "L1"]
trigger_time = 1126259462.4
duration = 4.0
post_trigger_duration = 2.0
psd_duration = 1024.0
type = "gwosc"— fetches strain and PSD from the public GWOSC archive automatically.detectors— the detectors to include.H1is LIGO Hanford,L1is LIGO Livingston.trigger_time— GPS time of the event (1126259462.4 s for GW150914).duration— analysis segment length in seconds. The strain window runs fromtrigger_time - duration + post_trigger_durationtotrigger_time + post_trigger_duration.post_trigger_duration— seconds after the trigger kept in the analysis window (2 s is standard for stellar-mass BBH).psd_duration— length of the off-source segment used to estimate the PSD (1024 s is recommended to resolve low-frequency features).
[waveform]¤
[waveform]
approximant = "IMRPhenomXAS"
f_ref = 20.0
approximant— which ripple waveform model to use.IMRPhenomXASis a fast, accurate aligned-spin BBH model.f_ref— reference frequency in Hz at which spin magnitudes and angles are defined (20 Hz is conventional for BBH).
[prior]¤
[prior]
M_c = { type = "uniform", min = 10.0, max = 80.0 }
q = { type = "uniform", min = 0.125, max = 1.0 }
s1_z = { type = "uniform", min = -0.99, max = 0.99 }
s2_z = { type = "uniform", min = -0.99, max = 0.99 }
iota = { type = "sine" }
d_L = { type = "power_law", min = 1.0, max = 2000.0, alpha = 2.0 }
t_c = { type = "uniform", min = -0.1, max = 0.1 }
phase_c = { type = "uniform", min = 0.0, max = 6.283185307179586 }
psi = { type = "uniform", min = 0.0, max = 3.141592653589793 }
ra = { type = "uniform", min = 0.0, max = 6.283185307179586 }
dec = { type = "cosine" }
Each line names a parameter and specifies its prior distribution. Key choices for GW150914:
| Parameter | Meaning | Prior choice |
|---|---|---|
M_c |
Chirp mass (\(M_\odot\)) | Uniform, broad enough to encompass GW150914 (\(\sim 28\,M_\odot\)) |
q |
Mass ratio \(m_2/m_1 \leq 1\) | Uniform; 0.125 = 1:8 mass ratio |
s1_z, s2_z |
Aligned spin components | Uniform on (-0.99, 0.99) — physical black holes |
iota |
Inclination angle | sine prior = uniform on the sphere |
d_L |
Luminosity distance (Mpc) | power_law with \(\alpha=2\) = uniform in volume |
t_c |
Coalescence time offset (s) | Uniform ±0.1 s around trigger_time |
phase_c |
Coalescence phase | Uniform on \([0, 2\pi)\) |
psi |
Polarisation angle | Uniform on \([0, \pi)\) |
ra, dec |
Sky position | Uniform in ra; cosine prior in dec = uniform on sphere |
The CLI automatically infers all required transforms (mass-ratio conversion, sky-frame rotation) from the parameter names — you do not configure these yourself.
[likelihood]¤
[likelihood]
f_min = 20.0
f_max = 1024.0
The frequency band for the matched-filter likelihood. 20–1024 Hz is standard for stellar-mass BBH with LIGO O1 data.
[sampler]¤
[sampler]
type = "flowmc"
n_chains = 1000
n_local_steps = 100
n_global_steps = 1000
n_training_loops = 50
n_production_loops = 10
n_NFproposal_batch_size = 100
global_thinning = 100
flowmc is a normalizing-flow-enhanced MCMC sampler. For a quick test (minutes instead of hours), reduce to:
n_chains = 100
n_global_steps = 100
n_production_loops = 2
[output]¤
[output]
dir = "output/GW150914"
save_corner = false
Results are written to output/GW150914/. Set save_corner = true to automatically generate a corner plot (requires the corner package).
3. Run the analysis¤
jim-run gw150914.toml
Use -v for verbose (DEBUG-level) logging. On a modern GPU the production settings finish in roughly 30–60 minutes; the quick-test settings complete in a few minutes.
Expected console output:
INFO | jimgw.cli | Loaded config from gw150914.toml
INFO | jimgw.cli | seed: 0
INFO | jimgw.cli | data: type=gwosc, detectors=['H1', 'L1']
INFO | jimgw.cli | waveform: IMRPhenomXAS (f_ref=20.0 Hz)
INFO | jimgw.cli | prior: 11 parameter(s): ['M_c', 'q', 's1_z', ...]
INFO | jimgw.cli | sampler: type=flowmc
INFO | jimgw.cli | Sampling complete.
4. Inspect the outputs¤
After the run, output/GW150914/ contains:
output/GW150914/
├── samples.npz # posterior samples
├── diagnostics.json # scalar diagnostics (acceptance rates, …)
├── diagnostics.npz # array diagnostics (log-prob traces, …)
└── config.final.toml # the resolved config (useful for reproducing this run)
Load the posterior samples¤
import numpy as np
data = np.load("output/GW150914/samples.npz")
params = list(data.keys()) # one key per parameter
samples = np.column_stack([data[p] for p in params]) # shape: (n_samples, n_params)
print(params)
# ['M_c', 'q', 's1_z', 's2_z', 'iota', 'd_L', 't_c', 'phase_c', 'psi', 'ra', 'dec']
Make a corner plot¤
import corner
import matplotlib.pyplot as plt
fig = corner.corner(samples, labels=params)
plt.savefig("corner.png", dpi=150)
Reproduce the run¤
config.final.toml records the exact resolved configuration (including any defaults that were applied). To reproduce the run, pass it directly to jim-run. Because config.final.toml retains the original output.dir, the run will abort if that directory already exists and output.overwrite is not set. Before re-running, either change output.dir to a new path or add output.overwrite = true:
# in config.final.toml — pick one:
[output]
dir = "output/GW150914_repro" # write to a fresh directory
# or
overwrite = true # allow overwriting output/GW150914 in-place
Then run:
jim-run output/GW150914/config.final.toml
5. Next steps¤
- Switch to a nested sampler — change
[sampler]totype = "blackjax-ns-aw"ortype = "blackjax-nss"(requiresuv sync --group nested-sampling) to obtain a log-evidence estimate. - Try an injection — change
[data]totype = "injection"withinjection_parametersto validate recovery on a known signal. See the CLI Config Reference for the full injection syntax. - Enable heterodyning — add a
[likelihood.heterodyne]block for a 10–100× likelihood speedup. See the CLI Config Reference. - Full config reference — CLI Config Reference documents every available field and default.