PyFstat
2.3.0+44.fce9b6f3.clean

Contents:

  • PyFstat
  • PyFstat module documentation
  • Examples
    • Grid searches for isolated CW
    • MCMC searches for isolated CW signals
    • Comparison between MCMC and Grid searches
    • Multi-stage MCMC follow up
    • Binary-modulated CW searches
      • Binary CW example: Semicoherent MCMC search
      • Binary CW example: Comparison between MCMC and grid search
    • Glitch robust CW searches
    • Transient CW searches
    • Other examples
PyFstat
  • Examples
  • Binary-modulated CW searches
  • Binary CW example: Comparison between MCMC and grid search
  • View page source

Note

Go to the end to download the full example code.

Binary CW example: Comparison between MCMC and grid search

Comparison of the semicoherent F-statistic MCMC search algorithm to a simple grid search across the parameter space corresponding to a CW source in a binary system.

 10 import os
 11
 12 import matplotlib.pyplot as plt
 13 import numpy as np
 14
 15 import pyfstat
 16
 17 # Set to false to include eccentricity
 18 circular_orbit = False
 19
 20 label = "PyFstatExampleBinaryMCMCvsGridComparison" + (
 21     "CircularOrbit" if circular_orbit else ""
 22 )
 23 outdir = os.path.join("PyFstat_example_data", label)
 24 logger = pyfstat.set_up_logger(label=label, outdir=outdir)
 25
 26 # Parameters to generate a data set
 27 data_parameters = {
 28     "sqrtSX": 1e-22,
 29     "tstart": 1000000000,
 30     "duration": 90 * 86400,
 31     "detectors": "H1,L1",
 32     "Tsft": 3600,
 33     "Band": 4,
 34 }
 35
 36 # Injected signal parameters
 37 tend = data_parameters["tstart"] + data_parameters["duration"]
 38 mid_time = 0.5 * (data_parameters["tstart"] + tend)
 39 depth = 10.0
 40 signal_parameters = {
 41     "tref": data_parameters["tstart"],
 42     "F0": 40.0,
 43     "F1": 0,
 44     "F2": 0,
 45     "Alpha": 0.5,
 46     "Delta": 0.5,
 47     "period": 85 * 24 * 3600.0,
 48     "asini": 4.0,
 49     "tp": mid_time * 1.05,
 50     "argp": 0.0 if circular_orbit else 0.54,
 51     "ecc": 0.0 if circular_orbit else 0.7,
 52     "h0": data_parameters["sqrtSX"] / depth,
 53     "cosi": 1.0,
 54 }
 55
 56
 57 logger.info("Generating SFTs with injected signal...")
 58 writer = pyfstat.BinaryModulatedWriter(
 59     label=label + "SimulatedSignal",
 60     outdir=outdir,
 61     **data_parameters,
 62     **signal_parameters,
 63 )
 64 writer.make_data()
 65 logger.info("")
 66
 67 logger.info("Performing Grid Search...")
 68
 69 # Create ad-hoc grid and compute Fstatistic around injection point
 70 # There's no class supporting a binary search in the same way as
 71 # grid_based_searches.GridSearch, so we do it by hand constructing
 72 # a grid and using core.ComputeFstat.
 73 half_points_per_dimension = 2
 74 search_keys = ["period", "asini", "tp", "argp", "ecc"]
 75 search_keys_label = [
 76     r"$P$ [s]",
 77     r"$a_p$ [s]",
 78     r"$t_{p}$ [s]",
 79     r"$\omega$ [rad]",
 80     r"$e$",
 81 ]
 82
 83 grid_arrays = np.meshgrid(
 84     *[
 85         signal_parameters[key]
 86         * (
 87             1
 88             + 0.01
 89             * np.arange(-half_points_per_dimension, half_points_per_dimension + 1, 1)
 90         )
 91         for key in search_keys
 92     ]
 93 )
 94 grid_points = np.hstack(
 95     [grid_arrays[i].reshape(-1, 1) for i in range(len(grid_arrays))]
 96 )
 97
 98 compute_f_stat = pyfstat.ComputeFstat(
 99     sftfilepattern=writer.sftfilepath,
100     tref=signal_parameters["tref"],
101     binary=True,
102     minCoverFreq=-0.5,
103     maxCoverFreq=-0.5,
104 )
105 twoF_values = np.zeros(grid_points.shape[0])
106 for ind in range(grid_points.shape[0]):
107     point = grid_points[ind]
108     twoF_values[ind] = compute_f_stat.get_fullycoherent_twoF(
109         F0=signal_parameters["F0"],
110         F1=signal_parameters["F1"],
111         F2=signal_parameters["F2"],
112         Alpha=signal_parameters["Alpha"],
113         Delta=signal_parameters["Delta"],
114         period=point[0],
115         asini=point[1],
116         tp=point[2],
117         argp=point[3],
118         ecc=point[4],
119     )
120 logger.info(f"2Fstat computed on {grid_points.shape[0]} points")
121 logger.info("")
122 logger.info("Plotting results...")
123 dim = len(search_keys)
124 fig, ax = plt.subplots(dim, 1, figsize=(10, 10))
125 for ind in range(dim):
126     a = ax.ravel()[ind]
127     a.grid()
128     a.set(xlabel=search_keys_label[ind], ylabel=r"$2 \mathcal{F}$", yscale="log")
129     a.plot(grid_points[:, ind], twoF_values, "o")
130     a.axvline(signal_parameters[search_keys[ind]], label="Injection", color="orange")
131 plt.tight_layout()
132 fig.savefig(os.path.join(outdir, "grid_twoF_per_dimension.png"))
133
134
135 logger.info("Performing MCMCSearch...")
136 # Fixed points in frequency and sky parameters
137 theta_prior = {
138     "F0": signal_parameters["F0"],
139     "F1": signal_parameters["F1"],
140     "F2": signal_parameters["F2"],
141     "Alpha": signal_parameters["Alpha"],
142     "Delta": signal_parameters["Delta"],
143 }
144
145 # Set up priors for the binary parameters
146 for key in search_keys:
147     theta_prior.update(
148         {
149             key: {
150                 "type": "unif",
151                 "lower": 0.999 * signal_parameters[key],
152                 "upper": 1.001 * signal_parameters[key],
153             }
154         }
155     )
156 if circular_orbit:
157     for key in ["ecc", "argp"]:
158         theta_prior[key] = 0
159         search_keys.remove(key)
160
161 # ptemcee sampler settings - in a real application we might want higher values
162 ntemps = 2
163 log10beta_min = -1
164 nwalkers = 100
165 nsteps = [100, 100]  # [burn-in,production]
166
167 mcmcsearch = pyfstat.MCMCSearch(
168     label=label + "MCMCSearch",
169     outdir=outdir,
170     sftfilepattern=writer.sftfilepath,
171     theta_prior=theta_prior,
172     tref=signal_parameters["tref"],
173     nsteps=nsteps,
174     nwalkers=nwalkers,
175     ntemps=ntemps,
176     log10beta_min=log10beta_min,
177     binary=True,
178 )
179 # walker plot is generated during main run of the search class
180 mcmcsearch.run(
181     plot_walkers=True,
182     walker_plot_args={"plot_det_stat": True, "injection_parameters": signal_parameters},
183 )
184 mcmcsearch.print_summary()
185
186 # call some built-in plotting methods
187 # these can all highlight the injection parameters, too
188 logger.info("Making MCMCSearch {:s} corner plot...".format("-".join(search_keys)))
189 mcmcsearch.plot_corner(truths=signal_parameters)
190 logger.info("Making MCMCSearch prior-posterior comparison plot...")
191 mcmcsearch.plot_prior_posterior(injection_parameters=signal_parameters)
192 logger.info("")
193
194 logger.info("*" * 20)
195 logger.info("Quantitative comparisons:")
196 logger.info("*" * 20)
197
198 # some informative command-line output comparing search results and injection
199 # get max twoF and binary Doppler parameters
200 max_grid_index = np.argmax(twoF_values)
201 max_grid_2F = twoF_values[max_grid_index]
202 max_grid_parameters = grid_points[max_grid_index]
203
204 # same for MCMCSearch, here twoF is separate, and non-sampled parameters are not included either
205 max_dict_mcmc, max_2F_mcmc = mcmcsearch.get_max_twoF()
206 logger.info(
207     "Grid Search:\n\tmax2F={:.4f}\n\tOffsets from injection parameters (relative error): {:s}.".format(
208         max_grid_2F,
209         ", ".join(
210             [
211                 "\n\t\t{1:s}: {0:.4e} ({2:.4f}%)".format(
212                     max_grid_parameters[search_keys.index(key)]
213                     - signal_parameters[key],
214                     key,
215                     100
216                     * (
217                         max_grid_parameters[search_keys.index(key)]
218                         - signal_parameters[key]
219                     )
220                     / signal_parameters[key],
221                 )
222                 for key in search_keys
223             ]
224         ),
225     )
226 )
227 logger.info(
228     "Max 2F candidate from MCMC Search:\n\tmax2F={:.4f}"
229     "\n\tOffsets from injection parameters (relative error): {:s}.".format(
230         max_2F_mcmc,
231         ", ".join(
232             [
233                 "\n\t\t{1:s}: {0:.4e} ({2:.4f}%)".format(
234                     max_dict_mcmc[key] - signal_parameters[key],
235                     key,
236                     100
237                     * (max_dict_mcmc[key] - signal_parameters[key])
238                     / signal_parameters[key],
239                 )
240                 for key in search_keys
241             ]
242         ),
243     )
244 )
245 # get additional point and interval estimators
246 stats_dict_mcmc = mcmcsearch.get_summary_stats()
247 logger.info(
248     "Mean from MCMCSearch:\n\tOffset from injection parameters (relative error): {:s}"
249     "\n\tExpressed as fractions of 2sigma intervals: {:s}.".format(
250         ", ".join(
251             [
252                 "\n\t\t{1:s}: {0:.4e} ({2:.4f}%)".format(
253                     stats_dict_mcmc[key]["mean"] - signal_parameters[key],
254                     key,
255                     100
256                     * (stats_dict_mcmc[key]["mean"] - signal_parameters[key])
257                     / signal_parameters[key],
258                 )
259                 for key in search_keys
260             ]
261         ),
262         ", ".join(
263             [
264                 "\n\t\t{1:s}: {0:.4f}%".format(
265                     100
266                     * np.abs(stats_dict_mcmc[key]["mean"] - signal_parameters[key])
267                     / (2 * stats_dict_mcmc[key]["std"]),
268                     key,
269                 )
270                 for key in search_keys
271             ]
272         ),
273     )
274 )
275 logger.info(
276     "Median from MCMCSearch:\n\tOffset from injection parameters (relative error): {:s},"
277     "\n\tExpressed as fractions of 90% confidence intervals: {:s}.".format(
278         ", ".join(
279             [
280                 "\n\t\t{1:s}: {0:.4e} ({2:.4f}%)".format(
281                     stats_dict_mcmc[key]["median"] - signal_parameters[key],
282                     key,
283                     100
284                     * (stats_dict_mcmc[key]["median"] - signal_parameters[key])
285                     / signal_parameters[key],
286                 )
287                 for key in search_keys
288             ]
289         ),
290         ", ".join(
291             [
292                 "\n\t\t{1:s}: {0:.4f}%".format(
293                     100
294                     * np.abs(stats_dict_mcmc[key]["median"] - signal_parameters[key])
295                     / (
296                         stats_dict_mcmc[key]["upper90"]
297                         - stats_dict_mcmc[key]["lower90"]
298                     ),
299                     key,
300                 )
301                 for key in search_keys
302             ]
303         ),
304     )
305 )

Download Jupyter notebook: PyFstat_example_binary_mcmc_vs_grid_comparison.ipynb

Download Python source code: PyFstat_example_binary_mcmc_vs_grid_comparison.py

Download zipped: PyFstat_example_binary_mcmc_vs_grid_comparison.zip

Gallery generated by Sphinx-Gallery

Previous Next

© Copyright 2020, Gregory Ashton, David Keitel, Reinhard Prix, Rodrigo Tenorio.

Built with Sphinx using a theme provided by Read the Docs.