From fea5d7c39da5dc1ac65f4fe292df34f722a4e2e6 Mon Sep 17 00:00:00 2001
From: "gregory.ashton" <gregory.ashton@ligo.org>
Date: Fri, 21 Apr 2017 13:43:27 +0200
Subject: [PATCH] Adds sliding window search

A search, based on Reinhard's J0537-6910 work, in which the search is
performed over F0 in a sliding window. Able to track changes in the
power and frequency of the signal.
---
 examples/sliding_window.py     |  35 +++++++++++
 pyfstat/__init__.py            |   2 +-
 pyfstat/grid_based_searches.py | 104 +++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 examples/sliding_window.py

diff --git a/examples/sliding_window.py b/examples/sliding_window.py
new file mode 100644
index 0000000..34b4311
--- /dev/null
+++ b/examples/sliding_window.py
@@ -0,0 +1,35 @@
+import pyfstat
+import numpy as np
+
+# Properties of the GW data
+sqrtSX = 1e-23
+tstart = 1000000000
+duration = 100*86400
+tend = tstart + duration
+
+# Properties of the signal
+F0 = 30.0
+F1 = -1e-10
+F2 = 0
+Alpha = np.radians(83.6292)
+Delta = np.radians(22.0144)
+tref = .5*(tstart+tend)
+
+depth = 60
+h0 = sqrtSX / depth
+data_label = 'sliding_window'
+
+data = pyfstat.Writer(
+    label=data_label, outdir='data', tref=tref,
+    tstart=tstart, F0=F0, F1=F1, F2=F2, duration=duration, Alpha=Alpha,
+    Delta=Delta, h0=h0, sqrtSX=sqrtSX)
+data.make_data()
+
+DeltaF0 = 1e-5
+search = pyfstat.FrequencySlidingWindow(
+        label='sliding_window', outdir='data', sftfilepath='data/*sliding_window*sft',
+        F0s=[F0-DeltaF0, F0+DeltaF0, DeltaF0/100.], F1=F1, F2=0,
+        Alpha=Alpha, Delta=Delta, tref=tref, minStartTime=tstart,
+        maxStartTime=tend, window_size=25*86400, window_delta=1*86400)
+search.run()
+search.plot_sliding_window()
diff --git a/pyfstat/__init__.py b/pyfstat/__init__.py
index 139e97b..3ada8dc 100644
--- a/pyfstat/__init__.py
+++ b/pyfstat/__init__.py
@@ -2,5 +2,5 @@ from __future__ import division as _division
 
 from .core import BaseSearchClass, ComputeFstat, Writer, SemiCoherentSearch, SemiCoherentGlitchSearch
 from .mcmc_based_searches import MCMCSearch, MCMCGlitchSearch, MCMCSemiCoherentSearch, MCMCFollowUpSearch, MCMCTransientSearch
-from .grid_based_searches import GridSearch, GridUniformPriorSearch, GridGlitchSearch
+from .grid_based_searches import GridSearch, GridUniformPriorSearch, GridGlitchSearch, FrequencySlidingWindow
 
diff --git a/pyfstat/grid_based_searches.py b/pyfstat/grid_based_searches.py
index b59c478..ea078e8 100644
--- a/pyfstat/grid_based_searches.py
+++ b/pyfstat/grid_based_searches.py
@@ -326,4 +326,108 @@ class GridGlitchSearch(GridSearch):
         self.input_data = np.array(input_data)
 
 
