LALPulsar  6.1.0.1-89842e6
LineRobustStats.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011-2014 David Keitel
3  * Copyright (C) 2014 Reinhard Prix
4  * Copyright (C) 2017 Reinhard Prix
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with with program; see the file COPYING. If not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301 USA
20  */
21 
22 //---------- INCLUDES ----------
23 #include <lal/UserInputParse.h>
24 
25 #include <lal/LineRobustStats.h>
26 
27 
28 //---------- local DEFINES ----------
29 
30 //----- Macros -----
31 
32 // ---------- internal types ----------
33 // ----- module-internal global variables ----------
34 
35 // opaque internal setup structure for XLALComputeBSGL()
36 struct tagBSGLSetup {
38  REAL4 Fstar0sc; // semi-coherent Fstar0sc = Nseg * Fstar0coh
40  REAL4 C; // constant term C = Fstar0sc + ln(1-pL)
41  REAL4 ln_pLtL_X[PULSAR_MAX_DETECTORS]; // per-detector term ln(pX) = ln(oLGX) - ln(1+oLG)
42  REAL4 perSegTerm; // extra term for per-segment transient contributions, (Nseg - 1)*Fstar0sc/Nseg - ln(Nseg)
44 };
45 
46 // ---------- module-internal prototypes ----------
47 int
49  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS],
50  const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS],
51  const UINT4 len,
52  const BSGLSetup *setup
53  );
54 
55 /*==================== FUNCTION DEFINITIONS ====================*/
56 
57 /// \addtogroup LineRobustStats_h
58 /// @{
59 
60 /**
61  * \f[
62  * \newcommand{\coh}[1]{\widetilde{#1}}
63  * \newcommand{\Ndet}{N_{\mathrm{det}}}
64  * \newcommand{\F}{\mathcal{F}}
65  * \newcommand{\scF}{\hat{\F}}
66  * \newcommand{\cohFtho}{\coh{\F}_*^{(0)}}
67  * \newcommand{\scFtho}{\scF_*^{(0)}}
68  * \newcommand{\oLGX}{o_{\mathrm{LG}}^X}
69  * \newcommand{\Nseg}{N_{\mathrm{seg}}}
70  * \f]
71  * Pre-compute the 'setup' for XLALComputeBSGL() for given prior parameters \f$ \scFtho \f$ and \f$ \{\oLGX\} \f$ .
72  */
73 BSGLSetup *
74 XLALCreateBSGLSetup( const UINT4 numDetectors, //!< [in] number of detectors \f$ \Ndet \f$
75  const REAL4 Fstar0sc, //!< [in] (semi-coherent) prior transition-scale parameter \f$ \scFtho=\Nseg\cohFtho \f$
76  const REAL4 oLGX[PULSAR_MAX_DETECTORS], //!< [in] prior per-detector line odds \f$ \{\oLGX\} \f$ , if NULL: interpreted as \f$ \oLGX=\frac{1}{\Ndet} \forall X \f$
77  const BOOLEAN useLogCorrection, //!< [in] include log-term correction [slower] or not [faster, less accurate]
78  const UINT4 numSegments //!< [in] number of segments \f$ \Nseg \f$ in a semi-coherent search (=1 for coherent search)
79  )
80 {
81  // check input
82  XLAL_CHECK_NULL( ( numDetectors >= 2 ) && ( numDetectors <= PULSAR_MAX_DETECTORS ), XLAL_EDOM, "numDetectors = %d not within [2,%d]\n", numDetectors, PULSAR_MAX_DETECTORS );
83  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
84  XLAL_CHECK_NULL( ( oLGX == NULL ) || ( oLGX[X] >= 0 ), XLAL_EDOM );
85  }
86 
87  // create setup struct
88  BSGLSetup *setup;
89  XLAL_CHECK_NULL( ( setup = XLALCalloc( 1, sizeof( *setup ) ) ) != NULL, XLAL_ENOMEM );
90  setup->numDetectors = numDetectors;
91  setup->Fstar0sc = Fstar0sc;
92 
93  // Compute oLG from Eq.(22)
94  REAL4 oLG = 0.0;
95  REAL4 oLGX_default = 1.0 / numDetectors; // 'even odds': use oLGX=1/numDetectors for all X ==> oLG=1, pL=0.5
96  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
97  setup->oLGX[X] = ( oLGX != NULL ) ? oLGX[X] : oLGX_default;
98  oLG += setup->oLGX[X];
99  }
100 
101  // constant transition scale term
102  REAL4 ln_1_plus_oLG = logf( 1.0 + oLG ); // ln(1+oLG)
103  setup->C = Fstar0sc - ln_1_plus_oLG; // Fstar0sc + ln(1-pL) = Fstar0sc - ln(1+oLG)
104 
105  for ( UINT4 X = 0; X < numDetectors; X++ ) {
106  setup->ln_pLtL_X[X] = -LAL_REAL4_MAX; // fallback if oLGX==0 to avoid raising underflow
107  if ( setup->oLGX[X] > 0 ) {
108  setup->ln_pLtL_X[X] = logf( setup->oLGX[X] ) - ln_1_plus_oLG; // ln(oLGX) - ln(1+oLG)
109  }
110  }
111 
112  setup->perSegTerm = Fstar0sc * ( numSegments - 1 ) / numSegments - logf( numSegments );
113 
114  setup->useLogCorrection = useLogCorrection;
115 
116  return setup;
117 
118 } // XLALCreateBSGLSetup()
119 
120 void
121 XLALDestroyBSGLSetup( BSGLSetup *setup )
122 {
123  XLALFree( setup );
124  return;
125 } // XLALDestroyBSGLSetup()
126 
127 /**
128  * \f[
129  * \newcommand{\F}{\mathcal{F}}
130  * \newcommand{\FpMax}{\F^{\#}_{\mathrm{max}}}
131  * \newcommand{\Ndet}{N_{\mathrm{det}}}
132  * \newcommand{\Signal}{\mathrm{S}}
133  * \newcommand{\Gauss}{\mathrm{G}}
134  * \newcommand{\Line}{\mathrm{L}}
135  * \newcommand{\SGL}{{\Signal/\Gauss\Line}}
136  * \newcommand{\oLG}{o_{\Line/\Gauss}}
137  * \newcommand{\oLGX}{\oLG^X}
138  * \newcommand{\OSGL}{O_\SGL}
139  * \newcommand{\oSGL}{o_\SGL}
140  * \newcommand{\data}{\mathrm{data}}
141  * \newcommand{\pL}{p_\Line}
142  * \newcommand{\logten}{\log_{10}}
143  * \newcommand{\BSGL}{B_{\SGL}}
144  * \f]
145  * Compute the 'line-robust statistic' \f$ \logten \BSGL \f$ from multi-detector \f$ 2\F \f$ and single-detector \f$ \{2\F^X\} \f$ 'F-stat values'
146  * (coherent or semi-coherent sum) and a pre-computed 'setup' from XLALCreateBSGLSetup().
147  *
148  * \f$ \BSGL \f$ is the BayesFactor[Signal-vs-Gauss_OR_Line], i.e.
149  * \f$ \BSGL \equiv \frac{P(\data | \text{Signal})}{P(\data | \text{Gauss or Line})} \f$ , which is related to the odds ratio
150  * via \f$ \OSGL = \oSGL\,\BSGL \f$ in terms of the prior odds \f$ \oSGL \f$ .
151  *
152  * Here we use the odds ratio derived in Eq.(36) (and Eq.(55)) of \cite KPPLS2014 , from which we can obtain
153  * \f{equation}{
154  * \ln \BSGL = \F - \FpMax - \ln\left( e^{C - \FpMax} + \sum_X \pL^X \, e^{\F^X - \FpMax} \right) \,,
155  * \f}
156  * where \c setup->useLogCorrection controls whether or not to include the (usually small) log-correction of the last term,
157  * and we defined
158  * \f{equation}{ \FpMax \equiv \max\left[ C, \{ \F^X + \ln\pL^X \} \right] \f}
159  * and \f$ C,\{\ln\pL^X\} \f$ are the prior quantities pre-computed in XLALCreateBSGLSetup(), namely
160  * \f{align}{
161  * C &\equiv \scFtho + \ln(1-\pL) = \scFtho - \ln(1+\oLG)\,,\\
162  * \ln\pL^X &\equiv \ln \oLGX - \ln(1+\oLG)\,,
163  * \f}
164  * and we used the following relations from \cite KPPLS2014 :
165  * \f$ \oLG = \sum_X \oLGX \; \f$ [Eq.(22)],
166  * and \f$ \pL = \frac{\oLG}{1 + \oLG} \; \f$ [Eq.(37)].
167  *
168  * Here, \f$ \FpMax \f$ differs from \f$ \F''_{\mathrm{max}} \f$ from [Eq.(41)] by \f$ \ln\Ndet \f$ , due to summation instead of an average over detectors.
169  *
170  * \return NOTE: return is \f$ \logten B_\SGL = \ln B_\SGL \, \logten e \f$
171  *
172  */
173 int
174 XLALVectorComputeBSGL( REAL4 *outBSGL, //!< [out] pre-allocated output vector for returning BSGL
175  const REAL4 *twoF, //!< [in] input vector of multi-IFO 2F values
176  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS], //!< [in] input vector of per-IFO 2F[X] values
177  const UINT4 len, //!< [in] length of input/output vectors
178  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
179  )
180 {
181  XLAL_CHECK( ( outBSGL != NULL ) && ( twoF != NULL ) && ( twoFPerDet != NULL ) && ( setup != NULL ) && ( len >= 1 ), XLAL_EINVAL );
182 
183  for ( UINT4 i = 0; i < len; i ++ ) {
184  // --------------------------------------------------
185  REAL4 FpMax = setup->C; // used to keep track of log of maximal denominator sum-term
186 
187  // per-detector contributions, including line weights
189  for ( UINT4 X = 0; X < setup->numDetectors; X ++ ) {
190  Xterm[X] = 0.5f * twoFPerDet[X][i] + setup->ln_pLtL_X[X]; // FX + ln(pLtL_X) = FX + ln(pL_X) as ptL=0
191  FpMax = fmaxf( FpMax, Xterm[X] );
192  }
193 
194  outBSGL[i] = 0.5f * twoF[i] - FpMax; // approximate result without log-correction term
195 
196  if ( setup->useLogCorrection ) { // FIXME: indicate to gcc that this is the unlikely branch
197  // if useLogCorrection: extraSum = e^(Fstar0sc +ln(1-pL) - FpMax) + sum_X e^( Xterm[X] - FpMax )
198  REAL4 extraSum = expf( setup->C - FpMax );
199 
200  // ... and add all FX-contributions
201  for ( UINT4 X = 0; X < setup->numDetectors; X++ ) {
202  extraSum += expf( Xterm[X] - FpMax );
203  }
204  outBSGL[i] -= logf( extraSum ); // F - FpMax - ln( ... )
205  } // if useLogCorrection
206 
207  outBSGL[i] *= LAL_LOG10E; // return log10(B_SGL)
208 
209  } // for i < len
210 
211  return XLAL_SUCCESS;
212 
213 } // XLALVectorComputeBSGL()
214 
215 
216 /// Single-bin wrapper of XLALVectorComputeBSGL(), provided for backwards compatibility.
217 REAL4
218 XLALComputeBSGL( const REAL4 twoF, //!< [in] multi-detector F-stat \f$ 2\F \f$ (coherent or semi-coherent sum(!))
219  const REAL4 twoFX[PULSAR_MAX_DETECTORS], //!< [in] per-detector F-stats \f$ \{2\F^X\} \f$ (coherent or semi-coherent sum(!))
220  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
221  )
222 {
223  REAL4 outBSGL;
224  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS];
225  for ( UINT4 X = 0; X < setup->numDetectors; X ++ ) {
226  twoFPerDet[X] = &( twoFX[X] );
227  }
228  XLAL_CHECK_REAL4( XLALVectorComputeBSGL( &outBSGL, &twoF, twoFPerDet, 1, setup ) == XLAL_SUCCESS, XLAL_EFUNC );
229 
230  return outBSGL;
231 
232 } // XLALComputeBSGL()
233 
234 /**
235  * \f[
236  * \newcommand{\cohF}{\coh{\F}}
237  * \f]
238  * Helper function to compute the denominator for XLALVectorComputeBSGLtL() and XLALVectorComputeBtSGLtL() - see their documentation for details.
239  */
240 int
241 XLALVectorComputeGLtLDenominator( REAL4 *outDenom, //!< [out] pre-allocated output array of denominator values
242  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS], //!< [in] input vector of semi-coherent sums \f$ \{2\scF^X\} \f$ of per-detector F-stats
243  const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS],//!< [in] input vector of maxima over segments of \f$ \{\max\limits_{\ell}2\{\cohF^{X\ell}\}\} \f$ of per-detector F-stats
244  const UINT4 len, //!< [in] length of input/output vectors
245  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
246  )
247 {
248  XLAL_CHECK( ( outDenom != NULL ) && ( twoFPerDet != NULL ) && ( maxTwoFSegPerDet != NULL ) && ( setup != NULL ), XLAL_EINVAL );
249  XLAL_CHECK_REAL4( !setup->useLogCorrection, XLAL_EDOM, "log correction not implemented for GLtL denominator." );
250 
251  for ( UINT4 i = 0; i < len; i ++ ) {
252  REAL4 FpMax = setup->C; // used to keep track of log of maximal denominator sum-term
253 
254  // per-detector contributions, including line weights
256  REAL4 Xlterm[PULSAR_MAX_DETECTORS];
257  for ( UINT4 X = 0; X < setup->numDetectors; X ++ ) {
258  REAL4 ln_pLX = setup->ln_pLtL_X[X] - ( REAL4 )LAL_LN2; // ln(pLX) = ln(pLtLX/2), as we assume pLX=ptLX, so pLtLX = 2*pLX
259  Xterm[X] = 0.5f * twoFPerDet[X][i] + ln_pLX; // FX + ln(pLX)
260  FpMax = fmaxf( FpMax, Xterm[X] );
261  Xlterm[X] = 0.5f * maxTwoFSegPerDet[X][i] + setup->perSegTerm + ln_pLX; // assuming equal odds between segments: ptL_X = pL_X/Nseg
262  FpMax = fmaxf( FpMax, Xlterm[X] );
263  } // for X < numDetectors
264 
265  outDenom[i] = FpMax;
266  } // for i < len
267 
268  return XLAL_SUCCESS;
269 
270 } // XLALVectorComputeGLtLDenominator()
271 
272 /**
273  * \f[
274  * \newcommand{\sc}[1]{\widehat{#1}}
275  * \newcommand{\cohF}{\coh{\F}}
276  * \newcommand{\scF}{\sc{\F}}
277  * \newcommand{\denomterm}{\sc{D}}
278  * \newcommand{\denommax}{\denomterm_{\mathrm{max}}}
279  * \newcommand{\Transline}{{\mathrm{t\Line}}}
280  * \newcommand{\cppLX}{\sc{p}_{\Line}^X}
281  * \newcommand{\cppTLXk}{\coh{p}_{\Transline}^{X\ell}}
282  * \newcommand{\cppLTLsc}{\sc{p}_{\Line\Transline}}
283  * \newcommand{\denomtermset}{\mathcal{\denomterm}}
284  * \newcommand{\SGLtL}{{\Signal/\Gauss\Line\Transline}}
285  * \newcommand{\OSGLtL}{O_\SGLtL}
286  * \newcommand{\oSGLtL}{o_\SGLtL}
287  * \newcommand{\BSGLtL}{B_{\SGLtL}}
288  * \f]
289  * Compute the semi-coherent transient-line-robust CW detection statistic \f$ \logten \BSGLtL \f$
290  * from \cite Keitel2015 .
291  *
292  * As defined in Eq.(22), \f$ \BSGLtL \f$ is the BayesFactor for CW signals vs.
293  * either Gaussian noise, a persistent line or a transient line, i.e.
294  * \f$ \BSGLtL \equiv \frac{P(\data | \text{Signal})}{P(\data | \text{Gauss or Line or transient Line})} \f$ .
295  *
296  * This function returns an approximation of \f$ \logten \BSGLtL = \ln \BSGLtL \, \logten e \f$ ,
297  * with the general expression for \f$ \ln \BSGLtL \f$ given in Eq.(23) of \cite Keitel2015,
298  * while here we compute only the leading term
299  * \f{equation}{
300  * \ln \BSGLtL \approx \F - \denommax\,.
301  * \f}
302  *
303  *
304  * NOTE: In the current implementation, only
305  * \c setup->useLogCorrection == FALSE
306  * is accepted!
307  * In this case, the output is simply the maximum of the set of denominator exponents,
308  * \f{equation}{
309  * \denommax \equiv \max \left\{ \Nseg\cohFtho + \ln\left( 1-\cppLTLsc \right) ,\,
310  * \scF^X + \ln\cppLX ,\,
311  * \cohF^{X\ell} + (\Nseg-1)\cohFtho + \ln\cppTLXk
312  * \right\} \,,
313  * \f}
314  * with the simplifying assumption of equal prior odds for persistent and transient lines (with equal odds for all segments), ie.
315  * \f$ \cppTLXk = \cppLX / \Nseg \f$ , therefore \f$ \ln\cppTLXk = \ln\cppLX - \ln\Nseg \f$ .
316  *
317  */
318 int
319 XLALVectorComputeBSGLtL( REAL4 *outBSGLtL, //!< [out] pre-allocated vector for returning BSLGtL values
320  const REAL4 *twoF, //!< [in] vector of semi-coherent sum \f$ 2\scF \f$ of multi-detector F-stats
321  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS],//!< [in] vector of semi-coherent sums \f$ \{2\scF^X\} \f$ of per-detector F-stats
322  const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS], //!< [in] vector of maxima over segments of \f$ \{\max\limits_{\ell}2\{\cohF^{X\ell}\}\} \f$ of per-detector F-stats
323  const UINT4 len, //!< [in] length of input/output vectors
324  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
325  )
326 {
327  XLAL_CHECK( ( outBSGLtL != NULL ) && ( twoF != NULL ) && ( twoFPerDet != NULL ) && ( maxTwoFSegPerDet != NULL ) && ( setup != NULL ), XLAL_EFUNC );
328 
329  XLAL_CHECK( XLALVectorComputeGLtLDenominator( outBSGLtL, twoFPerDet, maxTwoFSegPerDet, len, setup ) == XLAL_SUCCESS, XLAL_EFUNC );
330  // outBSGLtL now holds 'GLtLDenominator'
331 
332  for ( UINT4 i = 0; i < len; i ++ ) {
333  outBSGLtL[i] -= 0.5f * twoF[i]; // GLtLDenominator - F;
334  outBSGLtL[i] *= -LAL_LOG10E; //convert to log10(B_SGLtL), flip sign
335  }
336 
337  return XLAL_SUCCESS;
338 
339 } // XLALVectorComputeBSGLtL()
340 
341 /// Single-bin wrapper of XLALVectorComputeBSGLtL(), provided for backwards compatibility.
342 REAL4
343 XLALComputeBSGLtL( const REAL4 twoF, //!< [in] semi-coherent sum \f$ 2\scF \f$ of multi-detector F-stats
344  const REAL4 twoFX[PULSAR_MAX_DETECTORS], //!< [in] semi-coherent sums \f$ \{2\scF^X\} \f$ of per-detector F-stats
345  const REAL4 maxtwoFlX[PULSAR_MAX_DETECTORS], //!< [in] maxima \f$ \{\max\limits_{\ell}2\{\cohF^{X\ell}\}\} \f$ of per-detector F-stats over segments
346  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
347  )
348 {
349  REAL4 outBSGLtL;
350  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS];
351  const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS];
352  for ( UINT4 X = 0; X < setup->numDetectors; X ++ ) {
353  twoFPerDet[X] = &( twoFX[X] );
354  maxTwoFSegPerDet[X] = &( maxtwoFlX[X] );
355  }
356  XLAL_CHECK_REAL4( XLALVectorComputeBSGLtL( &outBSGLtL, &twoF, twoFPerDet, maxTwoFSegPerDet, 1, setup ) == XLAL_SUCCESS, XLAL_EFUNC );
357 
358  return outBSGLtL;
359 
360 } // XLALComputeBSGLtL()
361 
362 /**
363  * \f[
364  * \newcommand{\Transsig}{{\mathrm{t\Signal}}}
365  * \newcommand{\tSGLtL}{{\Transsig/\Gauss\Line\Transline}}
366  * \newcommand{\BtSGLtL}{B_{\tSGLtL}}
367  * \newcommand{\OtSGLtL}{O_\tSGLtL}
368  * \newcommand{\otSGLtL}{o_\tSGLtL}
369  * \newcommand{\oTSGk}{\coh{o}_{\Transsig/\Gauss}^{\ell}}
370  * \f]
371  * Compute a semi-coherent transient-line-robust tCW detection statistic \f$ \logten \BtSGLtL \f$
372  * from \cite Keitel2015 .
373  *
374  * As defined in Eq.(40), \f$ \BtSGLtL \f$ is the BayesFactor for tCW signals vs.
375  * either Gaussian noise, a persistent line or a transient line, i.e.
376  * \f$ \BtSGLtL \equiv \frac{P(\data | \text{transient Signal})}{P(\data | \text{Gauss or Line or transient Line})} \f$ .
377  *
378  * This function returns an approximation of \f$ \logten \BtSGLtL = \ln \BtSGLtL \, \logten e \f$ ,
379  * computing only the leading term
380  * \f{equation}{
381  * \ln \BtSGLtL \approx \max_{\ell}\cohF^{\ell} + (\Nseg - 1)\cohFtho - \ln \Nseg - \denommax\,,
382  * \f}
383  * using the maximum multi-detector, single-segment F-stat value \f$ \max\cohF^{\ell} \f$ in the numerator,
384  * and the maximum \f$ \denommax \f$ of the set of denominator exponents, see the documentation of XLALVectorComputeBSGLtL() for its definition.
385  *
386  * NOTE: This implementation also assumes equal prior transient-signal odds for all segments.
387  *
388  */
389 int
390 XLALVectorComputeBtSGLtL( REAL4 *outBtSGLtL, //!< [out] pre-allocated vector for returning BtSGLtL values
391  const REAL4 *maxTwoFSeg, //!< [in] vector of maximum \f$ \max\limits_{\ell}2\cohF^\ell \f$ of multi-detector F-stats over segments
392  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS], //!< [in] vector of semi-coherent sums \f$ \{2\scF^X\} \f$ of per-detector F-stats
393  const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS], //!< [in] vector of maxima \f$ \{\max\limits_{\ell}2\{\cohF^{X\ell}\}\} \f$ of per-detector F-stats over segments
394  const UINT4 len, //!< [in] length of input/output vectors
395  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
396  )
397 {
398  XLAL_CHECK( ( outBtSGLtL != NULL ) && ( maxTwoFSeg != NULL ) && ( twoFPerDet != NULL ) && ( maxTwoFSegPerDet != NULL ) && ( setup != NULL ), XLAL_EFUNC );
399 
400  XLAL_CHECK( XLALVectorComputeGLtLDenominator( outBtSGLtL, twoFPerDet, maxTwoFSegPerDet, len, setup ) == XLAL_SUCCESS, XLAL_EFUNC ); // outBtSGLtL = GLtLDenominator
401 
402  for ( UINT4 i = 0; i < len; i ++ ) {
403  outBtSGLtL[i] -= 0.5f * maxTwoFSeg[i] + setup->perSegTerm; // outBtSGLtL = GLtLDenominator - (max_l F_l + perSegTerm)
404  outBtSGLtL[i] *= -LAL_LOG10E; // convert to log10 and flip sign
405  }
406 
407  return XLAL_SUCCESS;
408 
409 } // XLALVectorComputeBtSGLtL()
410 
411 /// Single-bin wrapper of XLALVectorComputeBtSGLtL(), provided for backwards compatibility.
412 REAL4
413 XLALComputeBtSGLtL( const REAL4 maxtwoFl, //!< [in] maximum \f$ \max\limits_{\ell}2\cohF^\ell \f$ of multi-detector F-stats over segments
414  const REAL4 twoFX[PULSAR_MAX_DETECTORS], //!< [in] semi-coherent sums \f$ \{2\scF^X\} \f$ of per-detector F-stats
415  const REAL4 maxtwoFXl[PULSAR_MAX_DETECTORS], //!< [in] maxima \f$ \{\max\limits_{\ell}2\{\cohF^{X\ell}\}\} \f$ of per-detector F-stats over segments
416  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
417  )
418 {
419  REAL4 outBtSGLtL;
420  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS];
421  const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS];
422  for ( UINT4 X = 0; X < setup->numDetectors; X ++ ) {
423  twoFPerDet[X] = &( twoFX[X] );
424  maxTwoFSegPerDet[X] = &( maxtwoFXl[X] );
425  }
426  XLAL_CHECK_REAL4( XLALVectorComputeBtSGLtL( &outBtSGLtL, &maxtwoFl, twoFPerDet, maxTwoFSegPerDet, 1, setup ) == XLAL_SUCCESS, XLAL_EFUNC );
427 
428  return outBtSGLtL;
429 } // XLALComputeBtSGLtL()
430 
431 /**
432  * \f[
433  * \newcommand{\StSGLtL}{{\Signal\Transsig\Gauss\Line\Transline}}
434  * \newcommand{\OStSGLtL}{O_\StSGLtL}
435  * \newcommand{\oStSGLtL}{o_\StSGLtL}
436  * \newcommand{\BStSGLtL}{B_{\StSGLtL}}
437  * \newcommand{\numerterm}{\sc{E}}
438  * \newcommand{\numertermset}{\mathcal{\numerterm}}
439  * \newcommand{\numermin}{\numerterm_{\mathrm{min}}}
440  * \newcommand{\numermax}{\numerterm_{\mathrm{max}}}
441  * \newcommand{\cppS}{\sc{p}_{\Signal}}
442  * \newcommand{\cppTS}{\coh{p}_{\Transsig}}
443  * \newcommand{\cppTSk}{\coh{p}_{\Transsig}^{\ell}}
444  * \f]
445  * Compute the semi-coherent transient-line-robust CW+tCW detection statistic \f$ \logten \BStSGLtL \f$
446  * from \cite Keitel2015 .
447  *
448  * As defined in Eq.(35), \f$ \BStSGLtL \f$ is the BayesFactor for either persistent CW or transient tCW signals vs.
449  * either Gaussian noise, a persistent line or a transient line, i.e.
450  * \f$ \BStSGLtL \equiv \frac{P(\data | \text{Signal or transient Signal})}{P(\data | \text{Gauss or Line or transient Line})} \f$ .
451  *
452  * This function returns an approximation of \f$ \logten \BStSGLtL = \ln \BStSGLtL \, \logten e \f$ ,
453  * with the general expression for \f$ \ln \BStSGLtL \f$ given in Eq.(36) of \cite Keitel2015 .
454  * Here we compute only the leading term
455  * \f{equation}{
456  * \ln \BStSGLtL \approx \numermax + \ln \left( 1 + e^{\numermin-\numermax} \right) - \denommax \,,
457  * \f}
458  *
459  * with the \f$ \denommax \f$ terms defined in the documentation of XLALVectorComputeBSGLtL(), and
460  *
461  * \f$ \numermax = \max \left\{ \scF, \max\limits_{\ell}\cohF^\ell + \cohFtho (\Nseg-1) - \ln \Nseg\right\} \f$ ,
462  * where we have assumed prior equal odds between persistent and transient signals and equal odds for all segments.
463  *
464  */
465 REAL4
466 XLALComputeBStSGLtL( const REAL4 twoF, //!< [in] semi-coherent sum \f$ 2\scF \f$ of multi-detector F-stats
467  const REAL4 maxtwoFl, //!< [in] maximum \f$ \max\limits_{\ell}2\cohF^\ell \f$ of multi-detector F-stats over segments
468  const REAL4 twoFX[PULSAR_MAX_DETECTORS], //!< [in] semi-coherent sums \f$ \{2\scF^X\} \f$ of per-detector F-stats
469  const REAL4 maxtwoFXl[PULSAR_MAX_DETECTORS], //!< [in] maxima \f$ \{\max\limits_{\ell}2\{\cohF^{X\ell}\}\} \f$ of per-detector F-stats over segments
470  const BSGLSetup *setup //!< [in] pre-computed setup from XLALCreateBSGLSetup()
471  )
472 {
473  XLAL_CHECK_REAL4( setup != NULL, XLAL_EINVAL );
474 
475  REAL4 GLtLDenominator;
476  const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS];
477  const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS];
478  for ( UINT4 X = 0; X < setup->numDetectors; X ++ ) {
479  twoFPerDet[X] = &( twoFX[X] );
480  maxTwoFSegPerDet[X] = &( maxtwoFXl[X] );
481  }
482  XLAL_CHECK_REAL4( XLALVectorComputeGLtLDenominator( &GLtLDenominator, twoFPerDet, maxTwoFSegPerDet, 1, setup ) == XLAL_SUCCESS, XLAL_EFUNC );
483 
484  const REAL4 ln_pS = -( REAL4 )LAL_LN2; // =ln(2) assuming equal odds between S and tS hypotheses: pS = ptS = 1/2, conditional on (S or tS)
485  REAL4 multiF = 0.5f * twoF + ln_pS;
486  REAL4 tsTerm = 0.5f * maxtwoFl + setup->perSegTerm + ln_pS; // ptS_l = ptS/Nseg = pS/Nseg
487  REAL4 maxNumerator = fmaxf( multiF, tsTerm );
488  REAL4 minNumerator = fminf( multiF, tsTerm );
489 
490  REAL4 ln_BStSGLtL = maxNumerator + logf( 1 + expf( minNumerator - maxNumerator ) ) - GLtLDenominator;
491 
492  return ln_BStSGLtL * LAL_LOG10E; // return log10(B_SGL)
493 
494 } // XLALComputeBStSGLtL()
495 
496 /**
497  * Parse string-vectors (typically input by user) of N per-detector line-to-Gaussian prior ratios
498  * \f$ o_{LG}^X = \frac{P(H_L^X)}{P(H_G^X)} \f$ to a flat array of REAL4s.
499  */
500 int
501 XLALParseLinePriors( REAL4 oLGX[PULSAR_MAX_DETECTORS], //!< [out] array of parsed \f$ o_{LG}^X \f$ values
502  const LALStringVector *oLGX_string //!< [in] string-list of \f$ o_{LG}^X \f$ values
503  )
504 {
505  XLAL_CHECK( oLGX != NULL, XLAL_EINVAL );
506  XLAL_CHECK( oLGX_string != NULL, XLAL_EINVAL );
507  UINT4 numDetectors = oLGX_string->length;
509 
510  // parse input string
511  for ( UINT4 X = 0; X < numDetectors; X ++ ) {
512  XLAL_CHECK( XLALParseStringValueAsREAL4( &oLGX[X], oLGX_string->data[X] ) == XLAL_SUCCESS, XLAL_EFUNC );
513  } // for X < numDetectors
514 
515  return XLAL_SUCCESS;
516 
517 } // XLALParseLinePriors()
518 
519 /// @}
#define LAL_LN2
#define LAL_REAL4_MAX
#define LAL_LOG10E
unsigned char BOOLEAN
uint32_t UINT4
float REAL4
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
int XLALVectorComputeBSGLtL(REAL4 *outBSGLtL, const REAL4 *twoF, const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS], const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS], const UINT4 len, const BSGLSetup *setup)
REAL4 XLALComputeBSGLtL(const REAL4 twoF, const REAL4 twoFX[PULSAR_MAX_DETECTORS], const REAL4 maxtwoFlX[PULSAR_MAX_DETECTORS], const BSGLSetup *setup)
Single-bin wrapper of XLALVectorComputeBSGLtL(), provided for backwards compatibility.
REAL4 XLALComputeBtSGLtL(const REAL4 maxtwoFl, const REAL4 twoFX[PULSAR_MAX_DETECTORS], const REAL4 maxtwoFXl[PULSAR_MAX_DETECTORS], const BSGLSetup *setup)
Single-bin wrapper of XLALVectorComputeBtSGLtL(), provided for backwards compatibility.
void XLALDestroyBSGLSetup(BSGLSetup *setup)
int XLALVectorComputeBSGL(REAL4 *outBSGL, const REAL4 *twoF, const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS], const UINT4 len, const BSGLSetup *setup)
REAL4 XLALComputeBStSGLtL(const REAL4 twoF, const REAL4 maxtwoFl, const REAL4 twoFX[PULSAR_MAX_DETECTORS], const REAL4 maxtwoFXl[PULSAR_MAX_DETECTORS], const BSGLSetup *setup)
BSGLSetup * XLALCreateBSGLSetup(const UINT4 numDetectors, const REAL4 Fstar0sc, const REAL4 oLGX[PULSAR_MAX_DETECTORS], const BOOLEAN useLogCorrection, const UINT4 numSegments)
REAL4 XLALComputeBSGL(const REAL4 twoF, const REAL4 twoFX[PULSAR_MAX_DETECTORS], const BSGLSetup *setup)
Single-bin wrapper of XLALVectorComputeBSGL(), provided for backwards compatibility.
int XLALVectorComputeGLtLDenominator(REAL4 *outDenom, const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS], const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS], const UINT4 len, const BSGLSetup *setup)
int XLALParseLinePriors(REAL4 oLGX[PULSAR_MAX_DETECTORS], const LALStringVector *oLGX_string)
Parse string-vectors (typically input by user) of N per-detector line-to-Gaussian prior ratios to a ...
int XLALVectorComputeBtSGLtL(REAL4 *outBtSGLtL, const REAL4 *maxTwoFSeg, const REAL4 *twoFPerDet[PULSAR_MAX_DETECTORS], const REAL4 *maxTwoFSegPerDet[PULSAR_MAX_DETECTORS], const UINT4 len, const BSGLSetup *setup)
#define PULSAR_MAX_DETECTORS
maximal number of detectors we can handle (for static arrays of detector quantities)
int XLALParseStringValueAsREAL4(REAL4 *valREAL4, const char *valString)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_REAL4(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
XLAL_EINVAL
size_t numDetectors
internal storage for setup and pre-computed BSGL quantities
REAL4 oLGX[PULSAR_MAX_DETECTORS]
REAL4 ln_pLtL_X[PULSAR_MAX_DETECTORS]
BOOLEAN useLogCorrection