Fully coherent search using MCMC
In this example, we will show the basics of setting up and running a
fully-coherent MCMC search. This is based on the example
fully_coherent_search_using_MCMC.py.
We will run the search on the basic
data generated in the
make_fake_data example.
First, we need to import the search tool, in this example we will use the
MCMCSearch
, but one could equally use MCMCGlitchSearch
with nglitch=0
.
To import this,
from pyfstat import MCMCSearch
Next, we define some variables defining the exact parameters of the signal in the data, and the start and end times:
F0 = 30.0
F1 = -1e-10
F2 = 0
Alpha = np.radians(83.6292)
Delta = np.radians(22.0144)
tref = 362750407.0
tstart = 1000000000
duration = 100*86400
tend = tstart = duration
Now, we need to specify our prior. This is a dictionary containing keys for
each variable (in the MCMCSearch
these are F0
, F1
, F2
, Alpha
, and
Delta
). In this example, we choose a uniform box in F0
and F1
:
theta_prior = {'F0': {'type': 'unif', 'lower': F0*(1-1e-6), 'upper': F0*(1+1e-6)},
'F1': {'type': 'unif', 'lower': F1*(1+1e-2), 'upper': F1*(1-1e-2)},
'F2': F2,
'Alpha': Alpha,
'Delta': Delta
}
Each key and value of the theta_prior
contains an instruction to the MCMC
search. If the value is a scalar, the MCMC search holds these fixed (as is the
case for F2
, Alpha
, and Delta
here). If instead the value is a dictionary
describing a distribution, this is taken as the prior and the variable is
simulated in the MCMC search (as is the case for F0
and F1
). Note that
for MCMCSearch
, theta_prior
must contain at least all of the variables
given here (even if they are zero), and if binary=True
, it must also contain
the binary parameters.
Next, we define the parameters of the MCMC search:
ntemps = 4
log10temperature_min = -1
nwalkers = 100
nsteps = [1000, 1000]
These can be considered the tuning parameters of the search. A complete discussion of these can be found here.
Passing all this to the MCMC search, we also need to give it a label, a
directory to save the data, and provide sftfilepath
, a string matching
the data to use in the search
mcmc = MCMCSearch(label='fully_coherent_search_using_MCMC', outdir='data',
sftfilepath='data/*basic*sft', theta_prior=theta_prior,
tref=tref, tstart=tstart, tend=tend, nsteps=nsteps,
nwalkers=nwalkers, ntemps=ntemps,
log10temperature_min=log10temperature_min)
To run the simulation, we call
mcmc.run()
This produces two .png
images. The first is the position of the walkers
during the simulation:
This shows (in red) the position of the walkers during the burn-in stage. They
are initially defuse (they start from positions randomly picked from the prior),
but eventually converge to a single stable solution. The black is the production
period from which posterior estimates are made. The bottom panel is a histogram
of
twoF
, split for the production period. Note that, early on there are
multiple modes corresponding to other peaks, by using the parallel tempering,
we allow the walkers to explore all of these peaks and opt for the strong
central candidate.
To get posteriors, we call
mcmc.plot_corner()
which produces a corner plot
illustrating the tightly constrained posteriors on
F0
and F1
and their
covariance. Furthermore, one may wish to get a summary which can be printed
to the terminal via
mcmc.print_summary()
which gives the maximum twoF value, median and standard-deviation, in this case this is
Summary:
theta0 index: 0
Max twoF: 1771.50622559 with parameters:
F0 = 2.999999874e+01
F1 = -9.999802960e-11
Median +/- std for production values
F0 = 2.999999873e+01 +/- 6.004803009e-07
F1 = -9.999801583e-11 +/- 9.359959909e-16