LALPulsar  6.1.0.1-89842e6
TransientCW_utils.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 Reinhard Prix, Stefanos Giampanis
3  * Copyright (C) 2009 Reinhard Prix
4  * Copyright (C) 2017-2020 David Keitel
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 /*********************************************************************************/
23 /**
24  * \author R. Prix, S. Giampanis
25  * \file
26  * \brief
27  * Some helper functions useful for "transient CWs", mostly applying transient window
28  * functions.
29  *
30  */
31 #include "config.h"
32 
33 /* System includes */
34 #include <math.h>
35 
36 /* LAL-includes */
37 #include <lal/XLALError.h>
38 #include <lal/Date.h>
39 #include <lal/AVFactories.h>
40 #include <lal/LogPrintf.h>
41 #include <lal/LALString.h>
42 
43 #include <lal/ProbabilityDensity.h>
44 #include <lal/TransientCW_utils.h>
45 #include "ComputeFstat_internal.h"
46 
47 /* ----- MACRO definitions ---------- */
48 
49 /* ----- module-local fast lookup-table handling of negative exponentials ----- */
50 /**
51  * Lookup-table for negative exponentials e^(-x)
52  * Holds an array 'data' of 'length' for values e^(-x) for x in the range [0, xmax]
53  */
54 #define EXPLUT_XMAX 20.0 // LUT down to e^(-20) = 2.0612e-09
55 #define EXPLUT_LENGTH 2000 // number of LUT values to pre-compute
56 static gsl_vector *expLUT = NULL; /**< module-global lookup-table for negative exponentials e^(-x) */
57 #define EXPLUT_DXINV ((EXPLUT_LENGTH)/(EXPLUT_XMAX)) // 1/dx with dx = xmax/length
58 
59 static int XLALCreateExpLUT( void ); /* only ever used internally, destructor is in exported API */
60 
61 static const char *transientWindowNames[TRANSIENT_LAST] = {
62  [TRANSIENT_NONE] = "none",
63  [TRANSIENT_RECTANGULAR] = "rect",
64  [TRANSIENT_EXPONENTIAL] = "exp"
65 };
66 
67 /* ==================== function definitions ==================== */
68 
69 /// \addtogroup TransientCW_utils_h
70 /// @{
71 
72 /// Parse a transient window name string into the corresponding transientWindowType
73 int
74 XLALParseTransientWindowName( const char *windowName )
75 {
76  XLAL_CHECK( windowName != NULL, XLAL_EINVAL );
77 
78  // convert input window-name into lower-case first
79  char windowNameLC [ strlen( windowName ) + 1 ];
80  strcpy( windowNameLC, windowName );
81  XLALStringToLowerCase( windowNameLC );
82 
83  int winType = -1;
84  for ( UINT4 j = 0; j < TRANSIENT_LAST; j ++ ) {
85  if ( !strcmp( windowNameLC, transientWindowNames[j] ) ) {
86  winType = j;
87  break;
88  }
89  } // j < TRANSIENT_LAST
90 
91  if ( winType == -1 ) {
92  XLALPrintError( "Invalid transient Window-name '%s', allowed are (case-insensitive): [%s", windowName, transientWindowNames[0] );
93  for ( UINT4 j = 1; j < TRANSIENT_LAST; j ++ ) {
95  }
96  XLALPrintError( "]\n" );
98  } // if windowName not valid
99 
100  return winType;
101 
102 } // XLALParseTransientWindowName()
103 
104 /**
105  * Helper-function to determine the total timespan of
106  * a transient CW window, ie. the earliest and latest timestamps
107  * of non-zero window function.
108  */
109 int
110 XLALGetTransientWindowTimespan( UINT4 *t0, /**< [out] window start-time */
111  UINT4 *t1, /**< [out] window end-time */
112  transientWindow_t transientWindow /**< [in] window-parameters */
113  )
114 {
115  /* check input consistency */
116  if ( !t0 || !t1 ) {
117  XLALPrintError( "%s: invalid NULL input 't0=%p', 't1=%p'\n", __func__, t0, t1 );
119  }
120 
121  UINT4 win_t0 = transientWindow.t0;
122  UINT4 win_tau = transientWindow.tau;
123 
124  switch ( transientWindow.type ) {
125  case TRANSIENT_NONE:
126  ( *t0 ) = 0;
127  ( *t1 ) = LAL_INT4_MAX;
128  break;
130  ( *t0 ) = win_t0;
131  /* for given tau, what Tcoh does should the exponential window cover?
132  * for speed reasons we want to truncate Tcoh = tau * TRANSIENT_EXP_EFOLDING
133  * with the e-folding factor chosen such that the window-value
134  * is practically negligible after that, where it will be set to 0
135  */
136  ( *t1 ) = lround( win_t0 + TRANSIENT_EXP_EFOLDING * win_tau );
137  break;
139  ( *t0 ) = win_t0;
140  ( *t1 ) = win_t0 + win_tau;
141  break;
142  default:
143  XLALPrintError( "invalid transient window type %d not in [%d, %d].\n",
144  transientWindow.type, TRANSIENT_NONE, TRANSIENT_LAST - 1 );
146 
147  } /* switch window-type */
148 
149  return XLAL_SUCCESS;
150 
151 } /* XLALGetTransientWindowTimespan() */
152 
153 
154 /**
155  * apply a "transient CW window" described by TransientWindowParams to the given
156  * timeseries
157  */
158 int
159 XLALApplyTransientWindow( REAL4TimeSeries *series, /**< input timeseries to apply window to */
160  transientWindow_t transientWindow /**< transient-CW window to apply */
161  )
162 {
163  /* check input consistency */
164  if ( !series || !series->data ) {
165  XLALPrintError( "%s: Illegal NULL in input timeseries!\n", __func__ );
167  }
168 
169  /* special time-saving break-condition: do nothing for window=none */
170  if ( transientWindow.type == TRANSIENT_NONE ) {
171  return XLAL_SUCCESS;
172  }
173 
174  /* deal with non-trivial windows */
175  UINT4 ts_t0 = series->epoch.gpsSeconds;
176  UINT4 ts_length = series->data->length;
177  REAL8 ts_dt = series->deltaT;
178 
179  UINT4 t0, t1;
180  if ( XLALGetTransientWindowTimespan( &t0, &t1, transientWindow ) != XLAL_SUCCESS ) {
181  XLALPrintError( "%s: XLALGetTransientWindowTimespan() failed.\n", __func__ );
183  }
184 
185  UINT4 i;
186  switch ( transientWindow.type ) {
188  for ( i = 0; i < ts_length; i ++ ) {
189  UINT4 ti = lround( ts_t0 + i * ts_dt );
190  if ( ti < t0 || ti > t1 ) { // outside rectangular window: set to zero
191  series->data->data[i] = 0;
192  } // otherwise do nothing
193  } /* for i < length */
194  break;
195 
197  for ( i = 0; i < ts_length; i ++ ) {
198  UINT4 ti = lround( ts_t0 + i * ts_dt );
199  REAL8 win = XLALGetExponentialTransientWindowValue( ti, t0, t1, transientWindow.tau );
200  series->data->data[i] *= win;
201  } /* for i < length */
202  break;
203 
204  default:
205  XLALPrintError( "%s: invalid transient window type %d not in [%d, %d].\n",
206  __func__, transientWindow.type, TRANSIENT_NONE, TRANSIENT_LAST - 1 );
208  break;
209 
210  } /* switch (window.type) */
211 
212  return XLAL_SUCCESS;
213 
214 } /* XLALApplyTransientWindow() */
215 
216 
217 /**
218  * apply transient window to give multi noise-weights, associated with given
219  * multi timestamps
220  */
221 int
222 XLALApplyTransientWindow2NoiseWeights( MultiNoiseWeights *multiNoiseWeights, /**< [in/out] noise weights to apply transient window to */
223  const MultiLIGOTimeGPSVector *multiTS, /**< [in] associated timestamps of noise-weights */
224  transientWindow_t transientWindow /**< [in] transient window parameters */
225  )
226 {
227  UINT4 numIFOs, X;
228  UINT4 numTS, i;
229 
230  /* check input consistency */
231  if ( !multiNoiseWeights || multiNoiseWeights->length == 0 ) {
232  XLALPrintError( "%s: empty or NULL input 'multiNoiseWeights'.\n", __func__ );
234  }
235  if ( !multiTS || multiTS->length == 0 ) {
236  XLALPrintError( "%s: empty or NULL input 'multiTS'.\n", __func__ );
238  }
239 
240  numIFOs = multiNoiseWeights->length;
241  if ( multiTS->length != numIFOs ) {
242  XLALPrintError( "%s: inconsistent numIFOs between 'multiNoiseWeights' (%d) and 'multiTS' (%d).\n", __func__, numIFOs, multiTS->length );
244  }
245 
246  /* special time-saving break-condition: do nothing for window=none */
247  if ( transientWindow.type == TRANSIENT_NONE ) {
248  return XLAL_SUCCESS;
249  }
250 
251  /* deal with non-trivial windows */
252  UINT4 t0, t1;
253  if ( XLALGetTransientWindowTimespan( &t0, &t1, transientWindow ) != XLAL_SUCCESS ) {
254  XLALPrintError( "%s: XLALGetTransientWindowTimespan() failed.\n", __func__ );
256  }
257 
258  /* loop over all detectors X */
259  for ( X = 0; X < numIFOs; X ++ ) {
260  numTS = multiNoiseWeights->data[X]->length;
261 
262  if ( multiTS->data[X]->length != numTS ) {
263  XLALPrintError( "%s: inconsistent number of timesteps 'multiNoiseWeights[%d]' (%d) and 'multiTS[%d]' (%d).\n", __func__, X, numTS, X, multiTS->data[X]->length );
265  }
266 
267  switch ( transientWindow.type ) {
269  for ( i = 0; i < numTS; i ++ ) {
270  UINT4 ti = multiTS->data[X]->data[i].gpsSeconds;
272  multiNoiseWeights->data[X]->data[i] *= win;
273  } /* for i < length */
274  break;
275 
277  for ( i = 0; i < numTS; i ++ ) {
278  UINT4 ti = multiTS->data[X]->data[i].gpsSeconds;
279  REAL8 win = XLALGetExponentialTransientWindowValue( ti, t0, t1, transientWindow.tau );
280  multiNoiseWeights->data[X]->data[i] *= win;
281  } /* for i < length */
282  break;
283 
284  default:
285  XLALPrintError( "%s: invalid transient window type %d not in [%d, %d].\n",
286  __func__, transientWindow.type, TRANSIENT_NONE, TRANSIENT_LAST - 1 );
288  break;
289 
290  } /* switch (window.type) */
291 
292  } /* for X < numIFOs */
293 
294  return XLAL_SUCCESS;
295 
296 } /* XLALApplyTransientWindow2NoiseWeights() */
297 
298 
299 /**
300  * Turn pulsar doppler-params into a single string that can be used for filenames
301  * The format is
302  * tRefNNNNNN_RAXXXXX_DECXXXXXX_FreqXXXXX[_f1dotXXXXX][_f2dotXXXXx][_f3dotXXXXX]
303  */
304 CHAR *
306 {
307 #define MAXLEN 1024
308  CHAR buf[MAXLEN];
309  CHAR *ret = NULL;
310  int len;
311  UINT4 i;
312 
313  if ( !par ) {
314  LogPrintf( LOG_CRITICAL, "%s: NULL params input.\n", __func__ );
316  }
317 
318  len = snprintf( buf, MAXLEN, "tRef%09d_RA%.9g_DEC%.9g_Freq%.15g",
319  par->refTime.gpsSeconds,
320  par->Alpha,
321  par->Delta,
322  par->fkdot[0] );
323  if ( len >= MAXLEN ) {
324  LogPrintf( LOG_CRITICAL, "%s: filename-size (%d) exceeded maximal length (%d): '%s'!\n", __func__, len, MAXLEN, buf );
326  }
327 
328  for ( i = 1; i < PULSAR_MAX_SPINS; i++ ) {
329  if ( par->fkdot[i] ) {
330  CHAR buf1[MAXLEN];
331  len = snprintf( buf1, MAXLEN, "%s_f%ddot%.7g", buf, i, par->fkdot[i] );
332  if ( len >= MAXLEN ) {
333  LogPrintf( LOG_CRITICAL, "%s: filename-size (%d) exceeded maximal length (%d): '%s'!\n", __func__, len, MAXLEN, buf1 );
335  }
336  strcpy( buf, buf1 );
337  }
338  }
339 
340  if ( par->asini > 0 ) {
341  LogPrintf( LOG_NORMAL, "%s: orbital params not supported in Doppler-filenames yet\n", __func__ );
342  }
343 
344  len = strlen( buf ) + 1;
345  if ( ( ret = LALMalloc( len ) ) == NULL ) {
346  LogPrintf( LOG_CRITICAL, "%s: failed to LALMalloc(%d)!\n", __func__, len );
348  }
349 
350  strcpy( ret, buf );
351 
352  return ret;
353 } /* PulsarDopplerParams2String() */
354 
355 
356 /**
357  * Compute transient-CW Bayes-factor B_SG = P(x|HypS)/P(x|HypG) (where HypG = Gaussian noise hypothesis),
358  * marginalized over start-time and timescale of transient CW signal, using given type and parameters
359  * of transient window range.
360  *
361  * Note: this function is a C-implemention, partially based-on/inspired-by Stefanos Giampanis'
362  * original matlab implementation of this search function.
363  *
364  * Note2: if window->type == none, uses a single rectangular window covering all the data.
365  */
366 REAL8
367 XLALComputeTransientBstat( transientWindowRange_t windowRange, /**< [in] type and parameters specifying transient window range */
368  const transientFstatMap_t *FstatMap /**< [in] pre-computed transient-Fstat map F_mn over {t0, tau} ranges */
369  )
370 {
371  /* ----- check input consistency */
372  if ( !FstatMap || !FstatMap->F_mn ) {
373  XLALPrintError( "%s: invalid NULL input 'FstatMap' or 'FstatMap->F_mn'\n", __func__ );
375  }
376  if ( windowRange.type >= TRANSIENT_LAST ) {
377  XLALPrintError( "%s: unknown window-type (%d) passes as input. Allowed are [0,%d].\n", __func__, windowRange.type, TRANSIENT_LAST - 1 );
379  }
380 
381  /* ----- step through F_mn array subtract maxF and sum e^{F_mn - maxF}*/
382  /*
383  * The maximum-likelihood Fmax is globally subtracted from F_mn, and stored separatedly in the struct, because in most
384  * expressions it is numerically more robust to compute e^(F_mn - Fmax), which at worst can underflow, while
385  * e^F_mn can overflow (for F>~700). The constant offset e^Fmax is irrelevant for posteriors (normalization constant), or
386  * can be handled separately, eg by computing log(B) = Fmax + log(sum e^(Fmn-Fmax)) for the Bayes-factor.
387  */
388  UINT4 N_t0Range = FstatMap->F_mn->size1;
389  UINT4 N_tauRange = FstatMap->F_mn->size2;
390  UINT4 m, n;
391  REAL8 sum_eB = 0;
392  for ( m = 0; m < N_t0Range; m ++ ) {
393  for ( n = 0; n < N_tauRange; n ++ ) {
394  REAL8 DeltaF = FstatMap->maxF - gsl_matrix_get( FstatMap->F_mn, m, n ); // always >= 0, exactly ==0 at {m,n}_max
395 
396  //sum_eB += exp ( - DeltaF );
397  sum_eB += XLALFastNegExp( DeltaF );
398 
399  } /* for n < N_tauRange */
400 
401  } /* for m < N_t0Range */
402 
403  /* combine this to final log(Bstat) result with proper normalization (assuming rhohMax=1) : */
404 
405  REAL8 logBhat = FstatMap->maxF + log( sum_eB ); // unnormalized Bhat
406 
407  REAL8 normBh = 70.0 / ( N_t0Range * N_tauRange ); // normalization factor assuming rhohMax=1
408 
409  /* final normalized Bayes factor, assuming rhohMax=1 */
410  /* NOTE: correct this for different rhohMax by adding "- 4 * log(rhohMax)" to logB*/
411  REAL8 logBstat = log( normBh ) + logBhat; /* - 4.0 * log ( rhohMax ) */
412 
413  // printf ( "\n\nlogBhat = %g, normBh = %g, log(normBh) = %g\nN_t0Range = %d, N_tauRange=%d\n\n", logBhat, normBh, log(normBh), N_t0Range, N_tauRange );
414 
415  /* free mem */
417 
418  /* ----- return ----- */
419  return logBstat;
420 
421 } /* XLALComputeTransientBstat() */
422 
423 /**
424  * Compute transient-CW posterior (normalized) on start-time t0, using given type and parameters
425  * of transient window range.
426  *
427  * NOTE: the returned pdf has a number of sample-points N_t0Range given by the size
428  * of the input matrix FstatMap (namely N_t0Range = t0Band / dt0)
429  *
430  */
431 pdf1D_t *
432 XLALComputeTransientPosterior_t0( transientWindowRange_t windowRange, /**< [in] type and parameters specifying transient window range */
433  const transientFstatMap_t *FstatMap /**< [in] pre-computed transient-Fstat map F_mn over {t0, tau} ranges */
434  )
435 {
436  /* ----- check input consistency */
437  if ( !FstatMap || !FstatMap->F_mn ) {
438  XLALPrintError( "%s: invalid NULL input 'FstatMap' or 'FstatMap->F_mn'\n", __func__ );
440  }
441  if ( windowRange.type >= TRANSIENT_LAST ) {
442  XLALPrintError( "%s: unknown window-type (%d) passes as input. Allowed are [0,%d].\n", __func__, windowRange.type, TRANSIENT_LAST - 1 );
444  }
445 
446  /* ----- step through F_mn array subtract maxF and sum e^{F_mn - maxF}*/
447  /*
448  * It is numerically more robust to marginalize over e^(F_mn - Fmax), which at worst can underflow, while
449  * e^F_mn can overflow (for F>~700). The constant offset e^Fmax is irrelevant for posteriors (normalization constant).
450  */
451  UINT4 N_t0Range = FstatMap->F_mn->size1;
452  UINT4 N_tauRange = FstatMap->F_mn->size2;
453 
454  REAL8 t0 = windowRange.t0;
455  REAL8 t1 = t0 + windowRange.t0Band;
456 
457  pdf1D_t *ret;
458 
459  /* ----- handle special cases: 1) point-like support, 2) uniform pdf-value over 1 bin ----- */
460  if ( N_t0Range == 1 && ( windowRange.t0Band == 0 ) ) {
461  if ( ( ret = XLALCreateSingularPDF1D( t0 ) ) == NULL ) {
462  XLALPrintError( "%s: failed to create singular pdf for t0 = %g\n", __func__, t0 );
464  }
465  return ret;
466  } /* if singular pdf in t0 */
467  if ( ( N_t0Range == 1 ) && ( windowRange.t0Band > 0 ) ) {
468  if ( ( ret = XLALCreateUniformPDF1D( t0, t1 ) ) == NULL ) {
469  XLALPrintError( "%s: failed to created unform pdf over [%g, %g]\n", __func__, t0, t1 );
471  }
472  return ret;
473  } /* if uniform pdf over small band t0Band */
474 
475  /* ----- general N>1 point pdf case ----- */
476  if ( ( ret = XLALCreateDiscretePDF1D( t0, t1, N_t0Range ) ) == NULL ) {
477  XLALPrintError( "%s: XLALCreateDiscretePDF1D() failed with xlalErrno = %d\n", __func__, xlalErrno );
479  }
480 
481  UINT4 m, n;
482  for ( m = 0; m < N_t0Range; m ++ ) { /* loop over start-times t0 */
483  REAL8 sum_eF = 0;
484  for ( n = 0; n < N_tauRange; n ++ ) { /* loop over timescales tau */
485  REAL8 DeltaF = FstatMap->maxF - gsl_matrix_get( FstatMap->F_mn, m, n ); // always >= 0, exactly ==0 at {m,n}_max
486 
487  //sum_eB += exp ( - DeltaF );
488  sum_eF += XLALFastNegExp( DeltaF );
489 
490  } /* for n < N_tauRange */
491 
492  ret->probDens->data[m] = sum_eF;
493 
494  } /* for m < N_t0Range */
495 
496  /* free mem */
498 
499  /* normalize this PDF */
500  if ( XLALNormalizePDF1D( ret ) != XLAL_SUCCESS ) {
501  XLALPrintError( "%s: failed to normalize posterior pdf ..\n", __func__ );
503  }
504 
505  /* ----- return ----- */
506  return ret;
507 
508 } /* XLALComputeTransientPosterior_t0() */
509 
510 /**
511  * Compute transient-CW posterior (normalized) on timescale tau, using given type and parameters
512  * of transient window range.
513  *
514  * NOTE: the returned pdf has a number of sample-points N_tauRange given by the size
515  * of the input matrix FstatMap (namely N_tauRange = tauBand / dtau)
516  *
517  */
518 pdf1D_t *
519 XLALComputeTransientPosterior_tau( transientWindowRange_t windowRange, /**< [in] type and parameters specifying transient window range */
520  const transientFstatMap_t *FstatMap /**< [in] pre-computed transient-Fstat map F_mn over {t0, tau} ranges */
521  )
522 {
523  /* ----- check input consistency */
524  if ( !FstatMap || !FstatMap->F_mn ) {
525  XLALPrintError( "%s: invalid NULL input 'FstatMap' or 'FstatMap->F_mn'\n", __func__ );
527  }
528  if ( windowRange.type >= TRANSIENT_LAST ) {
529  XLALPrintError( "%s: unknown window-type (%d) passes as input. Allowed are [0,%d].\n", __func__, windowRange.type, TRANSIENT_LAST - 1 );
531  }
532 
533  /* ----- step through F_mn array subtract maxF and sum e^{F_mn - maxF}*/
534  /*
535  * It is numerically more robust to marginalize over e^(F_mn - Fmax), which at worst can underflow, while
536  * e^F_mn can overflow (for F>~700). The constant offset e^Fmax is irrelevant for posteriors (normalization constant).
537  */
538  UINT4 N_t0Range = FstatMap->F_mn->size1;
539  UINT4 N_tauRange = FstatMap->F_mn->size2;
540 
541  REAL8 tau0 = windowRange.tau;
542  REAL8 tau1 = tau0 + windowRange.tauBand;
543 
544  pdf1D_t *ret;
545 
546  /* ----- handle special cases: 1) point-like support, 2) uniform pdf-value over 1 bin ----- */
547  if ( N_tauRange == 1 && ( windowRange.tauBand == 0 ) ) {
548  if ( ( ret = XLALCreateSingularPDF1D( tau0 ) ) == NULL ) {
549  XLALPrintError( "%s: failed to create singular pdf for tau0 = %g\n", __func__, tau0 );
551  }
552  return ret;
553  } /* if singular pdf in tau */
554  if ( ( N_tauRange == 1 ) && ( windowRange.tauBand > 0 ) ) {
555  if ( ( ret = XLALCreateUniformPDF1D( tau0, tau1 ) ) == NULL ) {
556  XLALPrintError( "%s: failed to created unform pdf over [%g, %g]\n", __func__, tau0, tau1 );
558  }
559  return ret;
560  } /* if uniform pdf over small band tauBand */
561 
562  /* ----- general N>1 point pdf case ----- */
563  if ( ( ret = XLALCreateDiscretePDF1D( tau0, tau1, N_tauRange ) ) == NULL ) {
564  XLALPrintError( "%s: XLALCreateDiscretePDF1D() failed with xlalErrno = %d\n", __func__, xlalErrno );
566  }
567 
568  UINT4 m, n;
569  for ( n = 0; n < N_tauRange; n ++ ) { /* loop over timescales tau */
570  REAL8 sum_eF = 0;
571  for ( m = 0; m < N_t0Range; m ++ ) { /* loop over start-times t0 */
572  REAL8 DeltaF = FstatMap->maxF - gsl_matrix_get( FstatMap->F_mn, m, n ); // always >= 0, exactly ==0 at {m,n}_max
573 
574  //sum_eB += exp ( - DeltaF );
575  sum_eF += XLALFastNegExp( DeltaF );
576 
577  } /* for m < N_t0Range */
578 
579  ret->probDens->data[n] = sum_eF;
580 
581  } /* for n < N_tauRange */
582 
583  /* free mem */
585 
586  /* normalize this PDF */
587  if ( XLALNormalizePDF1D( ret ) != XLAL_SUCCESS ) {
588  XLALPrintError( "%s: failed to normalize posterior pdf ..\n", __func__ );
590  }
591 
592  /* ----- return ----- */
593  return ret;
594 
595 } /* XLALComputeTransientPosterior_tau() */
596 
597 
598 
599 /**
600  * Function to compute transient-window "F-statistic map" over start-time and timescale {t0, tau}.
601  * Returns a 2D matrix F_mn, with m = index over start-times t0, and n = index over timescales tau,
602  * in steps of dt0 in [t0, t0+t0Band], and dtau in [tau, tau+tauBand] as defined in transientWindowRange
603  *
604  * Note: if window->type == none, we compute a single rectangular window covering all the data.
605  *
606  * Note2: if the experimental switch useFReg is true, returns FReg=F - log(D) instead of F. This option is of
607  * little practical interest, except for demonstrating that marginalizing (1/D)e^F is *less* sensitive
608  * than marginalizing e^F (see transient methods-paper [in prepartion])
609  *
610  */
612 XLALComputeTransientFstatMap( const MultiFstatAtomVector *multiFstatAtoms, /**< [in] multi-IFO F-statistic atoms */
613  transientWindowRange_t windowRange, /**< [in] type and parameters specifying transient window range to search */
614  BOOLEAN useFReg /**< [in] experimental switch: compute FReg = F - log(D) instead of F */
615  )
616 {
617  /* check input consistency */
618  if ( !multiFstatAtoms || !multiFstatAtoms->data || !multiFstatAtoms->data[0] ) {
619  XLALPrintError( "%s: invalid NULL input.\n", __func__ );
621  }
622  if ( windowRange.type >= TRANSIENT_LAST ) {
623  XLALPrintError( "%s: unknown window-type (%d) passes as input. Allowed are [0,%d].\n", __func__, windowRange.type, TRANSIENT_LAST - 1 );
625  }
626 
627  /* ----- pepare return container ----- */
628  transientFstatMap_t *ret;
629  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
630  XLALPrintError( "%s: XLALCalloc(1,%zu) failed.\n", __func__, sizeof( *ret ) );
632  }
633 
634  /* ----- first combine all multi-atoms into a single atoms-vector with *unique* timestamps */
635  FstatAtomVector *atoms;
636  UINT4 TAtom = multiFstatAtoms->data[0]->TAtom;
637  UINT4 TAtomHalf = TAtom / 2; /* integer division */
638 
639  if ( ( atoms = XLALmergeMultiFstatAtomsBinned( multiFstatAtoms, TAtom ) ) == NULL ) {
640  XLALPrintError( "%s: XLALmergeMultiFstatAtomsBinned() failed with code %d\n", __func__, xlalErrno );
642  }
643  UINT4 numAtoms = atoms->length;
644  /* actual data spans [t0_data, t0_data + numAtoms * TAtom] in steps of TAtom */
645  UINT4 t0_data = atoms->data[0].timestamp;
646  UINT4 t1_data = atoms->data[numAtoms - 1].timestamp + TAtom;
647 
648  /* ----- special treatment of window_type = none ==> replace by rectangular window spanning all the data */
649  if ( windowRange.type == TRANSIENT_NONE ) {
650  windowRange.type = TRANSIENT_RECTANGULAR;
651  windowRange.t0 = t0_data;
652  windowRange.t0Band = 0;
653  windowRange.dt0 = TAtom; /* irrelevant */
654  windowRange.tau = numAtoms * TAtom;
655  windowRange.tauBand = 0;
656  windowRange.dtau = TAtom; /* irrelevant */
657  }
658 
659  /* NOTE: indices {i,j} enumerate *actual* atoms and their timestamps t_i, while the
660  * indices {m,n} enumerate the full grid of values in [t0_min, t0_max]x[Tcoh_min, Tcoh_max] in
661  * steps of deltaT. This allows us to deal with gaps in the data in a transparent way.
662  *
663  * NOTE2: we operate on the 'binned' atoms returned from XLALmergeMultiFstatAtomsBinned(),
664  * which means we can safely assume all atoms to be lined up perfectly on a 'deltaT' binned grid.
665  *
666  * The mapping used will therefore be {i,j} -> {m,n}:
667  * m = offs_i / deltaT = start-time offset from t0_min measured in deltaT
668  * n = Tcoh_ij / deltaT = duration Tcoh_ij measured in deltaT,
669  *
670  * where
671  * offs_i = t_i - t0_min
672  * Tcoh_ij = t_j - t_i + deltaT
673  *
674  */
675 
676  /* We allocate a matrix {m x n} = t0Range * TcohRange elements
677  * covering the full timerange the transient window-range [t0,t0+t0Band]x[tau,tau+tauBand]
678  */
679  UINT4 N_t0Range = ( UINT4 ) floor( windowRange.t0Band / windowRange.dt0 ) + 1;
680  UINT4 N_tauRange = ( UINT4 ) floor( windowRange.tauBand / windowRange.dtau ) + 1;
681 
682  if ( ( ret->F_mn = gsl_matrix_calloc( N_t0Range, N_tauRange ) ) == NULL ) {
683  XLALPrintError( "%s: failed ret->F_mn = gsl_matrix_calloc ( %d, %d )\n", __func__, N_tauRange, N_t0Range );
685  }
686 
687  transientWindow_t win_mn;
688  win_mn.type = windowRange.type;
689  ret->maxF = -1.0; // keep track of loudest F-stat point. Initializing to a negative value ensures that we always update at least once and hence return sane t0_d_ML, tau_d_ML even if there is only a single bin where F=0 happens.
690  UINT4 m, n;
691  /* ----- OUTER loop over start-times [t0,t0+t0Band] ---------- */
692  for ( m = 0; m < N_t0Range; m ++ ) { /* m enumerates 'binned' t0 start-time indices */
693  /* compute Fstat-atom index i_t0 in [0, numAtoms) */
694  win_mn.t0 = windowRange.t0 + m * windowRange.dt0;
695  INT4 i_tmp = ( win_mn.t0 - t0_data + TAtomHalf ) / TAtom; // integer round: floor(x+0.5)
696  if ( i_tmp < 0 ) {
697  i_tmp = 0;
698  }
699  UINT4 i_t0 = ( UINT4 )i_tmp;
700  if ( i_t0 >= numAtoms ) {
701  i_t0 = numAtoms - 1;
702  }
703 
704  /* ----- INNER loop over timescale-parameter tau ---------- */
705  REAL4 Ad = 0, Bd = 0, Cd = 0;
706  COMPLEX8 Fa = 0, Fb = 0;
707  UINT4 i_t1_last = i_t0;
708 
709  for ( n = 0; n < N_tauRange; n ++ ) {
710  /* translate n into an atoms end-index for this search interval [t0, t0+Tcoh],
711  * giving the index range of atoms to sum over
712  */
713  win_mn.tau = windowRange.tau + n * windowRange.dtau;
714 
715  /* get end-time t1 of this transient-window search */
716  UINT4 t0, t1;
717  if ( XLALGetTransientWindowTimespan( &t0, &t1, win_mn ) != XLAL_SUCCESS ) {
718  XLALPrintError( "%s: XLALGetTransientWindowTimespan() failed.\n", __func__ );
720  }
721 
722  /* compute window end-time Fstat-atom index i_t1 in [0, numAtoms) */
723  i_tmp = ( t1 - t0_data + TAtomHalf ) / TAtom - 1; // integer round: floor(x+0.5)
724  if ( i_tmp < 0 ) {
725  i_tmp = 0;
726  }
727  UINT4 i_t1 = ( UINT4 )i_tmp;
728  if ( i_t1 >= numAtoms ) {
729  i_t1 = numAtoms - 1;
730  }
731 
732  /* protection against degenerate 1-atom case: (this implies D=0 and therefore F->inf) */
733  if ( i_t1 == i_t0 ) {
734  XLALPrintError( "%s: encountered a single-atom Fstat-calculation. This is degenerate and cannot be computed!\n", __func__ );
735  XLALPrintError( "Window-values m=%d (t0=%d=t0_data + %d), n=%d (tau=%d) ==> t1_data - t0 = %d\n",
736  m, win_mn.t0, i_t0 * TAtom, n, win_mn.tau, t1_data - win_mn.t0 );
737  XLALPrintError( "The most likely cause is that your t0-range covered all of your data: t0 must stay away *at least* 2*TAtom from the end of the data!\n" );
739  }
740 
741  /* now we have two valid atoms-indices [i_t0, i_t1] spanning our Fstat-window to sum over,
742  * using weights according to the window-type
743  */
744  switch ( windowRange.type ) {
746 #if 0
747  /* 'vanilla' unoptimized method, for sanity checks with 'optimized' method */
748  Ad = 0;
749  Bd = 0;
750  Cd = 0;
751  Fa = 0;
752  Fb = 0;
753  for ( UINT4 i = i_t0; i <= i_t1; i ++ )
754 #else
755  /* special optimiziation in the rectangular-window case: just add on to previous tau values
756  * ie re-use the sum over [i_t0, i_t1_last] from the pevious tau-loop iteration
757  */
758  for ( UINT4 i = i_t1_last; i <= i_t1; i ++ )
759 #endif
760  {
761  FstatAtom *thisAtom_i = &atoms->data[i];
762 
763  /* now add on top of previous values, summed from [i_t0, i_t1_last] */
764  Ad += thisAtom_i->a2_alpha;
765  Bd += thisAtom_i->b2_alpha;
766  Cd += thisAtom_i->ab_alpha;
767 
768  Fa += thisAtom_i->Fa_alpha;
769  Fb += thisAtom_i->Fb_alpha;
770 
771  } /* for i = i_t1_last : i_t1 */
772 
773  i_t1_last = i_t1 + 1; /* keep track of up to where we summed for the next iteration */
774 
775  break;
776 
778  /* reset all values */
779  Ad = 0;
780  Bd = 0;
781  Cd = 0;
782  Fa = 0;
783  Fb = 0;
784 
785  for ( UINT4 i = i_t0; i <= i_t1; i ++ ) {
786  FstatAtom *thisAtom_i = &atoms->data[i];
787  UINT4 t_i = thisAtom_i->timestamp;
788 
789  REAL8 win_i;
790  win_i = XLALGetExponentialTransientWindowValue( t_i, t0, t1, win_mn.tau );
791 
792  REAL8 win2_i = win_i * win_i;
793 
794  Ad += thisAtom_i->a2_alpha * win2_i;
795  Bd += thisAtom_i->b2_alpha * win2_i;
796  Cd += thisAtom_i->ab_alpha * win2_i;
797 
798  Fa += thisAtom_i->Fa_alpha * win_i;
799  Fb += thisAtom_i->Fb_alpha * win_i;
800 
801  } /* for i in [i_t0, i_t1] */
802  break;
803 
804  default:
805  XLALPrintError( "%s: invalid transient window type %d not in [%d, %d].\n",
806  __func__, windowRange.type, TRANSIENT_NONE, TRANSIENT_LAST - 1 );
808  break;
809 
810  } /* switch window.type */
811 
812 
813  /* generic F-stat calculation from A,B,C, Fa, Fb */
814  REAL4 Dd = XLALComputeAntennaPatternSqrtDeterminant( Ad, Bd, Cd, 0 );
815  REAL4 DdInv = 1.0f / Dd;
816  REAL4 twoF = compute_fstat_from_fa_fb( Fa, Fb, Ad, Bd, Cd, 0, DdInv );
817  REAL4 F = 0.5 * twoF;
818  /* keep track of loudest F-stat value encountered over the m x n matrix */
819  if ( F > ret->maxF ) {
820  ret->maxF = F;
821  ret->t0_ML = win_mn.t0; /* start-time t0 corresponding to Fmax */
822  ret->tau_ML = win_mn.tau; /* timescale tau corresponding to Fmax */
823  }
824 
825  /* if requested: use 'regularized' F-stat: log ( 1/D * e^F ) = F + log(1/D) */
826  if ( useFReg ) {
827  F += log( DdInv );
828  }
829 
830  /* and store this in Fstat-matrix as element {m,n} */
831  gsl_matrix_set( ret->F_mn, m, n, F );
832 
833  } /* for n in n[tau] : n[tau+tauBand] */
834 
835  } /* for m in m[t0] : m[t0+t0Band] */
836 
837  /* free internal mem */
839 
840  /* return end product: F-stat map */
841  return ret;
842 
843 } /* XLALComputeTransientFstatMap() */
844 
845 
846 
847 
848 /**
849  * Combine N Fstat-atoms vectors into a single 'canonical' binned and ordered atoms-vector.
850  * The function pre-sums all atoms on a regular 'grid' of timestep bins deltaT covering the full data-span.
851  * Atoms with timestamps falling into the bin i : [t_i, t_{i+1} ) are pre-summed and returned as atoms[i],
852  * where t_i = t_0 + i * deltaT.
853  *
854  * Note: this pre-binning is equivalent to using a rectangular transient window on the deltaT timescale,
855  * which is OK even with a different transient window, provided deltaT << transient-window timescale!
856  *
857  * Bins containing no atoms are returned with all values set to zero.
858  */
861 {
862  if ( !multiAtoms || !multiAtoms->length || !multiAtoms->data[0] || ( deltaT == 0 ) ) {
863  XLALPrintError( "%s: invalid NULL input or deltaT=0.\n", __func__ );
865  }
866 
867  UINT4 numDet = multiAtoms->length;
868  UINT4 X;
869  UINT4 TAtom = multiAtoms->data[0]->TAtom;
870 
871  /* check consistency of time-step lengths between different IFOs */
872  for ( X = 0; X < numDet; X ++ ) {
873  if ( multiAtoms->data[X]->TAtom != TAtom ) {
874  XLALPrintError( "%s: Invalid input, atoms baseline TAtom=%d must be identical for all multiFstatAtomVectors (IFO=%d: TAtom=%d)\n",
875  __func__, TAtom, X, multiAtoms->data[X]->TAtom );
877  }
878  } /* for X < numDet */
879 
880  /* get earliest and latest atoms timestamps across all input detectors */
881  UINT4 tMin = LAL_INT4_MAX - 1;
882  UINT4 tMax = 0;
883  for ( X = 0; X < numDet; X ++ ) {
884  UINT4 numAtomsX = multiAtoms->data[X]->length;
885 
886  if ( multiAtoms->data[X]->data[0].timestamp < tMin ) {
887  tMin = multiAtoms->data[X]->data[0].timestamp;
888  }
889 
890  if ( multiAtoms->data[X]->data[numAtomsX - 1].timestamp > tMax ) {
891  tMax = multiAtoms->data[X]->data[numAtomsX - 1].timestamp;
892  }
893 
894  } /* for X < numDet */
895 
896 
897  /* prepare 'canonical' binned atoms output vector */
898  UINT4 NBinnedAtoms = ( UINT4 )floor( 1.0 * ( tMax - tMin ) / deltaT ) + 1; /* round up this way to make sure tMax is always included in the last bin */
899 
900  FstatAtomVector *atomsOut;
901  if ( ( atomsOut = XLALCreateFstatAtomVector( NBinnedAtoms ) ) == NULL ) { /* NOTE: these atoms are pre-initialized to zero already! */
902  XLALPrintError( "%s: failed to XLALCreateFstatAtomVector ( %d )\n", __func__, NBinnedAtoms );
904  }
905 
906  atomsOut->TAtom = deltaT; /* output atoms-vector has new atoms baseline 'deltaT' */
907 
908  /* Step through all input atoms, and sum them together into output bins */
909  for ( X = 0; X < numDet; X ++ ) {
910  UINT4 i;
911  UINT4 numAtomsX = multiAtoms->data[X]->length;
912  for ( i = 0; i < numAtomsX; i ++ ) {
913  FstatAtom *atom_X_i = &multiAtoms->data[X]->data[i];
914  UINT4 t_X_i = atom_X_i -> timestamp;
915 
916  /* determine target bin-index j such that t_X_i in [ t_j, t_{j+1} ) */
917  UINT4 j = ( UINT4 ) floor( 1.0 * ( t_X_i - tMin ) / deltaT );
918 
919  /* add atoms i to target atoms j */
920  FstatAtom *destAtom = &atomsOut->data[j];
921  destAtom->timestamp = tMin + j * deltaT; /* set binned output atoms timestamp */
922 
923  destAtom->a2_alpha += atom_X_i->a2_alpha;
924  destAtom->b2_alpha += atom_X_i->b2_alpha;
925  destAtom->ab_alpha += atom_X_i->ab_alpha;
926  destAtom->Fa_alpha += atom_X_i->Fa_alpha;
927  destAtom->Fb_alpha += atom_X_i->Fb_alpha;
928 
929  } /* for i < numAtomsX */
930  } /* for X < numDet */
931 
932  return atomsOut;
933 
934 } /* XLALmergeMultiFstatAtomsBinned() */
935 
936 /**
937  * Write one line for given transient CW candidate into output file.
938  *
939  * NOTE: if input thisCand == NULL, we write a header comment-line explaining the fields
940  *
941  */
942 int
943 write_transientCandidate_to_fp( LALFILE *fp, const transientCandidate_t *thisCand, const char timeUnit )
944 {
945  /* sanity checks */
946  if ( !fp ) {
947  XLALPrintError( "%s: invalid NULL filepointer input.\n", __func__ );
949  }
950 
951 
952  if ( thisCand == NULL ) { /* write header-line comment */
953  XLALFilePrintf( fp, "%%%% Freq[Hz] Alpha[rad] Delta[rad] fkdot[1] fkdot[2] fkdot[3] t0_ML[%c] tau_ML[%c] maxTwoF logBstat t0_MP[%c] tau_MP[%c]\n", timeUnit, timeUnit, timeUnit, timeUnit );
954  } else {
955  if ( !thisCand->FstatMap ) {
956  XLALPrintError( "%s: incomplete: transientCand->FstatMap == NULL!\n", __func__ );
958  }
959 
960  REAL8 maxTwoF = 2.0 * thisCand->FstatMap->maxF;
961  XLALFilePrintf( fp, " %- 18.16f %- 19.16f %- 19.16f %- 9.6g %- 9.5g %- 9.5g",
962  thisCand->doppler.fkdot[0], thisCand->doppler.Alpha, thisCand->doppler.Delta,
963  thisCand->doppler.fkdot[1], thisCand->doppler.fkdot[2], thisCand->doppler.fkdot[3]
964  );
965  if ( timeUnit == 's' ) {
966  XLALFilePrintf( fp, " %10d %10d %- 11.8g %- 11.8g %15.4f %15.4f\n",
967  thisCand->FstatMap->t0_ML, thisCand->FstatMap->tau_ML,
968  maxTwoF, thisCand->logBstat,
969  thisCand->t0_MP, thisCand->tau_MP
970  );
971  } else if ( timeUnit == 'd' ) {
972  UINT4 t0 = thisCand->windowRange.t0;
973  REAL8 t0_d_ML = 1.0 * ( thisCand->FstatMap->t0_ML - t0 ) / DAY24;
974  REAL8 tau_d_ML = 1.0 * thisCand->FstatMap->tau_ML / DAY24;
975  REAL8 t0_d_MP = 1.0 * ( thisCand->t0_MP - t0 ) / DAY24;
976  REAL8 tau_d_MP = 1.0 * thisCand->tau_MP / DAY24;
977  XLALFilePrintf( fp, " %-8.5f %-8.5f %- 11.8g %- 11.8g %-8.5f %8.5f\n",
978  t0_d_ML, tau_d_ML,
979  maxTwoF, thisCand->logBstat,
980  t0_d_MP, tau_d_MP
981  );
982  } else {
983  XLALPrintError( "%s: Unknown time unit '%c'!\n", __func__, timeUnit );
985  }
986  }
987 
988  return XLAL_SUCCESS;
989 
990 } /* write_transientCandidate_to_fp() */
991 
992 
993 /**
994  * Write full set of t0 and tau grid points (assumed at fixed Doppler parameters) into output file.
995  *
996  * NOTE: if input FstatMap == NULL, we write a header comment-line explaining the fields
997  *
998  * if doppler = NULL, we skip those columns
999  *
1000  */
1001 int write_transientFstatMap_to_fp( LALFILE *fp, const transientFstatMap_t *FstatMap, const transientWindowRange_t *windowRange, const PulsarDopplerParams *doppler )
1002 {
1003 
1004  /* sanity checks */
1005  if ( !fp ) {
1006  XLAL_ERROR( XLAL_EINVAL, "Invalid NULL filepointer input." );
1007  }
1008 
1009  if ( !FstatMap ) { /* write header-line comment */
1010  if ( !doppler ) {
1011  XLALFilePrintf( fp, "%%%% t0[s] tau[s] twoF\n" );
1012  } else {
1013  XLALFilePrintf( fp, "%%%% Freq[Hz] Alpha[rad] Delta[rad] fkdot[1] fkdot[2] fkdot[3] t0[s] tau[s] twoF\n" );
1014  }
1015  } else {
1016  if ( !windowRange ) {
1017  XLAL_ERROR( XLAL_EINVAL, "Invalid NULL windowRange input.\n" );
1018  }
1019 
1020  UINT4 t0 = windowRange->t0;
1021  UINT4 N_t0Range = ( UINT4 ) floor( windowRange->t0Band / windowRange->dt0 ) + 1;
1022  UINT4 N_tauRange = ( UINT4 ) floor( windowRange->tauBand / windowRange->dtau ) + 1;
1023  if ( ( N_t0Range != FstatMap->F_mn->size1 ) || ( N_tauRange != FstatMap->F_mn->size2 ) ) {
1024  XLAL_ERROR( XLAL_EDOM, "Inconsistent dimensions of windowRange (%ux%u) and FstatMap GSL matrix (%zux%zu).", N_t0Range, N_tauRange, FstatMap->F_mn->size1, FstatMap->F_mn->size2 );
1025  }
1026 
1027  /* ----- OUTER loop over start-times [t0,t0+t0Band] ---------- */
1028  for ( UINT4 m = 0; m < N_t0Range; m ++ ) { /* m enumerates 'binned' t0 start-time indices */
1029  UINT4 this_t0 = t0 + m * windowRange->dt0;
1030  /* ----- INNER loop over timescale-parameter tau ---------- */
1031  for ( UINT4 n = 0; n < N_tauRange; n ++ ) {
1032  UINT4 this_tau = windowRange->tau + n * windowRange->dtau;
1033  REAL4 this_2F = 2.0 * gsl_matrix_get( FstatMap->F_mn, m, n );
1034  if ( !doppler ) {
1035  XLALFilePrintf( fp, " %10d %10d %- 11.8g\n",
1036  this_t0, this_tau, this_2F
1037  );
1038  } else {
1039  XLALFilePrintf( fp, " %- 18.16f %- 19.16f %- 19.16f %- 9.6g %- 9.5g %- 9.5g %10d %10d %- 11.8g\n",
1040  doppler->fkdot[0], doppler->Alpha, doppler->Delta,
1041  doppler->fkdot[1], doppler->fkdot[2], doppler->fkdot[3],
1042  this_t0, this_tau, this_2F
1043  );
1044  }
1045  }
1046  }
1047  }
1048 
1049  return XLAL_SUCCESS;
1050 
1051 } /* write_transientFstatMap_to_fp() */
1052 
1053 
1054 /**
1055  * Write full set of t0 and tau grid points for given transient CW candidate into output file.
1056  *
1057  * NOTE: if input thisCand == NULL, we write a header comment-line explaining the fields
1058  *
1059  */
1060 int
1062 {
1063 
1064  /* sanity checks */
1065  if ( !fp ) {
1066  XLALPrintError( "%s: invalid NULL filepointer input.\n", __func__ );
1068  }
1069 
1070  if ( thisCand == NULL ) {
1071  /* still pass a pointer empty doppler struct,
1072  * so that the output file header will have all column names
1073  */
1074  PulsarDopplerParams XLAL_INIT_DECL( emptyDoppler );
1075  XLAL_CHECK( write_transientFstatMap_to_fp( fp, NULL, NULL, &emptyDoppler ) == XLAL_SUCCESS, XLAL_EFUNC, "Failed to write transient-FstatMap file header." );
1076  } else {
1077  XLAL_CHECK( write_transientFstatMap_to_fp( fp, thisCand->FstatMap, &thisCand->windowRange, &thisCand->doppler ) == XLAL_SUCCESS, XLAL_EFUNC, "Failed to write transient-FstatMap file body." );
1078  }
1079 
1080  return XLAL_SUCCESS;
1081 
1082 } /* write_transientCandidateAll_to_fp() */
1083 
1084 
1085 /**
1086  * Write multi-IFO F-stat atoms 'multiAtoms' into output stream 'fstat'.
1087  */
1088 int
1090 {
1091  UINT4 X, alpha;
1092 
1093  if ( !fp || !multiAtoms ) {
1094  XLALPrintError( "%s: invalid NULL input.\n", __func__ );
1096  }
1097 
1098  XLALFilePrintf( fp, "%%%% tGPS a2 b2 ab Fa_re Fa_im Fb_re Fb_im\n" );
1099 
1100  for ( X = 0; X < multiAtoms->length; X++ ) {
1101  FstatAtomVector *thisAtomVector = multiAtoms->data[X];
1102  for ( alpha = 0; alpha < thisAtomVector->length; alpha ++ ) {
1103  FstatAtom *thisAtom = &thisAtomVector->data[alpha];
1104  XLALFilePrintf( fp, "%10d %8.6f %8.6f %9.6f %9.6f %9.6f %9.6f %9.6f\n",
1105  thisAtom->timestamp,
1106  thisAtom->a2_alpha,
1107  thisAtom->b2_alpha,
1108  thisAtom->ab_alpha,
1109  crealf( thisAtom->Fa_alpha ),
1110  cimagf( thisAtom->Fa_alpha ),
1111  crealf( thisAtom->Fb_alpha ),
1112  cimagf( thisAtom->Fb_alpha )
1113  );
1114  } /* for alpha < numSFTs */
1115  } /* for X < numDet */
1116 
1117  return XLAL_SUCCESS;
1118 
1119 } /* write_MultiFstatAtoms_to_fp() */
1120 
1121 
1122 /**
1123  * Standard destructor for transientFstatMap_t
1124  * Fully NULL-robust as usual.
1125  */
1126 void
1128 {
1129  if ( !FstatMap ) {
1130  return;
1131  }
1132 
1133  if ( FstatMap->F_mn ) {
1134  gsl_matrix_free( FstatMap->F_mn );
1135  }
1136 
1137  XLALFree( FstatMap );
1138 
1139  return;
1140 
1141 } /* XLALDestroyTransientFstatMap() */
1142 
1143 /**
1144  * Standard destructor for transientCandidate_t
1145  * Fully NULL-robust as usual.
1146  */
1147 void
1149 {
1150  if ( !cand ) {
1151  return;
1152  }
1153 
1154  if ( cand->FstatMap ) {
1156  }
1157 
1158  XLALFree( cand );
1159 
1160  return;
1161 
1162 } /* XLALDestroyTransientCandidate() */
1163 
1164 
1165 // ========== LUT math functions used here ==========
1166 /**
1167  * Generate an exponential lookup-table expLUT for e^(-x)
1168  * over the interval x in [0, xmax], using 'length' points.
1169  */
1170 int
1172 {
1173  /* create empty output LUT */
1174  gsl_vector *ret;
1175  if ( ( ret = gsl_vector_alloc( EXPLUT_LENGTH + 1 ) ) == NULL ) {
1176  XLALPrintError( "%s: failed to gsl_vector_alloc (%i)\n", __func__, EXPLUT_LENGTH + 1 );
1178  }
1179 
1180  /* fill output LUT */
1182  UINT4 i;
1183  for ( i = 0; i <= EXPLUT_LENGTH; i ++ ) {
1184  REAL8 xi = i * dx;
1185 
1186  gsl_vector_set( ret, i, exp( - xi ) );
1187 
1188  } /* for i < length() */
1189 
1190  /* 'return' this by setting the global vector */
1191  expLUT = ret;
1192 
1193  return XLAL_SUCCESS;
1194 
1195 } /* XLALCreateExpLUT() */
1196 
1197 
1198 /**
1199  * Destructor function for expLUT_t lookup table
1200  */
1201 void
1203 {
1204  if ( !expLUT ) {
1205  return;
1206  }
1207 
1208  gsl_vector_free( expLUT );
1209 
1210  expLUT = NULL;
1211 
1212  return;
1213 
1214 } /* XLALDestroyExpLUT() */
1215 
1216 
1217 /**
1218  * Fast exponential function e^-x using lookup-table (LUT).
1219  * We need to compute exp(-x) for x >= 0, typically in a B-stat
1220  * integral of the form int e^-x dx: this means that small values e^(-x)
1221  * will not contribute much to the integral and are less important than
1222  * values close to 1. Therefore we pre-compute a LUT of e^(-x) for x in [0, xmax],
1223  * in Npoints points, and set e^(-x) = 0 for x < xmax.
1224  *
1225  * NOTE: if module-global expLUT=NULL, we create it here
1226  * NOTE: if argument is negative, we use math-lib exp(-x) instead of LUT
1227  */
1228 REAL8
1230 {
1231  if ( mx > EXPLUT_XMAX ) { /* for values smaller than e^(-xmax) we truncate to 0 */
1232  return 0.0;
1233  }
1234 
1235  if ( mx < 0 ) {
1236  return exp( - mx );
1237  }
1238 
1239  /* if lookup table doesn't exist yet: generate it now */
1240  if ( !expLUT && ( XLALCreateExpLUT() != XLAL_SUCCESS ) ) {
1242  }
1243 
1244  /* find index of closest point xp in LUT to xm */
1245  UINT4 i0 = ( UINT4 )( mx * EXPLUT_DXINV + 0.5 );
1246 
1247  return gsl_vector_get( expLUT, i0 );
1248 
1249 } /* XLALFastNegExp() */
1250 
1251 /// @}
static REAL4 compute_fstat_from_fa_fb(COMPLEX8 Fa, COMPLEX8 Fb, REAL4 A, REAL4 B, REAL4 C, REAL4 E, REAL4 Dinv)
#define __func__
log an I/O error, i.e.
#define LAL_INT4_MAX
int j
#define LALMalloc(n)
pdf1D_t * XLALCreateUniformPDF1D(REAL8 xMin, REAL8 xMax)
Creator function for a uniform 1D pdf over [xMin, xMax].
pdf1D_t * XLALCreateDiscretePDF1D(REAL8 xMin, REAL8 xMax, UINT4 numBins)
Creator function for a generic discrete 1D pdf over [xMin, xMax], discretized into numBins bins.
int XLALNormalizePDF1D(pdf1D_t *pdf)
Method to normalize the given pdf1D.
pdf1D_t * XLALCreateSingularPDF1D(REAL8 x0)
Creator function for a 'singular' 1D pdf, containing a single value with certainty,...
static const char * transientWindowNames[TRANSIENT_LAST]
#define EXPLUT_XMAX
Lookup-table for negative exponentials e^(-x) Holds an array 'data' of 'length' for values e^(-x) for...
static gsl_vector * expLUT
module-global lookup-table for negative exponentials e^(-x)
#define EXPLUT_LENGTH
#define EXPLUT_DXINV
#define MAXLEN
const double deltaT
FstatAtomVector * XLALCreateFstatAtomVector(const UINT4 length)
Create a FstatAtomVector of the given length.
Definition: ComputeFstat.c:276
void XLALDestroyFstatAtomVector(FstatAtomVector *atoms)
Free all memory associated with a FstatAtomVector structure.
Definition: ComputeFstat.c:297
int XLALFilePrintf(LALFILE *file, const char *fmt,...)
REAL4 XLALComputeAntennaPatternSqrtDeterminant(REAL4 A, REAL4 B, REAL4 C, REAL4 E)
Compute (sqrt of) determinant of the antenna-pattern matrix Mmunu = [ A, C, 0, -E; C B E,...
Definition: LALComputeAM.c:544
unsigned char BOOLEAN
double REAL8
#define XLAL_INIT_DECL(var,...)
char CHAR
uint32_t UINT4
float complex COMPLEX8
int32_t INT4
float REAL4
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
int XLALStringToLowerCase(char *string)
void LogPrintf(LogLevel_t, const char *format,...) _LAL_GCC_PRINTF_FORMAT_(2
LOG_CRITICAL
LOG_NORMAL
#define PULSAR_MAX_SPINS
maximal number of spin-parameters (Freq + spindowns) we can handle
@ TRANSIENT_RECTANGULAR
standard rectangular window covering [t0, t0+tau]
@ TRANSIENT_LAST
@ TRANSIENT_NONE
Note: in this case the window-parameters will be ignored, and treated as rect={data},...
@ TRANSIENT_EXPONENTIAL
exponentially decaying window e^{-t0/tau} starting at t0.
static const INT4 m
transientFstatMap_t * XLALComputeTransientFstatMap(const MultiFstatAtomVector *multiFstatAtoms, transientWindowRange_t windowRange, BOOLEAN useFReg)
Function to compute transient-window "F-statistic map" over start-time and timescale {t0,...
void XLALDestroyTransientFstatMap(transientFstatMap_t *FstatMap)
Standard destructor for transientFstatMap_t Fully NULL-robust as usual.
int XLALParseTransientWindowName(const char *windowName)
Parse a transient window name string into the corresponding transientWindowType.
int XLALApplyTransientWindow2NoiseWeights(MultiNoiseWeights *multiNoiseWeights, const MultiLIGOTimeGPSVector *multiTS, transientWindow_t transientWindow)
apply transient window to give multi noise-weights, associated with given multi timestamps
static int XLALCreateExpLUT(void)
Generate an exponential lookup-table expLUT for e^(-x) over the interval x in [0, xmax],...
int write_transientCandidate_to_fp(LALFILE *fp, const transientCandidate_t *thisCand, const char timeUnit)
Write one line for given transient CW candidate into output file.
int XLALGetTransientWindowTimespan(UINT4 *t0, UINT4 *t1, transientWindow_t transientWindow)
Helper-function to determine the total timespan of a transient CW window, ie.
#define DAY24
standard 24h day = 86400 seconds ==> this is what's used in the definition of 'tauDays'
FstatAtomVector * XLALmergeMultiFstatAtomsBinned(const MultiFstatAtomVector *multiAtoms, UINT4 deltaT)
Combine N Fstat-atoms vectors into a single 'canonical' binned and ordered atoms-vector.
void XLALDestroyExpLUT(void)
Destructor function for expLUT_t lookup table.
REAL8 XLALFastNegExp(REAL8 mx)
Fast exponential function e^-x using lookup-table (LUT).
int write_MultiFstatAtoms_to_fp(LALFILE *fp, const MultiFstatAtomVector *multiAtoms)
Write multi-IFO F-stat atoms 'multiAtoms' into output stream 'fstat'.
CHAR * XLALPulsarDopplerParams2String(const PulsarDopplerParams *par)
Turn pulsar doppler-params into a single string that can be used for filenames The format is tRefNNNN...
int write_transientCandidateAll_to_fp(LALFILE *fp, const transientCandidate_t *thisCand)
Write full set of t0 and tau grid points for given transient CW candidate into output file.
#define TRANSIENT_EXP_EFOLDING
e-folding parameter for exponential window, after which we truncate the window for efficiency.
int XLALApplyTransientWindow(REAL4TimeSeries *series, transientWindow_t transientWindow)
apply a "transient CW window" described by TransientWindowParams to the given timeseries
pdf1D_t * XLALComputeTransientPosterior_t0(transientWindowRange_t windowRange, const transientFstatMap_t *FstatMap)
Compute transient-CW posterior (normalized) on start-time t0, using given type and parameters of tran...
static REAL8 XLALGetExponentialTransientWindowValue(UINT4 timestamp, UINT4 t0, UINT4 t1, UINT4 tau)
Function to compute the value of an exponential transient-window at a given timestamp.
static REAL8 XLALGetRectangularTransientWindowValue(UINT4 timestamp, UINT4 t0, UINT4 t1)
Function to compute the value of a rectangular transient-window at a given timestamp.
pdf1D_t * XLALComputeTransientPosterior_tau(transientWindowRange_t windowRange, const transientFstatMap_t *FstatMap)
Compute transient-CW posterior (normalized) on timescale tau, using given type and parameters of tran...
REAL8 XLALComputeTransientBstat(transientWindowRange_t windowRange, const transientFstatMap_t *FstatMap)
Compute transient-CW Bayes-factor B_SG = P(x|HypS)/P(x|HypG) (where HypG = Gaussian noise hypothesis)...
void XLALDestroyTransientCandidate(transientCandidate_t *cand)
Standard destructor for transientCandidate_t Fully NULL-robust as usual.
int write_transientFstatMap_to_fp(LALFILE *fp, const transientFstatMap_t *FstatMap, const transientWindowRange_t *windowRange, const PulsarDopplerParams *doppler)
Write full set of t0 and tau grid points (assumed at fixed Doppler parameters) into output file.
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR_NULL(...)
#define xlalErrno
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
XLAL_EINVAL
n
double alpha
double t0
An -statistic 'atom', i.e.
Definition: ComputeFstat.h:161
COMPLEX8 Fa_alpha
.
Definition: ComputeFstat.h:166
REAL4 b2_alpha
Antenna-pattern factor .
Definition: ComputeFstat.h:164
UINT4 timestamp
SFT GPS timestamp in seconds.
Definition: ComputeFstat.h:162
REAL4 ab_alpha
Antenna-pattern factor .
Definition: ComputeFstat.h:165
COMPLEX8 Fb_alpha
.
Definition: ComputeFstat.h:167
REAL4 a2_alpha
Antenna-pattern factor .
Definition: ComputeFstat.h:163
A vector of -statistic 'atoms', i.e.
Definition: ComputeFstat.h:174
UINT4 TAtom
Time-baseline of 'atoms', typically .
Definition: ComputeFstat.h:180
FstatAtom * data
Array of FstatAtom pointers of given length.
Definition: ComputeFstat.h:179
UINT4 length
Number of per-SFT 'atoms'.
Definition: ComputeFstat.h:178
A multi-detector vector of FstatAtomVector.
Definition: ComputeFstat.h:186
FstatAtomVector ** data
Array of FstatAtomVector pointers, one for each detector X.
Definition: ComputeFstat.h:191
UINT4 length
Number of detectors.
Definition: ComputeFstat.h:190
A collection of (multi-IFO) LIGOTimeGPSVector time-stamps vectors.
Definition: SFTfileIO.h:198
One noise-weight (number) per SFT (therefore indexed over IFOs and SFTs.
Definition: PSDutils.h:71
UINT4 length
number of detectors
Definition: PSDutils.h:75
REAL8Vector ** data
weights-vector for each detector
Definition: PSDutils.h:76
Type containing the 'Doppler-parameters' affecting the time-evolution of the phase.
PulsarSpins fkdot
Intrinsic spins: [Freq, f1dot, f2dot, ...
REAL8 Delta
Sky position: DEC (latitude) in equatorial coords and radians.
REAL8 Alpha
Sky position: RA (longitude) in equatorial coords and radians.
REAL4Sequence * data
LIGOTimeGPS epoch
REAL4 * data
REAL8 * data
Struct holding a transient CW candidate.
transientFstatMap_t * FstatMap
F-statistic over transient-window range {t0, tau} AND ML-estimators { Fmax, t0_Fmax,...
REAL8 t0_MP
maximum-posterior estimate for t0
PulsarDopplerParams doppler
Doppler params of this 'candidate'.
REAL8 tau_MP
maximum-posterior estimate for tau
REAL8 logBstat
log of Bayes-factor, marginalized over transientWindowRange
transientWindowRange_t windowRange
type and parameters specifying the transient window range in {t0, tau} covered
Struct holding a transient-window "F-statistic map" over start-time and timescale {t0,...
gsl_matrix * F_mn
"payload" F-map: F_mn for t0_m = t0 + m*dt0, and tau_n = tau + n*dtau
UINT4 tau_ML
maximum-likelihood estimator for duration Tcoh of max{2F} over the transientWindowRange (in seconds)
UINT4 t0_ML
maximum-likelihood estimator for start-time t0 of max{2F} over transientWindowRange (in GPS seconds)
REAL8 maxF
maximal F-value obtained over transientWindowRange
Struct defining one transient window instance.
UINT4 t0
GPS start-time 't0'.
UINT4 tau
transient timescale tau in seconds
transientWindowType_t type
window-type: none, rectangular, exponential, ....
Struct defining a range of transient windows.
UINT4 tauBand
range of transient timescales tau to search, in seconds
UINT4 dtau
stepsize to search tau-range with, in seconds
UINT4 tau
shortest transient timescale tau in seconds
UINT4 t0
earliest GPS start-time 't0' in seconds
UINT4 dt0
stepsize to search t0-range with, in seconds
transientWindowType_t type
window-type: none, rectangular, exponential, ....
UINT4 t0Band
range of start-times 't0' to search, in seconds