+class FrequencySlidingWindow(GridSearch):
+    """ A sliding-window search over the Frequency """
+    @helper_functions.initializer
+    def __init__(self, label, outdir, sftfilepath, F0s, F1, F2,
+                 Alpha, Delta, tref, minStartTime=None,
+                 maxStartTime=None, window_size=10*86400, window_delta=86400,
+                 BSGL=False, minCoverFreq=None, maxCoverFreq=None,
+                 earth_ephem=None, sun_ephem=None, detectors=None):
+        """
+        Parameters
+        ----------
+        label, outdir: str
+            A label and directory to read/write data from/to
+        sftfilepath: str
+            File patern to match SFTs
+        F0s: array
+            Frequency range
+        F1, F2, Alpha, Delta: float
+            Fixed values to compute twoF(F) over
+        tref, minStartTime, maxStartTime: int
+            GPS seconds of the reference time, start time and end time
+
+        For all other parameters, see `pyfstat.ComputeFStat` for details
+        """
+
+        if earth_ephem is None:
+            self.earth_ephem = self.earth_ephem_default
+        if sun_ephem is None:
+            self.sun_ephem = self.sun_ephem_default
+
+        if os.path.isdir(outdir) is False:
+            os.mkdir(outdir)
+        self.out_file = '{}/{}_gridFS.txt'.format(self.outdir, self.label)
+        self.nsegs = 1
+        self.F1s = [F1]
+        self.F2s = [F2]
+        self.Alphas = [Alpha]
+        self.Deltas = [Delta]
 
+    def inititate_search_object(self):
+        logging.info('Setting up search object')
+        self.search = ComputeFstat(
+            tref=self.tref, sftfilepath=self.sftfilepath,
+            minCoverFreq=self.minCoverFreq, maxCoverFreq=self.maxCoverFreq,
+            earth_ephem=self.earth_ephem, sun_ephem=self.sun_ephem,
+            detectors=self.detectors, transient=True,
+            minStartTime=self.minStartTime, maxStartTime=self.maxStartTime,
+            BSGL=self.BSGL)
+        self.search.get_det_stat = (
+            self.search.run_computefstatistic_single_point)
+
+    def get_input_data_array(self):
+        arrays = []
+        tstarts = [self.minStartTime]
+        while tstarts[-1] + self.window_size < self.maxStartTime:
+            tstarts.append(tstarts[-1]+self.window_delta)
+        arrays = [tstarts]
+        for tup in (self.F0s, self.F1s, self.F2s,
+                    self.Alphas, self.Deltas):
+            arrays.append(self.get_array_from_tuple(tup))
+
+        input_data = []
+        for vals in itertools.product(*arrays):
+            input_data.append(vals)
+
+        input_data = np.array(input_data)
+        input_data = np.insert(
+            input_data, 1, input_data[:, 0] + self.window_size, axis=1)
+
+        self.arrays = arrays
+        self.input_data = np.array(input_data)
+
+    def plot_sliding_window(self, F0=None, ax=None, savefig=True,
+                            colorbar=True):
+        data = self.data
+        if ax is None:
+            ax = plt.subplot()
+        tstarts = np.unique(data[:, 0])
+        tends = np.unique(data[:, 1])
+        frequencies = np.unique(data[:, 2])
+        twoF = data[:, -1]
+        tmids = (tstarts + tends) / 2.0
+        dts = (tmids - self.minStartTime) / 86400.
+        if F0:
+            frequencies = frequencies - F0
+            ax.set_ylabel('Frequency - $f_0$ [Hz]')
+        else:
+            ax.set_ylabel('Frequency [Hz]')
+        twoF = twoF.reshape((len(tmids), len(frequencies)))
+        Y, X = np.meshgrid(frequencies, dts)
+        pax = ax.pcolormesh(X, Y, twoF)
+        if colorbar:
+            cb = plt.colorbar(pax, ax=ax)
+            cb.set_label('$2\mathcal{F}$')
+        ax.set_xlabel(
+            r'Days from $t_\mathrm{{start}}$={}'.format(self.minStartTime))
+        ax.set_title(
+            'Sliding window length = {} days in increments of {} days'
+            .format(self.window_size/86400, self.window_delta/86400))
+        if savefig:
+            plt.tight_layout()
+            plt.savefig(
+                '{}/{}_sliding_window.png'.format(self.outdir, self.label))
+        else:
+            return ax
-- 
GitLab