Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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>
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
56static 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
59static int XLALCreateExpLUT( void ); /* only ever used internally, destructor is in exported API */
60
61static 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
73int
74XLALParseTransientWindowName( 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 */
109int
110XLALGetTransientWindowTimespan( 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 */
158int
159XLALApplyTransientWindow( 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 */
221int
222XLALApplyTransientWindow2NoiseWeights( 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 */
304CHAR *
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 */
366REAL8
367XLALComputeTransientBstat( 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 */
431pdf1D_t *
432XLALComputeTransientPosterior_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 */
518pdf1D_t *
519XLALComputeTransientPosterior_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 */
612XLALComputeTransientFstatMap( 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 ----- */
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 */
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 */
942int
943write_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 */
1001int 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 */
1060int
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 */
1088int
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 */
1126void
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 */
1147void
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 */
1170int
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 */
1201void
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 */
1228REAL8
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 * XLALCreateSingularPDF1D(REAL8 x0)
Creator function for a 'singular' 1D pdf, containing a single value with certainty,...
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 * XLALCreateUniformPDF1D(REAL8 xMin, REAL8 xMax)
Creator function for a uniform 1D pdf over [xMin, xMax].
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
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:162
COMPLEX8 Fa_alpha
.
Definition: ComputeFstat.h:167
REAL4 b2_alpha
Antenna-pattern factor .
Definition: ComputeFstat.h:165
UINT4 timestamp
SFT GPS timestamp in seconds.
Definition: ComputeFstat.h:163
REAL4 ab_alpha
Antenna-pattern factor .
Definition: ComputeFstat.h:166
COMPLEX8 Fb_alpha
.
Definition: ComputeFstat.h:168
REAL4 a2_alpha
Antenna-pattern factor .
Definition: ComputeFstat.h:164
A vector of -statistic 'atoms', i.e.
Definition: ComputeFstat.h:175
UINT4 TAtom
Time-baseline of 'atoms', typically .
Definition: ComputeFstat.h:181
FstatAtom * data
Array of FstatAtom pointers of given length.
Definition: ComputeFstat.h:180
UINT4 length
Number of per-SFT 'atoms'.
Definition: ComputeFstat.h:179
A multi-detector vector of FstatAtomVector.
Definition: ComputeFstat.h:187
FstatAtomVector ** data
Array of FstatAtomVector pointers, one for each detector X.
Definition: ComputeFstat.h:192
UINT4 length
Number of detectors.
Definition: ComputeFstat.h:191
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, ... ] where fkdot = d^kFreq/dt^k.
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
double deltaT