Analyzing Model Grids¶
Once you have a model grid in hand, there are a slew of built-in analysis
routines that you might consider using. For the rest of this example,
we’ll assume you have completed a Simple Parameter Study, and have the associated set of files
with prefix test_model_grid
.
To begin, initialize an instance of the analysis class, ModelSet
:
anl = ares.analysis.ModelSet('test_model_grid')
First, let’s verify that we’ve surveyed the part of parameter space we intended to:
ax = anl.Scatter('fX', 'fstar')
You should see a scatterplot with points in the \(f_X\)—\(f_{\ast}\) plane representing the models in our grid.
Basic Inspection¶
Now, the kind of analysis you can do will be limited by what quantities were saved for each model. Recall (from Simple Parameter Study) that we have the following quantities at our disposal:
- 21-cm brightness temperature,
dTb
. - Spin temperature,
Ts
. - Kinetic temperature,
igm_Tk
. - HII region volume filling factor,
cgm_h_2
. - Neutral fraction in the bulk IGM,
igm_h_1
. - Heating rate in the IGM,
igm_heat_h_1
. - Volume-averaged ionization rate, i.e., the rate of change in
cgm_h_2
,cgm_Gamma_h_1
.
and we know them at redshifts 6, 8, 10, 12, and the redshifts corresponding to turning points B, C, and D in the global 21-cm signal.
Let’s have a look at how the thermal history depends on our two parameters of interest in this example, \(f_X\) and \(f_{\ast}\).
ax = anl.Scatter('fX', 'igm_Tk', z=10, fig=2)
Note
All ModelSet
functions accept fig
as an optional keyword argument, which you can set to any integer to open plots in a new window.
Notice that there are two tracks of points, one for each value of \(f_{\ast}\).
This information can be visualized on the same axis by supplying the keyword
argument c
, which color-codes each point by the field provided:
ax = anl.Scatter('fX', 'igm_Tk', c='fstar', z=10, fig=3)
For more 21-cm-focused analyses, you may want to view how the extrema in the global 21-cm signal change as a function of the model parameters:
# Scatterplot showing where absorption/emission peaks occur
ax = anl.Scatter(x='nu', y='dTb', z='C', fig=4)
ax = anl.Scatter(x='nu', y='dTb', z='D', ax=ax)
# Run default global 21-cm signal model
sim = ares.simulations.Global21cm()
sim.run()
# Overplot it
anl_sim = ares.analysis.Global21cm(sim)
anl_sim.GlobalSignature(ax=ax)
If you forget what fields are available for analysis (and at what redshifts), see:
print anl.blob_names, anl.blob_redshifts
Note
Calling quantities of interest blobs was inspired by the arbitrary meta-data blobs in emcee.
Confidence Contours¶
Notice that we have yet to assume anything about a measurement, meaning we have made no attempt to quantify the likelihood that any model in our grid is correct. Let’s say that somebody hands us a measurement of the position of the absorption trough in the global 21-cm signal: it’s at \(\nu=80 \pm 2\) MHz and \(\delta T_b = -100 \pm 20\) mK, where the errors provided are assumed to be \(1−\sigma\) (independent) Gaussian errors.
Note
For this example, it will be advantageous to have a more well-sampled parameter space. Consider re-running the Simple Parameter Study with more points in each dimension before proceeding. Or, just download one here.
To compute the likelihood for each model in our grid, we can define functions
representing the Gaussian errors on the measurement, and pass them to the
set_constraint
function:
nuC = lambda x: np.exp(-(x - 80.)**2 / 2 / 2.**2)
TC = lambda x: np.exp(-(x + 100.)**2 / 2. / 10.**2)
anl.set_constraint(nu=['C', nuC], dTb=['C', TC])
Each argument passed to set_constraint
is a two-element list: the redshift
Now, to look at the probability distribution function for our parameters of interest,
ax = anl.PosteriorPDF(['fX', 'fstar'], take_log=True)
Note
It may often be advantageous to supply take_log=True
in order
to view posterior PDFs of quantities in log-log space.
To convert the color-scale from one proportional to the likelihood of a given model to one that denotes, e.g., the 1 and 2 \(\sigma\) bounds on the likelihood, do something like:
ax = anl.PosteriorPDF(['fX', 'fstar'], take_log=True, color_by_like=True,
colors=['g', 'b'])
By default, this includes the 68 and 95 percent confidence intervals, but you can pick any contour(s) you like (no matter how unconventional it might be):
ax = anl.PosteriorPDF(['fX', 'fstar'], take_log=True, color_by_like=True,
colors=['g', 'b'], nu=[0.5, 0.8])
Note
To view the confidence regions as open contours, set
filled=False
. You can control the color and linestyle of each contour
by the colors
and linestyles
keyword arguments.
Extracting Subsets of Models¶
Often you may want to focus on some subset of models within a grid. There are a few different ways of doing this in ares. The model grid from above (in section on confidence contours) will make for a nice test dataset.
To read in that dataset,
anl = ares.analysis.ModelSet('test_grid_30x80')
Then, set the constraints as we did before:
constraints = \
{
'nu': ['C', lambda x: np.exp(-(x - 80.)**2 / 2 / 2.**2)],
'dTb': ['C', lambda x: np.exp(-(x + 100.)**2 / 2. / 10.**2)],
}
# Set constraints
anl.set_constraint(**constraints)
and visualize
ax = anl.PosteriorPDF(['fX', 'fstar'], take_log=[True, True],
color_by_like=True)
Now, to select only the models within the \(2-\sigma\) confidence contour in the \(f_X-f_{\ast}\) plane, for example, we can take a slice through the model grid:
new_anl = anl.Slice(['fX', 'fstar'], like=0.95, take_log=True,
**constraints)
The returned value is a new instance of ModelSet. To convince yourself that
you’ve retrieved the correct data, overplot the new
dataset as points
on the previous axes (with the posterior PDF):
new_anl.Scatter('fX', 'fstar', take_log=[True, True],
ax=ax, color='r', label=r'$\mathcal{L} > 0.95$')
You can also extract a subset of models that have some desired set of properties, independent of likelihood. For example, to extract all models with absorption troughs located at \(72 \leq \nu / \text{MHz} \leq 88\) and \(-120 \leq \delta T_b / \text{mK} \leq -80\), you would do:
new_constraints = \
{
'nu': ['C', lambda x: 1 if 72 <= x <= 88 else 0],
'dTb': ['C', lambda x: 1 if -120 <= x <= -80 else 0],
}
# Take slice and return new ModelSet instance
new_anl = anl.Slice(['fX', 'fstar'], bins=100,
take_log=True, **new_constraints)
# Overplot new points on previous axis
new_anl.Scatter('fX', 'fstar', take_log=[True, True],
ax=ax, color='c', facecolors='none', label='crude slice')
ax.legend(fontsize=14)
pl.draw()
Highly Dimensional Grids¶
For parameter studies with \(\gtrsim 3\) dimensions, you might want to use MCMC. See Running ares with emcee for an example.