Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
synthesizeBstatMC.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2008 Reinhard Prix
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19
20/*********************************************************************************/
21/**
22 * \author R. Prix
23 * \file
24 * \ingroup lalpulsar_bin_Fstatistic
25 * \brief
26 * Generate N samples of B-statistic (and F-statistic) values drawn from their
27 * respective distributions, assuming Gaussian noise, for given signal parameters.
28 *
29 * This is mostly meant to be used for Monte-Carlos studies of ROC curves
30 *
31 */
32#include "config.h"
33
34#include <stdio.h>
35
36#include <gsl/gsl_vector.h>
37#include <gsl/gsl_matrix.h>
38#include <gsl/gsl_blas.h>
39#include <gsl/gsl_permutation.h>
40#include <gsl/gsl_linalg.h>
41#include <gsl/gsl_rng.h>
42#include <gsl/gsl_randist.h>
43#include <gsl/gsl_sf_bessel.h>
44#include <gsl/gsl_integration.h>
45#include <gsl/gsl_monte.h>
46#include <gsl/gsl_monte_plain.h>
47#include <gsl/gsl_monte_miser.h>
48#include <gsl/gsl_monte_vegas.h>
49
50#include <lal/LALGSL.h>
51#include <lal/AVFactories.h>
52#include <lal/LALInitBarycenter.h>
53#include <lal/UserInput.h>
54#include <lal/SFTfileIO.h>
55#include <lal/ExtrapolatePulsarSpins.h>
56#include <lal/NormalizeSFTRngMed.h>
57#include <lal/ComputeFstat.h>
58#include <lal/LALHough.h>
59#include <lal/LogPrintf.h>
60#include <lal/FstatisticTools.h>
61#include <lal/LALPulsarVCSInfo.h>
62
63#define SQ(x) ((x)*(x))
64
65/**
66 * Signal (amplitude) parameter ranges
67 */
68typedef struct {
69 REAL8 h0Nat; /**< h0 in *natural units* ie h0Nat = h0 * sqrt(T/Sn) */
70 REAL8 h0NatBand; /**< draw h0Nat from Band [h0Nat, h0Nat + Band ] */
71 REAL8 SNR; /**< if > 0: alternative to h0Nat/h0NatBand: fix optimal signal SNR */
79
80/**
81 * Configuration settings required for and defining a coherent pulsar search.
82 * These are 'pre-processed' settings, which have been derived from the user-input.
83 */
84typedef struct {
85 gsl_matrix *M_mu_nu; /**< antenna-pattern matrix and normalization */
86 AmpParamsRange_t AmpRange; /**< signal amplitude-parameter ranges: lower bounds + bands */
87 gsl_rng *rng; /**< gsl random-number generator */
88
90
91/*---------- Global variables ----------*/
92extern int vrbflg; /**< defined in lal/lib/std/LALError.c */
93
94/* ----- User-variables: can be set from config-file or command-line */
95typedef struct {
96 /* amplitude parameters + ranges */
97 REAL8 h0Nat; /**< overall GW amplitude h0 in *natural units*: h0Nat = h0 * sqrt(T/Sn) */
98 REAL8 h0NatBand; /**< randomize signal within [h0, h0+Band] with uniform prior */
99 REAL8 SNR; /**< specify fixed SNR: adjust h0 to obtain signal of this optimal SNR */
100 REAL8 cosi; /**< cos(inclination angle). If not set: randomize within [-1,1] */
101 REAL8 psi; /**< polarization angle psi. If not set: randomize within [-pi/4,pi/4] */
102 REAL8 phi0; /**< initial GW phase phi_0. If not set: randomize within [0, 2pi] */
103
104 /* Doppler parameters are not needed, only the input of the antenna-pattern matrix M_{mu nu} */
105 REAL8 A; /**< componentent {1,1} of MNat_{mu,nu}: A = <|a|^2> */
106 REAL8 B; /**< componentent {2,2} of MNat_{mu,nu}: B = <|b|^2> */
107 REAL8 C; /**< componentent {1,2} of MNat_{mu,nu}: C = <Re(b a*)> */
108 REAL8 E; /**< componentent {1,4} of MNat_{mu,nu}: E = <Im(b a*)> */
109
110 REAL8 numDraws; /**< number of random 'draws' to simulate for F-stat and B-stat */
111
112 REAL8 numMCpoints; /**< number of points to use for Monte-Carlo integration */
113
114 CHAR *outputStats; /**< output file to write numDraw resulting statistics into */
115
116 INT4 integrationMethod; /**< 0 = 2D Gauss-Kronod, 1 = 2D Vegas Monte-Carlo, */
117
118 BOOLEAN SignalOnly; /**< don't generate noise-draws: will result in non-random 'signal only' values of F and B */
119
121
122
123typedef struct {
124 double A;
125 double B;
126 double C;
127 double E;
128 const gsl_vector *x_mu;
129 double cosi; /**< only used for *inner* 2D Gauss-Kronod gsl-integration: value of cosi at which to integrate over psi */
131
132
133/* ---------- local prototypes ---------- */
134int main( int argc, char *argv[] );
135
136int initUserVars( UserInput_t *uvar );
137int InitCode( ConfigVariables *cfg, const UserInput_t *uvar );
138
139int XLALsynthesizeSignals( gsl_matrix **A_Mu_i, gsl_matrix **s_mu_i, gsl_matrix **Amp_i, gsl_vector **rho2,
140 const gsl_matrix *M_mu_nu, AmpParamsRange_t AmpRange,
141 gsl_rng *rnd, UINT4 numDraws );
142int XLALsynthesizeNoise( gsl_matrix **n_mu_i, const gsl_matrix *M_mu_nu, gsl_rng *rng, UINT4 numDraws );
143
144int XLALcomputeLogLikelihood( gsl_vector **lnL, const gsl_matrix *A_Mu_i, const gsl_matrix *s_mu_i, const gsl_matrix *x_mu_i );
145int XLALcomputeFstatistic( gsl_vector **Fstat, gsl_matrix **A_Mu_MLE_i, const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i );
146
147int XLALcomputeBstatisticMC( gsl_vector **Bstat, const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i, gsl_rng *rng, UINT4 numMCpoints );
148int XLALcomputeBstatisticGauss( gsl_vector **Bstat, const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i );
149
150gsl_vector *XLALcomputeBhatStatistic( const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i );
151
152double BstatIntegrandOuter( double cosi, void *p );
153double BstatIntegrandInner( double psi, void *p );
154double BstatIntegrand( double A[], size_t dim, void *p );
155
156REAL8 XLALComputeBhatCorrection( const gsl_vector *A_Mu, const gsl_matrix *M_mu_nu );
157
158/*----------------------------------------------------------------------*/
159/* Main Function starts here */
160/*----------------------------------------------------------------------*/
161/**
162 * MAIN function
163 * Generates samples of B-stat and F-stat according to their pdfs for given signal-params.
164 */
165int main( int argc, char *argv[] )
166{
168 ConfigVariables XLAL_INIT_DECL( GV ); /**< various derived configuration settings */
169 UINT4 i;
170 CHAR *version_string;
171
172 /* signal + data vectors */
173 gsl_matrix *Amp_i = NULL; /**< numDraws signal amplitude-params {h0Nat, cosi, psi, phi0} */
174 gsl_matrix *A_Mu_i = NULL; /**< list of 'numDraws' signal amplitude vectors {A^mu} */
175 gsl_matrix *s_mu_i = NULL; /**< list of 'numDraws' (covariant) signal amplitude vectors {s_mu = (s|h_mu) = M_mu_nu A^nu} */
176 gsl_matrix *n_mu_i = NULL; /**< list of 'numDraws' (covariant) noise vectors {n_mu = (n|h_mu)} */
177 gsl_matrix *x_mu_i = NULL; /**< list of 'numDraws' (covariant) data vectors {x_mu = n_mu + s_mu} */
178 gsl_matrix *x_Mu_i = NULL; /**< list of 'numDraws' (contravariant) data-vectors x^mu = A^mu_MLE = M^{mu nu} x_nu */
179
180 /* detection statistics */
181 gsl_vector *rho2_i = NULL; /**< list of 'numDraws' optimal SNRs^2 */
182 gsl_vector *lnL_i = NULL; /**< list of 'numDraws' log-likelihood statistics */
183 gsl_vector *Fstat_i = NULL; /**< list of 'numDraws' F-statistics */
184 gsl_vector *Bstat_i = NULL; /**< list of 'numDraws' B-statistics */
185 gsl_vector *Bhat_i = NULL; /**< list of 'numDraws' approximat B-statistics 'Bhat' */
186
187 int gslstat;
188
189 vrbflg = 1; /* verbose error-messages */
190
191 /* turn off default GSL error handler */
192 gsl_set_error_handler_off();
193
194 /* register all user-variable */
196
197 /* do ALL cmdline and cfgfile handling */
198 BOOLEAN should_exit = 0;
200 if ( should_exit ) {
201 return EXIT_FAILURE;
202 }
203
204 XLAL_CHECK_MAIN( ( version_string = XLALVCSInfoString( lalPulsarVCSInfoList, 0, "%% " ) ) != NULL, XLAL_EFUNC );
205
206 /* ---------- Initialize code-setup ---------- */
208
209 /* ---------- generate numDraws random draws of signals (A^mu, s_mu) */
210 XLAL_CHECK_MAIN( XLALsynthesizeSignals( &A_Mu_i, &s_mu_i, &Amp_i, &rho2_i, GV.M_mu_nu, GV.AmpRange, GV.rng, uvar.numDraws ) == XLAL_SUCCESS, XLAL_EFUNC );
211
212 /* ----- data = noise + signal: x_mu = n_mu + s_mu ----- */
213 XLAL_CHECK_MAIN( ( x_mu_i = gsl_matrix_calloc( uvar.numDraws, 4 ) ) != NULL, XLAL_ENOMEM );
214
215 if ( ! uvar.SignalOnly ) {
216 XLAL_CHECK_MAIN( XLALsynthesizeNoise( &n_mu_i, GV.M_mu_nu, GV.rng, uvar.numDraws ) == XLAL_SUCCESS, XLAL_EFUNC );
217 } else {
218 XLAL_CHECK_MAIN( ( n_mu_i = gsl_matrix_calloc( uvar.numDraws, 4 ) ) != NULL, XLAL_ENOMEM );
219 } /* if SignalOnly */
220
221 XLAL_CHECK_MAIN( ( gslstat = gsl_matrix_memcpy( x_mu_i, n_mu_i ) ) == 0, XLAL_EFAILED, "gsl_matrix_memcpy() failed): %s\n", gsl_strerror( gslstat ) );
222
223 XLAL_CHECK_MAIN( ( gslstat = gsl_matrix_add( x_mu_i, s_mu_i ) ) == 0, XLAL_EFAILED, "gsl_matrix_add() failed): %s\n", gsl_strerror( gslstat ) );
224
225 /* ---------- compute log likelihood ratio lnL ---------- */
226 XLAL_CHECK_MAIN( XLALcomputeLogLikelihood( &lnL_i, A_Mu_i, s_mu_i, x_mu_i ) == XLAL_SUCCESS, XLAL_EFUNC );
227
228 /* ---------- compute F-statistic ---------- */
229 XLAL_CHECK_MAIN( XLALcomputeFstatistic( &Fstat_i, &x_Mu_i, GV.M_mu_nu, x_mu_i ) == XLAL_SUCCESS, XLAL_EFUNC );
230
231 /* ---------- compute (full) B-statistic ---------- */
232 switch ( uvar.integrationMethod ) {
233 case 0:
235 break;
236
237 case 1:
238 XLAL_CHECK_MAIN( XLALcomputeBstatisticMC( &Bstat_i, GV.M_mu_nu, x_mu_i, GV.rng, uvar.numMCpoints ) == XLAL_SUCCESS, XLAL_EFUNC );
239 break;
240
241 default:
242 XLAL_ERROR_MAIN( XLAL_EINVAL, "Sorry, --integrationMethod = %d not implemented!\n", uvar.integrationMethod );
243 break;
244 } /* switch integrationMethod */
245
246
247 /* ---------- compute (approximate) B-statistic 'Bhat' ---------- */
248 XLAL_CHECK_MAIN( ( Bhat_i = XLALcomputeBhatStatistic( GV.M_mu_nu, x_mu_i ) ) != NULL, XLAL_EFUNC );
249
250 /* ---------- output F-statistic and B-statistic samples into file, if requested */
251 if ( uvar.outputStats ) {
252 FILE *fpStat = NULL;
253 CHAR *logstr = NULL;
254
255 XLAL_CHECK_MAIN( ( fpStat = fopen( uvar.outputStats, "wb" ) ) != NULL, XLAL_ESYS, "\nError opening file '%s' for writing..\n\n", uvar.outputStats );
256
257 /* log search-footprint at head of output-file */
259
260 fprintf( fpStat, "%%%% cmdline: %s\n", logstr );
261 XLALFree( logstr );
262 fprintf( fpStat, "%s\n", version_string );
263
264 /* append 'dataSummary' */
265 fprintf( fpStat, "%%%% h0Nat cosi psi phi0 n1 n2 n3 n4 rho2 lnL 2F Bstat Bhat\n" );
266 for ( i = 0; i < Bstat_i->size; i ++ ) {
267 fprintf( fpStat, "%10f %10f %10f %10f %10f %10f %10f %10f %12f %12f %12f %12f %12f\n",
268 gsl_matrix_get( Amp_i, i, 0 ),
269 gsl_matrix_get( Amp_i, i, 1 ),
270 gsl_matrix_get( Amp_i, i, 2 ),
271 gsl_matrix_get( Amp_i, i, 3 ),
272
273 gsl_matrix_get( n_mu_i, i, 0 ),
274 gsl_matrix_get( n_mu_i, i, 1 ),
275 gsl_matrix_get( n_mu_i, i, 2 ),
276 gsl_matrix_get( n_mu_i, i, 3 ),
277
278 gsl_vector_get( rho2_i, i ),
279
280 gsl_vector_get( lnL_i, i ),
281 gsl_vector_get( Fstat_i, i ),
282 gsl_vector_get( Bstat_i, i ),
283
284 gsl_vector_get( Bhat_i, i )
285 );
286 }
287 fclose( fpStat );
288 } /* if outputStat */
289
290 /* Free config-Variables and userInput stuff */
292 XLALFree( version_string );
293
294 gsl_matrix_free( GV.M_mu_nu );
295 gsl_matrix_free( s_mu_i );
296 gsl_matrix_free( Amp_i );
297 gsl_matrix_free( A_Mu_i );
298 gsl_vector_free( rho2_i );
299 gsl_vector_free( lnL_i );
300 gsl_vector_free( Fstat_i );
301 gsl_matrix_free( x_mu_i );
302 gsl_matrix_free( x_Mu_i );
303 gsl_matrix_free( n_mu_i );
304 gsl_vector_free( Bstat_i );
305 gsl_vector_free( Bhat_i );
306
307 gsl_rng_free( GV.rng );
308
309 /* did we forget anything ? */
311
312 return 0;
313
314} /* main() */
315
316/**
317 * Register all our "user-variables" that can be specified from cmd-line and/or config-file.
318 * Here we set defaults for some user-variables and register them with the UserInput module.
319 */
320int
322{
323 XLAL_CHECK( uvar != NULL, XLAL_EINVAL );
324
325 /* set a few defaults */
326 uvar->outputStats = NULL;
327
328 uvar->phi0 = 0;
329 uvar->psi = 0;
330
331 uvar->numDraws = 1;
332 uvar->numMCpoints = 1e4;
333
334 uvar->integrationMethod = 0; /* Gauss-Kronod integration */
335
336 uvar->E = 0; /* RAA approximation antenna-pattern matrix component M_{14}. Zero if using LWL */
337
338 /* register all our user-variables */
339 XLALRegisterUvarMember( h0Nat, REAL8, 's', OPTIONAL, "Overall GW amplitude h0 in *natural units*: h0Nat = h0 sqrt(T/Sn) " );
340 XLALRegisterUvarMember( h0NatBand, REAL8, 0, OPTIONAL, "Randomize amplitude within [h0, h0+h0Band] with uniform prior" );
341 XLALRegisterUvarMember( SNR, REAL8, 0, OPTIONAL, "Alternative: adjust h0 to obtain signal of exactly this optimal SNR" );
342
343 XLALRegisterUvarMember( cosi, REAL8, 'i', OPTIONAL, "cos(inclination angle). If not set: randomize within [-1,1]." );
344 XLALRegisterUvarMember( psi, REAL8, 0, OPTIONAL, "polarization angle psi. If not set: randomize within [-pi/4,pi/4]." );
345 XLALRegisterUvarMember( phi0, REAL8, 0, OPTIONAL, "initial GW phase phi_0. If not set: randomize within [0, 2pi]" );
346
347 XLALRegisterUvarMember( A, REAL8, 0, REQUIRED, "Antenna-pattern matrix MNat_mu_nu: component {1,1} = A = <|a|^2>" );
348 XLALRegisterUvarMember( B, REAL8, 0, REQUIRED, "Antenna-pattern matrix MNat_mu_nu: component {2,2} = B = <|b|^2>" );
349 XLALRegisterUvarMember( C, REAL8, 0, REQUIRED, "Antenna-pattern matrix MNat_mu_nu: component {1,2} = C = <Re(b a*)>" );
350 XLALRegisterUvarMember( E, REAL8, 0, OPTIONAL, "Antenna-pattern matrix MNat_mu_nu: component {1,4} = E = <Im(b a*)>" );
351
352 XLALRegisterUvarMember( numDraws, REAL8, 'N', OPTIONAL, "Number of random 'draws' to simulate for F-stat and B-stat" );
353
354 XLALRegisterUvarMember( outputStats, STRING, 'o', OPTIONAL, "Output file containing 'numDraws' random draws of lnL, 2F and B" );
355
356 XLALRegisterUvarMember( integrationMethod, INT4, 'm', OPTIONAL, "2D Integration-method: 0=Gauss-Kronod, 1=Monte-Carlo(Vegas)" );
357 XLALRegisterUvarMember( numMCpoints, REAL8, 'M', OPTIONAL, "Number of points to use in Monte-Carlo integration" );
358
359 XLALRegisterUvarMember( SignalOnly, BOOLEAN, 'S', OPTIONAL, "No noise-draws: will result in non-random 'signal only' values for F and B" );
360
361 return XLAL_SUCCESS;
362
363} /* initUserVars() */
364
365
366/** Initialized Fstat-code: handle user-input and set everything up. */
367int
369{
370 /* ----- parse user-input on signal amplitude-paramters + ranges ----- */
371
372 if ( XLALUserVarWasSet( &uvar->SNR ) && ( XLALUserVarWasSet( &uvar->h0Nat ) || XLALUserVarWasSet( &uvar->h0NatBand ) ) ) {
373 XLAL_ERROR( XLAL_EINVAL, "Don't specify either of {--h0,--h0Band} and --SNR\n" );
374 }
375
376 cfg->AmpRange.h0Nat = uvar->h0Nat;
377 cfg->AmpRange.h0NatBand = uvar->h0NatBand;
378 cfg->AmpRange.SNR = uvar->SNR;
379
380 /* implict ranges on cosi, psi and phi0 if not specified by user */
381 if ( XLALUserVarWasSet( &uvar->cosi ) ) {
382 cfg->AmpRange.cosi = uvar->cosi;
383 cfg->AmpRange.cosiBand = 0;
384 } else {
385 cfg->AmpRange.cosi = -1;
386 cfg->AmpRange.cosiBand = 2;
387 }
388 if ( XLALUserVarWasSet( &uvar->psi ) ) {
389 cfg->AmpRange.psi = uvar->psi;
390 cfg->AmpRange.psiBand = 0;
391 } else {
392 cfg->AmpRange.psi = - LAL_PI_4;
394 }
395 if ( XLALUserVarWasSet( &uvar->phi0 ) ) {
396 cfg->AmpRange.phi0 = uvar->phi0;
397 cfg->AmpRange.phi0Band = 0;
398 } else {
399 cfg->AmpRange.phi0 = 0;
401 }
402
403 /* ----- set up M_mu_nu matrix ----- */
404 if ( ( cfg->M_mu_nu = gsl_matrix_calloc( 4, 4 ) ) == NULL ) {
406 }
407
408 gsl_matrix_set( cfg->M_mu_nu, 0, 0, uvar->A );
409 gsl_matrix_set( cfg->M_mu_nu, 1, 1, uvar->B );
410 gsl_matrix_set( cfg->M_mu_nu, 0, 1, uvar->C );
411 gsl_matrix_set( cfg->M_mu_nu, 1, 0, uvar->C );
412
413 gsl_matrix_set( cfg->M_mu_nu, 2, 2, uvar->A );
414 gsl_matrix_set( cfg->M_mu_nu, 3, 3, uvar->B );
415 gsl_matrix_set( cfg->M_mu_nu, 2, 3, uvar->C );
416 gsl_matrix_set( cfg->M_mu_nu, 3, 2, uvar->C );
417
418 /* RAA components, only non-zero if NOT using the LWL approximation */
419 gsl_matrix_set( cfg->M_mu_nu, 0, 3, uvar->E );
420 gsl_matrix_set( cfg->M_mu_nu, 1, 2, -uvar->E );
421 gsl_matrix_set( cfg->M_mu_nu, 3, 0, uvar->E );
422 gsl_matrix_set( cfg->M_mu_nu, 2, 1, -uvar->E );
423
424 /* ----- initialize random-number generator ----- */
425 /* read out environment variables GSL_RNG_xxx
426 * GSL_RNG_SEED: use to set random seed: defult = 0
427 * GSL_RNG_TYPE: type of random-number generator to use: default = 'mt19937'
428 */
429 gsl_rng_env_setup();
430 cfg->rng = gsl_rng_alloc( gsl_rng_default );
431
432 LogPrintf( LOG_DEBUG, "random-number generator type: %s\n", gsl_rng_name( cfg->rng ) );
433 LogPrintf( LOG_DEBUG, "seed = %lu\n", gsl_rng_default_seed );
434
435 return XLAL_SUCCESS;
436
437} /* InitCode() */
438
439
440/**
441 * Generate random signal draws with uniform priors in given bands [h0, cosi, psi, phi0], and
442 * return list of 'numDraws' {s_mu} vectors.
443 */
444int
445XLALsynthesizeSignals( gsl_matrix **A_Mu_i, /**< [OUT] list of numDraws 4D line-vectors {A^nu} */
446 gsl_matrix **s_mu_i, /**< [OUT] list of numDraws 4D line-vectors {s_mu = M_mu_nu A^nu} */
447 gsl_matrix **Amp_i, /**< [OUT] list of numDraws 4D amplitude-parameters {h0, cosi, psi, phi} */
448 gsl_vector **rho2_i, /**< [OUT] optimal SNR^2 */
449 const gsl_matrix *M_mu_nu, /**< antenna-pattern matrix M_mu_nu */
450 AmpParamsRange_t AmpRange, /**< signal amplitude-parameters ranges: lower bound + bands */
451 gsl_rng *rng, /**< gsl random-number generator */
452 UINT4 numDraws /**< number of random draws to synthesize */
453 )
454{
455 UINT4 row;
456
457 REAL8 h0NatMin, h0NatMax;
458 REAL8 cosiMin = AmpRange.cosi;
459 REAL8 cosiMax = cosiMin + AmpRange.cosiBand;
460 REAL8 psiMin = AmpRange.psi;
461 REAL8 psiMax = psiMin + AmpRange.psiBand;
462 REAL8 phi0Min = AmpRange.phi0;
463 REAL8 phi0Max = phi0Min + AmpRange.phi0Band;
464 REAL8 SNR = AmpRange.SNR;
465 REAL8 res_rho2;
466 REAL8 h0, cosi;
467
468 int gslstat;
469
470 /* ----- check input arguments ----- */
471 if ( !M_mu_nu || M_mu_nu->size1 != M_mu_nu->size2 || M_mu_nu->size1 != 4 ) {
472 LogPrintf( LOG_CRITICAL, "%s: Invalid input, M_mu_nu must be a 4x4 matrix.", __func__ );
473 return XLAL_EINVAL;
474 }
475 if ( !( numDraws > 0 ) ) {
476 LogPrintf( LOG_CRITICAL, "%s: Invalid input, numDraws must be > 0.", __func__ );
477 return XLAL_EINVAL;
478 }
479 if ( ( ( *A_Mu_i ) != NULL ) || ( ( *s_mu_i ) != NULL ) || ( ( *Amp_i ) != NULL ) ) {
480 LogPrintf( LOG_CRITICAL, "%s: Invalid input: output-vectors A_Mu_i, s_mu_i and Amp_i must be set to NULL.", __func__ );
481 return XLAL_EINVAL;
482 }
483
484 /* ----- allocate return signal amplitude vectors ---------- */
485 if ( ( ( *A_Mu_i ) = gsl_matrix_calloc( numDraws, 4 ) ) == NULL ) {
486 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc (%d, 4) failed.\n", __func__, numDraws );
487 return XLAL_ENOMEM;
488 }
489 if ( ( ( *s_mu_i ) = gsl_matrix_calloc( numDraws, 4 ) ) == NULL ) {
490 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc (%d, 4) failed.\n", __func__, numDraws );
491 return XLAL_ENOMEM;
492 }
493 if ( ( ( *Amp_i ) = gsl_matrix_calloc( numDraws, 4 ) ) == NULL ) {
494 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc (%d, 4) failed.\n", __func__, numDraws );
495 return XLAL_ENOMEM;
496 }
497
498 if ( ( ( *rho2_i ) = gsl_vector_calloc( numDraws ) ) == NULL ) {
499 LogPrintf( LOG_CRITICAL, "%s: gsl_vector_calloc (%d) failed.\n", __func__, numDraws );
500 return XLAL_ENOMEM;
501 }
502
503 /* ----- allocate temporary interal storage vectors */
504 PulsarAmplitudeVect A_Mu_data = {0, 0, 0, 0}, s_mu_data = {0, 0, 0, 0};
505
506 if ( SNR > 0 ) {
507 h0NatMin = 1;
508 h0NatMax = 1;
509 } else {
510 h0NatMin = AmpRange.h0Nat;
511 h0NatMax = h0NatMin + AmpRange.h0NatBand;
512 }
513
514 for ( row = 0; row < numDraws; row ++ ) {
516
517 h0 = gsl_ran_flat( rng, h0NatMin, h0NatMax );
518 cosi = gsl_ran_flat( rng, cosiMin, cosiMax );
519 Amp.aPlus = 0.5 * h0 * ( 1.0 + SQ( cosi ) );
520 Amp.aCross = h0 * cosi;
521 Amp.psi = gsl_ran_flat( rng, psiMin, psiMax );
522 Amp.phi0 = gsl_ran_flat( rng, phi0Min, phi0Max );
523
524 XLALAmplitudeParams2Vect( A_Mu_data, Amp );
525
526 /* testing inversion property
527 {
528 REAL8 a1, a2, a3, a4;
529 XLALAmplitudeVect2Params ( &a1, &a2, &a3, &a4, A_Mu );
530 printf ("h0 = %f, cosi = %f, psi = %f, phi0 = %f\n", h0Nat, cosi, psi, phi0 );
531 printf ("a1 = %f, a2 = %f, a3 = %f, a4 = %f\n", a1, a2, a3, a4 );
532 }
533 */
534
535 /* set gsl-vector views on the fixed-size arrays A_Mu_data and s_mu_data */
536
537 gsl_vector_view A_Mu = gsl_vector_view_array( A_Mu_data, 4 );
538 gsl_vector_view s_mu = gsl_vector_view_array( s_mu_data, 4 );
539
540 /* GSL-doc: int gsl_blas_dsymv (CBLAS_UPLO_t Uplo, double alpha, const gsl_matrix * A,
541 * const gsl_vector * x, double beta, gsl_vector * y )
542 *
543 * compute the matrix-vector product and sum: y = alpha A x + beta y
544 * for the symmetric matrix A. Since the matrix A is symmetric only its
545 * upper half or lower half need to be stored. When Uplo is CblasUpper
546 * then the upper triangle and diagonal of A are used, and when Uplo
547 * is CblasLower then the lower triangle and diagonal of A are used.
548 */
549 if ( ( gslstat = gsl_blas_dsymv( CblasUpper, 1.0, M_mu_nu, &A_Mu.vector, 0.0, &s_mu.vector ) ) ) {
550 LogPrintf( LOG_CRITICAL, "%s: gsl_blas_dsymv(M_mu_nu * A^mu failed): %s\n", __func__, gsl_strerror( gslstat ) );
551 return XLAL_EDOM;
552 }
553
554 /* compute optimal SNR for this signal: rho2 = A^mu M_{mu,nu} A^nu = A^mu s_mu */
555 if ( ( gslstat = gsl_blas_ddot( &A_Mu.vector, &s_mu.vector, &res_rho2 ) ) ) {
556 LogPrintf( LOG_CRITICAL, "%s: lnL = gsl_blas_ddot(A^mu * s_mu) failed: %s\n", __func__, gsl_strerror( gslstat ) );
557 return XLAL_EDOM;
558 }
559
560 /* if specified SNR: rescale signal to this SNR */
561 if ( SNR > 0 ) {
562 REAL8 rescale_h0 = SNR / sqrt( res_rho2 );
563 Amp.aPlus *= rescale_h0;
564 Amp.aCross *= rescale_h0;
565 res_rho2 = SQ( SNR );
566 gsl_vector_scale( &A_Mu.vector, rescale_h0 );
567 gsl_vector_scale( &s_mu.vector, rescale_h0 );
568 }
569
570 gsl_vector_set( *rho2_i, row, res_rho2 );
571
572 gsl_matrix_set( *Amp_i, row, 0, h0 );
573 gsl_matrix_set( *Amp_i, row, 1, cosi );
574 gsl_matrix_set( *Amp_i, row, 2, Amp.psi );
575 gsl_matrix_set( *Amp_i, row, 3, Amp.phi0 );
576
577 gsl_matrix_set_row( *A_Mu_i, row, &A_Mu.vector );
578 gsl_matrix_set_row( *s_mu_i, row, &s_mu.vector );
579
580 /*
581 printf("A^mu = ");
582 XLALfprintfGSLvector ( stdout, "%g", A_Mu );
583 printf("s_mu = ");
584 XLALfprintfGSLvector ( stdout, "%g", s_mu );
585 */
586
587 } /* row < numDraws */
588
589 return XLAL_SUCCESS;
590
591} /* XLALsynthesizeSignals() */
592
593
594/**
595 * Generate random-noise draws and combine with (FIXME: single!) signal.
596 * Returns a list of numDraws vectors {x_mu}
597 */
598int
599XLALsynthesizeNoise( gsl_matrix **n_mu_i, /**< [OUT] list of numDraws 4D line-vectors of noise-components {n_mu} */
600 const gsl_matrix *M_mu_nu, /**< 4x4 antenna-pattern matrix */
601 gsl_rng *rng, /**< gsl random-number generator */
602 UINT4 numDraws /**< number of random draws to synthesize */
603 )
604{
605 gsl_matrix *tmp, *M_chol;
606 UINT4 row, col;
607 gsl_matrix *normal;
608 int gslstat;
609
610 /* ----- check input arguments ----- */
611 if ( !M_mu_nu || M_mu_nu->size1 != M_mu_nu->size2 || M_mu_nu->size1 != 4 ) {
612 LogPrintf( LOG_CRITICAL, "%s: Invalid input, M_mu_nu must be a 4x4 matrix.", __func__ );
613 return XLAL_EINVAL;
614 }
615 if ( !( numDraws > 0 ) ) {
616 LogPrintf( LOG_CRITICAL, "%s: Invalid input, numDraws must be > 0.", __func__ );
617 return XLAL_EINVAL;
618 }
619 if ( ( ( *n_mu_i ) != NULL ) ) {
620 LogPrintf( LOG_CRITICAL, "%s: Invalid input: output vector n_mu_i must be set to NULL.", __func__ );
621 return XLAL_EINVAL;
622 }
623
624 /* ----- allocate return vector of nnoise components n_mu ----- */
625 if ( ( ( *n_mu_i ) = gsl_matrix_calloc( numDraws, 4 ) ) == NULL ) {
626 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc (%d, 4) failed.\n", __func__, numDraws );
627 return XLAL_ENOMEM;
628 }
629
630 /* ----- Cholesky decompose M_mu_nu = L . L^T ----- */
631 if ( ( M_chol = gsl_matrix_calloc( 4, 4 ) ) == NULL ) {
632 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc(4,4) failed\n", __func__ );
633 return XLAL_ENOMEM;
634 }
635 if ( ( tmp = gsl_matrix_calloc( 4, 4 ) ) == NULL ) {
636 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc(4,4) failed\n", __func__ );
637 return XLAL_ENOMEM;
638 }
639 if ( ( gslstat = gsl_matrix_memcpy( tmp, M_mu_nu ) ) ) {
640 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_memcpy() failed: %s\n", __func__, gsl_strerror( gslstat ) );
641 return XLAL_EDOM;
642 }
643 if ( ( gslstat = gsl_linalg_cholesky_decomp( tmp ) ) ) {
644 LogPrintf( LOG_CRITICAL, "%s: gsl_linalg_cholesky_decomp(M_mu_nu) failed: %s\n", __func__, gsl_strerror( gslstat ) );
645 return XLAL_EDOM;
646 }
647 /* copy lower triangular matrix, which is L */
648 for ( row = 0; row < 4; row ++ )
649 for ( col = 0; col <= row; col ++ ) {
650 gsl_matrix_set( M_chol, row, col, gsl_matrix_get( tmp, row, col ) );
651 }
652
653 /* ----- generate 'numDraws' normal-distributed random numbers ----- */
654 if ( ( normal = gsl_matrix_calloc( numDraws, 4 ) ) == NULL ) {
655 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc(%d,4) failed\n", __func__, numDraws );
656 return XLAL_ENOMEM;
657 }
658
659 for ( row = 0; row < numDraws; row ++ ) {
660 gsl_matrix_set( normal, row, 0, gsl_ran_gaussian( rng, 1.0 ) );
661 gsl_matrix_set( normal, row, 1, gsl_ran_gaussian( rng, 1.0 ) );
662 gsl_matrix_set( normal, row, 2, gsl_ran_gaussian( rng, 1.0 ) );
663 gsl_matrix_set( normal, row, 3, gsl_ran_gaussian( rng, 1.0 ) );
664 } /* for row < numDraws */
665
666 /* use four normal-variates {norm_nu} with Cholesky decomposed matrix L to get: n_mu = L_{mu nu} norm_nu
667 * which gives {n_\mu} satisfying cov(n_mu,n_nu) = M_mu_nu
668 */
669 for ( row = 0; row < numDraws; row ++ ) {
670 gsl_vector_const_view normi = gsl_matrix_const_row( normal, row );
671 gsl_vector_view ni = gsl_matrix_row( *n_mu_i, row );
672
673 /* int gsl_blas_dgemv (CBLAS_TRANSPOSE_t TransA, double alpha, const gsl_matrix * A, const gsl_vector * x, double beta, gsl_vector * y)
674 * compute the matrix-vector product and sum y = \alpha op(A) x + \beta y, where op(A) = A, A^T, A^H
675 * for TransA = CblasNoTrans, CblasTrans, CblasConjTrans.
676 */
677 if ( ( gslstat = gsl_blas_dgemv( CblasNoTrans, 1.0, M_chol, &( normi.vector ), 0.0, &( ni.vector ) ) ) ) {
678 LogPrintf( LOG_CRITICAL, "%s: gsl_blas_dgemv(M_chol * ni) failed: %s\n", __func__, gsl_strerror( gslstat ) );
679 return 1;
680 }
681 } /* for row < numDraws */
682
683 /* ---------- free memory ---------- */
684 gsl_matrix_free( tmp );
685 gsl_matrix_free( M_chol );
686 gsl_matrix_free( normal );
687
688 return XLAL_SUCCESS;
689
690} /* XLALsynthesizeNoise() */
691
692
693
694/**
695 * Compute log-likelihood function for given input data
696 */
697int
698XLALcomputeLogLikelihood( gsl_vector **lnL_i, /**< [OUT] log-likelihood vector */
699 const gsl_matrix *A_Mu_i, /**< 4D amplitude-vector (FIXME: numDraws) */
700 const gsl_matrix *s_mu_i, /**< 4D signal-component vector s_mu = (s|h_mu) [FIXME] */
701 const gsl_matrix *x_mu_i /**< numDraws x 4D data-vectors x_mu */
702 )
703{
704 int gslstat;
705 UINT4 row, numDraws;
706 gsl_matrix *tmp;
707 REAL8 res_lnL;
708
709 /* ----- check input arguments ----- */
710 if ( ( *lnL_i ) != NULL ) {
711 LogPrintf( LOG_CRITICAL, "%s: output vector 'lnL_i' must be set to NULL.\n", __func__ );
712 return XLAL_EINVAL;
713 }
714 if ( !A_Mu_i || !s_mu_i || !x_mu_i ) {
715 LogPrintf( LOG_CRITICAL, "%s: input vectors A_Mu_i, s_mu_i must not be NULL.\n", __func__ );
716 return XLAL_EINVAL;
717 }
718
719 numDraws = A_Mu_i->size1;
720 if ( !( numDraws > 0 ) ) {
721 LogPrintf( LOG_CRITICAL, "%s: Invalid input, numDraws must be > 0.", __func__ );
722 return XLAL_EINVAL;
723 }
724
725 if ( ( A_Mu_i->size1 != numDraws ) || ( A_Mu_i->size2 != 4 ) ) {
726 LogPrintf( LOG_CRITICAL, "%s: input Amplitude-vector A^mu must be numDraws(=%d) x 4D.\n", __func__, numDraws );
727 return XLAL_EINVAL;
728 }
729 if ( ( s_mu_i->size1 != numDraws ) || ( s_mu_i->size2 != 4 ) ) {
730 LogPrintf( LOG_CRITICAL, "%s: input Amplitude-vector s_mu must be numDraws(=%d) x 4D.\n", __func__, numDraws );
731 return XLAL_EINVAL;
732 }
733 if ( ( x_mu_i->size1 != numDraws ) || ( x_mu_i->size2 != 4 ) ) {
734 LogPrintf( LOG_CRITICAL, "%s: input vector-list x_mu_i must be numDraws(=%d) x 4.\n", __func__, numDraws );
735 return XLAL_EINVAL;
736 }
737
738 /* ----- allocate return statistics vector ---------- */
739 if ( ( ( *lnL_i ) = gsl_vector_calloc( numDraws ) ) == NULL ) {
740 LogPrintf( LOG_CRITICAL, "%s: gsl_vector_calloc (%d) failed.\n", __func__, numDraws );
741 return XLAL_ENOMEM;
742 }
743
744 /* ----- allocate temporary internal storage ---------- */
745 if ( ( tmp = gsl_matrix_alloc( numDraws, 4 ) ) == NULL ) {
746 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_alloc(%d,4) failed.\n", __func__, numDraws );
747 return XLAL_ENOMEM;
748 }
749
750 /* STEP1: compute tmp_mu = x_mu - 0.5 s_mu */
751 gsl_matrix_memcpy( tmp, s_mu_i );
752 gsl_matrix_scale( tmp, - 0.5 );
753 gsl_matrix_add( tmp, x_mu_i );
754
755
756 /* STEP2: compute A^mu tmp_mu */
757 for ( row = 0; row < numDraws; row ++ ) {
758 gsl_vector_const_view A_Mu = gsl_matrix_const_row( A_Mu_i, row );
759 gsl_vector_const_view d_mu = gsl_matrix_const_row( tmp, row );
760
761 /* Function: int gsl_blas_ddot (const gsl_vector * x, const gsl_vector * y, double * result)
762 * These functions compute the scalar product x^T y for the vectors x and y, returning the result in result.
763 */
764 if ( ( gslstat = gsl_blas_ddot( &A_Mu.vector, &d_mu.vector, &res_lnL ) ) ) {
765 LogPrintf( LOG_CRITICAL, "%s: lnL = gsl_blas_ddot(A^mu * (x_mu - 0.5 s_mu) failed: %s\n", __func__, gsl_strerror( gslstat ) );
766 return 1;
767 }
768
769 gsl_vector_set( *lnL_i, row, res_lnL );
770
771
772 } /* for row < numDraws */
773
774 gsl_matrix_free( tmp );
775
776 return 0;
777
778} /* XLALcomputeLogLikelihood() */
779
780
781/**
782 * Compute F-statistic for given input data
783 */
784int
785XLALcomputeFstatistic( gsl_vector **Fstat_i, /**< [OUT] F-statistic vector */
786 gsl_matrix **A_Mu_MLE_i, /**< [OUT] vector of {A^mu_MLE} amplitude-vectors */
787 const gsl_matrix *M_mu_nu, /**< antenna-pattern matrix M_mu_nu */
788 const gsl_matrix *x_mu_i /**< data-vectors x_mu: numDraws x 4 */
789 )
790{
791 int sig;
792 gsl_permutation *perm = gsl_permutation_calloc( 4 );
793 gsl_matrix *Mmunu_LU = gsl_matrix_calloc( 4, 4 );
794 int gslstat;
795 UINT4 row, numDraws;
796
797 /* ----- check input arguments ----- */
798 if ( !M_mu_nu || !x_mu_i ) {
799 LogPrintf( LOG_CRITICAL, "%s: input M_mu_nu and x_mu_i must not be NULL.\n", __func__ );
800 return XLAL_EINVAL;
801 }
802 if ( ( ( *Fstat_i ) != NULL ) ) {
803 LogPrintf( LOG_CRITICAL, "%s: output vector 'Fstat_i' must be set to NULL.\n", __func__ );
804 return XLAL_EINVAL;
805 }
806
807 numDraws = x_mu_i->size1;
808 if ( !( numDraws > 0 ) ) {
809 LogPrintf( LOG_CRITICAL, "%s: Invalid input, numDraws must be > 0.", __func__ );
810 return XLAL_EINVAL;
811 }
812
813 if ( ( M_mu_nu->size1 != 4 ) || ( M_mu_nu->size2 != 4 ) ) {
814 LogPrintf( LOG_CRITICAL, "%s: antenna-pattern matrix M_mu_nu must be 4x4.\n", __func__ );
815 return XLAL_EINVAL;
816 }
817 if ( ( x_mu_i->size1 != numDraws ) || ( x_mu_i->size2 != 4 ) ) {
818 LogPrintf( LOG_CRITICAL, "%s: input vector-list x_mu_i must be numDraws(=%d) x 4.\n", __func__, numDraws );
819 return XLAL_EINVAL;
820 }
821
822 /* ----- allocate return statistics vector ---------- */
823 if ( ( ( *Fstat_i ) = gsl_vector_calloc( numDraws ) ) == NULL ) {
824 LogPrintf( LOG_CRITICAL, "%s: gsl_vector_calloc (%d) failed.\n", __func__, numDraws );
825 return XLAL_ENOMEM;
826 }
827 if ( ( ( *A_Mu_MLE_i ) = gsl_matrix_calloc( numDraws, 4 ) ) == NULL ) {
828 LogPrintf( LOG_CRITICAL, "%s: gsl_matrix_calloc (%d)x4 failed.\n", __func__, numDraws );
829 return XLAL_ENOMEM;
830 }
831
832 gsl_matrix_memcpy( Mmunu_LU, M_mu_nu );
833
834 /* Function: int gsl_linalg_LU_decomp (gsl_matrix * A, gsl_permutation * p, int * signum)
835 *
836 * These functions factorize the square matrix A into the LU decomposition PA = LU.
837 * On output the diagonal and upper triangular part of the input matrix A contain the matrix U. The lower
838 * triangular part of the input matrix (excluding the diagonal) contains L. The diagonal elements of L are
839 * unity, and are not stored. The permutation matrix P is encoded in the permutation p. The j-th column of
840 * the matrix P is given by the k-th column of the identity matrix, where k = p_j the j-th element of the
841 * permutation vector. The sign of the permutation is given by signum. It has the value (-1)^n, where n is
842 * the number of interchanges in the permutation.
843 * The algorithm used in the decomposition is Gaussian Elimination with partial pivoting
844 * (Golub & Van Loan, Matrix Computations, Algorithm 3.4.1).
845 */
846 if ( ( gslstat = gsl_linalg_LU_decomp( Mmunu_LU, perm, &sig ) ) ) {
847 LogPrintf( LOG_CRITICAL, "%s: gsl_linalg_LU_decomp (Mmunu) failed: %s\n", __func__, gsl_strerror( gslstat ) );
848 return 1;
849 }
850
851 for ( row = 0; row < numDraws; row ++ ) {
852 gsl_vector_const_view xi = gsl_matrix_const_row( x_mu_i, row );
853 gsl_vector_view x_Mu = gsl_matrix_row( ( *A_Mu_MLE_i ), row );
854 double x2;
855
856 /* STEP 1: compute x^mu = M^{mu,nu} x_nu */
857
858 /*
859 printf("x_mu = ");
860 XLALfprintfGSLvector ( stdout, "%g", &(xi.vector) );
861 */
862
863 /* Function: int gsl_linalg_LU_solve (const gsl_matrix * LU, const gsl_permutation * p, const gsl_vector * b, gsl_vector * x)
864 *
865 * These functions solve the square system A x = b using the LU decomposition of A into (LU, p) given by
866 * gsl_linalg_LU_decomp or gsl_linalg_complex_LU_decomp.
867 */
868 if ( ( gslstat = gsl_linalg_LU_solve( Mmunu_LU, perm, &( xi.vector ), &( x_Mu.vector ) ) ) ) {
869 LogPrintf( LOG_CRITICAL, "%s: gsl_linalg_LU_solve (x^Mu = M^{mu,nu} x_nu) failed: %s\n", __func__, gsl_strerror( gslstat ) );
870 return 1;
871 }
872
873#if 0
874 {
875 REAL8 h0, cosi, psi, phi0;
876
877 XLALAmplitudeVect2Params( &h0, &cosi, &psi, &phi0, &( x_Mu.vector ) );
878 fprintf( stderr, "A^mu_MLE = " );
879 XLALfprintfGSLvector( stderr, "%g", &( x_Mu.vector ) );
880 fprintf( stderr, "MLE: h0 = %g, cosi = %g, psi = %g, phi0 = %g\n", h0, cosi, psi, phi0 );
881 }
882#endif
883
884 /* STEP 2: compute scalar product x_mu x^mu */
885
886 /* Function: int gsl_blas_ddot (const gsl_vector * x, const gsl_vector * y, double * result)
887 *
888 * These functions compute the scalar product x^T y for the vectors x and y, returning the result in result.
889 */
890 if ( ( gslstat = gsl_blas_ddot( &( xi.vector ), &( x_Mu.vector ), &x2 ) ) ) {
891 LogPrintf( LOG_CRITICAL, "%s: row = %d: int gsl_blas_ddot (x_mu x^mu) failed: %s\n", __func__, row, gsl_strerror( gslstat ) );
892 return 1;
893 }
894
895 /* write result into Fstat (=2F) vector */
896 gsl_vector_set( *Fstat_i, row, x2 );
897
898 } /* for row < numDraws */
899
900 gsl_permutation_free( perm );
901 gsl_matrix_free( Mmunu_LU );
902
903 return 0;
904
905} /* XLALcomputeFstatistic () */
906
907
908/**
909 * Compute the B-statistic for given input data, using Monte-Carlo integration for
910 * the marginalization over {cosi, psi}, while {h0, phi0} have been marginalized analytically.
911 *
912 * Currently uses the Vegas Monte-Carlo integrator, which samples more densely where the integrand is larger.
913 */
914int
915XLALcomputeBstatisticMC( gsl_vector **Bstat_i, /**< [OUT] vector of numDraws B-statistic values */
916 const gsl_matrix *M_mu_nu, /**< antenna-pattern matrix M_mu_nu */
917 const gsl_matrix *x_mu_i, /**< data-vectors x_mu: numDraws x 4 */
918 gsl_rng *rng, /**< gsl random-number generator */
919 UINT4 numMCpoints /**< number of points to use in Monte-Carlo integration */
920 )
921{
922 gsl_monte_vegas_state *MCS_vegas = gsl_monte_vegas_alloc( 2 );
923 gsl_monte_function F;
925 UINT4 row, numDraws;
926 int gslstat;
927
928 /* ----- check input arguments ----- */
929 if ( !M_mu_nu || !x_mu_i || !rng ) {
930 LogPrintf( LOG_CRITICAL, "%s: input M_mu_nu, x_mu_i and rng must not be NULL.\n", __func__ );
931 return XLAL_EINVAL;
932 }
933 if ( ( ( *Bstat_i ) != NULL ) ) {
934 LogPrintf( LOG_CRITICAL, "%s: output vector 'Bstat_i' must be set to NULL.\n", __func__ );
935 return XLAL_EINVAL;
936 }
937
938 numDraws = x_mu_i->size1;
939 if ( !( numDraws > 0 ) ) {
940 LogPrintf( LOG_CRITICAL, "%s: Invalid input, numDraws must be > 0.", __func__ );
941 return XLAL_EINVAL;
942 }
943
944 if ( ( M_mu_nu->size1 != 4 ) || ( M_mu_nu->size2 != 4 ) ) {
945 LogPrintf( LOG_CRITICAL, "%s: antenna-pattern matrix M_mu_nu must be 4x4.\n", __func__ );
946 return XLAL_EINVAL;
947 }
948 if ( ( x_mu_i->size1 != numDraws ) || ( x_mu_i->size2 != 4 ) ) {
949 LogPrintf( LOG_CRITICAL, "%s: input vector-list x_mu_i must be numDraws(=%d) x 4.\n", __func__, numDraws );
950 return XLAL_EINVAL;
951 }
952
953 /* ----- allocate return signal amplitude vectors ---------- */
954 if ( ( ( *Bstat_i ) = gsl_vector_calloc( numDraws ) ) == NULL ) {
955 LogPrintf( LOG_CRITICAL, "%s: gsl_vector_calloc (%d) failed.\n", __func__, numDraws );
956 return XLAL_ENOMEM;
957 }
958
959
960 /* ----- prepare Monte-Carlo integrator ----- */
961 pars.A = gsl_matrix_get( M_mu_nu, 0, 0 );
962 pars.B = gsl_matrix_get( M_mu_nu, 1, 1 );
963 pars.C = gsl_matrix_get( M_mu_nu, 0, 1 );
964 pars.E = gsl_matrix_get( M_mu_nu, 0, 3 );
965
966 F.f = &BstatIntegrand;
967 F.dim = 2;
968 F.params = &pars;
969
970 for ( row = 0; row < numDraws; row ++ ) {
971 gsl_vector_const_view xi = gsl_matrix_const_row( x_mu_i, row );
972 double Bb;
973 double AmpLower[2], AmpUpper[2];
974 double abserr;
975 pars.x_mu = &( xi.vector );
976
977 gsl_monte_vegas_init( MCS_vegas );
978
979 /* Integration boundaries */
980 AmpLower[0] = -1; /* cosi */
981 AmpUpper[0] = 1; /* cosi */
982
983 AmpLower[1] = -LAL_PI_4; /* psi */
984 AmpUpper[1] = LAL_PI_4; /* psi */
985
986 /* Function: int gsl_monte_vegas_integrate (gsl_monte_function * f, double * xl, double * xu, size_t dim, size_t calls,
987 * gsl_rng * r, gsl_monte_vegas_state * s, double * result, double * abserr)
988 *
989 * This routines uses the vegas Monte Carlo algorithm to integrate the function f over the dim-dimensional hypercubic
990 * region defined by the lower and upper limits in the arrays xl and xu, each of size dim. The integration uses a
991 * fixed number of function calls calls, and obtains random sampling points using the random number generator r.
992 * A previously allocated workspace s must be supplied. The result of the integration is returned in result, with
993 * an estimated absolute error abserr. The result and its error estimate are based on a weighted average of independent
994 * samples. The chi-squared per degree of freedom for the weighted average is returned via the state struct component,
995 * s->chisq, and must be consistent with 1 for the weighted average to be reliable.
996 */
997 if ( ( gslstat = gsl_monte_vegas_integrate( &F, AmpLower, AmpUpper, 2, numMCpoints, rng, MCS_vegas, &Bb, &abserr ) ) ) {
998 LogPrintf( LOG_CRITICAL, "%s: row = %d: gsl_monte_vegas_integrate() failed: %s\n", __func__, row, gsl_strerror( gslstat ) );
999 return 1;
1000 }
1001 gsl_vector_set( *Bstat_i, row, 2.0 * log( Bb ) );
1002
1003 } /* row < numDraws */
1004
1005 gsl_monte_vegas_free( MCS_vegas );
1006
1007 return 0;
1008
1009} /* XLALcomputeBstatisticMC() */
1010
1011
1012/**
1013 * Compute the B-statistic for given input data, using standard Gauss-Kronod integration (gsl_integration_qng)
1014 * for the marginalization over {cosi, psi}, while {h0, phi0} have been marginalized analytically.
1015 *
1016 */
1017int
1018XLALcomputeBstatisticGauss( gsl_vector **Bstat_i, /**< [OUT] vector of numDraws B-statistic values */
1019 const gsl_matrix *M_mu_nu, /**< antenna-pattern matrix M_mu_nu */
1020 const gsl_matrix *x_mu_i /**< data-vectors x_mu: numDraws x 4 */
1021 )
1022{
1023 UINT4 row, numDraws;
1024 int gslstat;
1025 double epsabs = 0;
1026 double epsrel = 1e-2;
1027 double abserr;
1028 gsl_function F;
1030
1031 gsl_integration_workspace *w = gsl_integration_workspace_alloc( 1000 );
1032
1033 /* ----- check input arguments ----- */
1034 if ( !M_mu_nu || !x_mu_i ) {
1035 LogPrintf( LOG_CRITICAL, "%s: input M_mu_nu, x_mu_i must not be NULL.\n", __func__ );
1036 return XLAL_EINVAL;
1037 }
1038
1039 if ( ( ( *Bstat_i ) != NULL ) ) {
1040 LogPrintf( LOG_CRITICAL, "%s: output vector 'Bstat_i' must be set to NULL.\n", __func__ );
1041 return XLAL_EINVAL;
1042 }
1043
1044 numDraws = x_mu_i->size1;
1045 if ( !( numDraws > 0 ) ) {
1046 LogPrintf( LOG_CRITICAL, "%s: Invalid input, numDraws must be > 0.", __func__ );
1047 return XLAL_EINVAL;
1048 }
1049
1050 if ( ( M_mu_nu->size1 != 4 ) || ( M_mu_nu->size2 != 4 ) ) {
1051 LogPrintf( LOG_CRITICAL, "%s: antenna-pattern matrix M_mu_nu must be 4x4.\n", __func__ );
1052 return XLAL_EINVAL;
1053 }
1054 if ( ( x_mu_i->size1 != numDraws ) || ( x_mu_i->size2 != 4 ) ) {
1055 LogPrintf( LOG_CRITICAL, "%s: input vector-list x_mu_i must be numDraws x 4.\n", __func__ );
1056 return XLAL_EINVAL;
1057 }
1058
1059 /* ----- allocate return signal amplitude vectors ---------- */
1060 if ( ( ( *Bstat_i ) = gsl_vector_calloc( numDraws ) ) == NULL ) {
1061 LogPrintf( LOG_CRITICAL, "%s: gsl_vector_calloc (%d) failed.\n", __func__, numDraws );
1062 return XLAL_ENOMEM;
1063 }
1064
1065 /* ----- prepare Gauss-Kronod integrator ----- */
1066 pars.A = gsl_matrix_get( M_mu_nu, 0, 0 );
1067 pars.B = gsl_matrix_get( M_mu_nu, 1, 1 );
1068 pars.C = gsl_matrix_get( M_mu_nu, 0, 1 );
1069 pars.E = gsl_matrix_get( M_mu_nu, 0, 3 );
1070
1071 F.function = &BstatIntegrandOuter;
1072 F.params = &pars;
1073
1074 for ( row = 0; row < numDraws; row ++ ) {
1075 gsl_vector_const_view xi = gsl_matrix_const_row( x_mu_i, row );
1076 double Bb;
1077 double CosiLower, CosiUpper;
1078
1079 pars.x_mu = &( xi.vector );
1080
1081 /* Integration boundaries */
1082 CosiLower = -1;
1083 CosiUpper = 1;
1084
1085 /* Function: int gsl_integration_qags (const gsl_function * f, double a, double b, double epsabs, double epsrel,
1086 * size_t limit, gsl_integration_workspace * workspace, double * result, double * abserr)
1087 *
1088 * This function applies the Gauss-Kronrod 21-point integration rule adaptively until an estimate of the integral
1089 * of f over (a,b) is achieved within the desired absolute and relative error limits, epsabs and epsrel. The results
1090 * are extrapolated using the epsilon-algorithm, which accelerates the convergence of the integral in the presence of
1091 * discontinuities and integrable singularities. The function returns the final approximation from the extrapolation,
1092 * result, and an estimate of the absolute error, abserr. The subintervals and their results are stored in the memory
1093 * provided by workspace. The maximum number of subintervals is given by limit, which may not exceed the allocated size of the workspace.
1094 */
1095 if ( ( gslstat = gsl_integration_qags( &F, CosiLower, CosiUpper, epsabs, epsrel, 1000, w, &Bb, &abserr ) ) ) {
1096 LogPrintf( LOG_CRITICAL, "%s: row = %d: gsl_integration_qag() failed: res=%f, abserr=%f, intervals=%zu, %s\n",
1097 __func__, row, Bb, abserr, w->size, gsl_strerror( gslstat ) );
1098 return 1;
1099 }
1100
1101 gsl_vector_set( *Bstat_i, row, 2.0 * log( Bb ) );
1102
1103 } /* row < numDraws */
1104
1105 gsl_integration_workspace_free( w );
1106
1107 return 0;
1108
1109} /* XLALcomputeBstatisticGauss() */
1110
1111
1112/**
1113 * log likelihood ratio lnL marginalized over {h0, phi0} (analytical) and integrated over psi in [-pi/4,pi/4], for
1114 * given cosi: BstatIntegrandOuter(cosi) = int lnL dh0 dphi0 dpsi
1115 *
1116 * This function is of type gsl_function for gsl-integration over cosi
1117 *
1118 */
1119double
1121{
1123 gsl_function F;
1124 double epsabs = 0;
1125 double epsrel = 1e-3;
1126 double abserr;
1127 double ret;
1128 double PsiLower, PsiUpper;
1129 int gslstat;
1130 static gsl_integration_workspace *w = NULL;
1131
1132 if ( !w ) {
1133 w = gsl_integration_workspace_alloc( 1000 );
1134 }
1135
1136 par->cosi = cosi;
1137 F.function = &BstatIntegrandInner;
1138 F.params = p;
1139
1140 /* Integration boundaries */
1141 PsiLower = -LAL_PI_4;
1142 PsiUpper = LAL_PI_4;
1143
1144 /* Function: int gsl_integration_qags (const gsl_function * f, double a, double b, double epsabs, double epsrel,
1145 * size_t limit, gsl_integration_workspace * workspace, double * result, double * abserr)
1146 *
1147 * This function applies the Gauss-Kronrod 21-point integration rule adaptively until an estimate of the integral
1148 * of f over (a,b) is achieved within the desired absolute and relative error limits, epsabs and epsrel. The results
1149 * are extrapolated using the epsilon-algorithm, which accelerates the convergence of the integral in the presence of
1150 * discontinuities and integrable singularities. The function returns the final approximation from the extrapolation,
1151 * result, and an estimate of the absolute error, abserr. The subintervals and their results are stored in the memory
1152 * provided by workspace. The maximum number of subintervals is given by limit, which may not exceed the allocated size of the workspace.
1153 */
1154 if ( ( gslstat = gsl_integration_qags( &F, PsiLower, PsiUpper, epsabs, epsrel, 1000, w, &ret, &abserr ) ) ) {
1155 LogPrintf( LOG_CRITICAL, "%s: gsl_integration_qag() failed: res=%f, abserr=%f, intervals=%zu, %s\n",
1156 __func__, ret, abserr, w->size, gsl_strerror( gslstat ) );
1157 return 1;
1158 }
1159
1160 return ret;
1161
1162} /* BstatIntegrandOuter() */
1163
1164
1165/**
1166 * log likelihood ratio lnL marginalized over {h0, phi0} (analytical) for given psi and pars->cosi
1167 * BstatIntegrandInner(cosi,psi) = int lnL dh0 dphi0
1168 *
1169 * This function is of type gsl_function for gsl-integration over psi at fixed cosi,
1170 * and represents a simple wrapper around BstatIntegrand() for gsl-integration.
1171 *
1172 */
1173double
1174BstatIntegrandInner( double psi, void *p )
1175{
1177 double Amp[2], ret;
1178
1179 Amp[0] = par->cosi;
1180 Amp[1] = psi;
1181
1182 ret = BstatIntegrand( Amp, 2, p );
1183
1184 return ret;
1185
1186} /* BstatIntegrandInner() */
1187
1188
1189/**
1190 * compute log likelihood ratio lnL for given Amp = {h0, cosi, psi, phi0} and M_{mu,nu}.
1191 * computes lnL = A^mu x_mu - 1/2 A^mu M_mu_nu A^nu.
1192 *
1193 * This function is of type gsl_monte_function for gsl Monte-Carlo integration.
1194 *
1195 */
1196double
1197BstatIntegrand( double Amp[], size_t dim, void *p )
1198{
1200 double x1, x2, x3, x4;
1201 double al1, al2, al3, al4;
1202 double eta, etaSQ, etaSQp1SQ;
1203 double psi, sin2psi, cos2psi, sin2psiSQ, cos2psiSQ;
1204 double gammaSQ, qSQ, Xi;
1205 double integrand;
1206
1207 if ( dim != 2 ) {
1208 LogPrintf( LOG_CRITICAL, "Error: BstatIntegrand() was called with illegal dim = %zu != 2\n", dim );
1209 abort();
1210 }
1211
1212 /* introduce a few handy shortcuts */
1213 x1 = gsl_vector_get( par->x_mu, 0 );
1214 x2 = gsl_vector_get( par->x_mu, 1 );
1215 x3 = gsl_vector_get( par->x_mu, 2 );
1216 x4 = gsl_vector_get( par->x_mu, 3 );
1217
1218 eta = Amp[0];
1219 etaSQ = SQ( eta ); /* eta^2 */
1220 etaSQp1SQ = SQ( ( 1.0 + etaSQ ) ); /* (1+eta^2)^2 */
1221
1222 psi = Amp[1];
1223 sin2psi = sin( 2.0 * psi );
1224 cos2psi = cos( 2.0 * psi );
1225 sin2psiSQ = SQ( sin2psi );
1226 cos2psiSQ = SQ( cos2psi );
1227
1228 /* compute amplitude-params alpha1, alpha2, alpha3 and alpha4 */
1229 al1 = 0.25 * etaSQp1SQ * cos2psiSQ + etaSQ * sin2psiSQ;
1230 al2 = 0.25 * etaSQp1SQ * sin2psiSQ + etaSQ * cos2psiSQ;
1231 al3 = 0.25 * SQ( ( 1.0 - etaSQ ) ) * sin2psi * cos2psi;
1232 al4 = 0.5 * eta * ( 1.0 + etaSQ );
1233
1234 /* STEP 1: compute gamma^2 = At^mu Mt_{mu,nu} At^nu */
1235 gammaSQ = al1 * par->A + al2 * par->B + 2.0 * al3 * par->C + 2.0 * al4 * par->E;
1236
1237 /* STEP2: compute q^2 */
1238 qSQ = al1 * ( SQ( x1 ) + SQ( x3 ) ) + al2 * ( SQ( x2 ) + SQ( x4 ) ) + 2.0 * al3 * ( x1 * x2 + x3 * x4 ) + 2.0 * al4 * ( x1 * x4 - x2 * x3 );
1239
1240 /* STEP3 : put all the pieces together */
1241 Xi = 0.25 * qSQ / gammaSQ;
1242
1243 integrand = exp( Xi ); /* * pow(gammaSQ, -0.5) * gsl_sf_bessel_I0(Xi); */
1244
1245 if ( lalDebugLevel & LALINFOBIT ) {
1246 printf( "%f %f %f %f %f\n", eta, psi, integrand, gammaSQ, Xi );
1247 }
1248
1249 return integrand;
1250
1251} /* BstatIntegrand() */
1252
1253
1254/**
1255 * Compute an approximation to the full B-statistic, without using any integrations!
1256 * Returns Bhat vector of dimensions (numDraws x 1), or NULL on error.
1257 */
1258gsl_vector *
1259XLALcomputeBhatStatistic( const gsl_matrix *M_mu_nu, /**< antenna-pattern matrix M_mu_nu */
1260 const gsl_matrix *x_mu_i /**< data-vectors x_mu: numDraws x 4 */
1261 )
1262{
1263 int gslstat;
1264
1265 /* ----- check input arguments ----- */
1266 if ( !M_mu_nu || !x_mu_i ) {
1267 XLAL_ERROR_NULL( XLAL_EINVAL, "\nInput M_mu_nu, x_mu_i must not be NULL.\n" );
1268 }
1269
1270 if ( ( M_mu_nu->size1 != 4 ) || ( M_mu_nu->size2 != 4 ) ) {
1271 XLAL_ERROR_NULL( XLAL_EINVAL, "\nAntenna-pattern matrix M_mu_nu must be 4x4.\n" );
1272 }
1273
1274 size_t numDraws = x_mu_i->size1;
1275 if ( ( x_mu_i->size1 != numDraws ) || ( x_mu_i->size2 != 4 ) ) {
1276 XLAL_ERROR_NULL( XLAL_EINVAL, "\nInput vector-list dimensions of x_mu_i must be ( numDraws x 4 ).\n" );
1277 }
1278
1279 /* ----- allocate return statistics vectors ---------- */
1280 gsl_vector *Bhat_i;
1281 if ( ( Bhat_i = gsl_vector_calloc( numDraws ) ) == NULL ) {
1282 XLAL_ERROR_NULL( XLAL_ENOMEM, "\ngsl_vector_calloc (%zu) failed.\n", numDraws );
1283 }
1284
1285 /* ----- prepare Mmunu_LU for M-inverse operations ---------- */
1286 gsl_matrix *Mmunu_LU = gsl_matrix_calloc( 4, 4 );
1287 if ( Mmunu_LU == NULL ) {
1288 XLAL_ERROR_NULL( XLAL_ENOMEM, "\nMmunu_LU = gsl_matrix_calloc (4,4) failed.\n" );
1289 }
1290 gsl_permutation *perm = gsl_permutation_calloc( 4 );
1291 if ( Mmunu_LU == NULL ) {
1292 XLAL_ERROR_NULL( XLAL_ENOMEM, "\nperm = gsl_permutation_calloc (4) failed.\n" );
1293 }
1294
1295 gsl_matrix_memcpy( Mmunu_LU, M_mu_nu );
1296
1297 /* Function: int gsl_linalg_LU_decomp (gsl_matrix * A, gsl_permutation * p, int * signum)
1298 *
1299 * These functions factorize the square matrix A into the LU decomposition PA = LU.
1300 * On output the diagonal and upper triangular part of the input matrix A contain the matrix U. The lower
1301 * triangular part of the input matrix (excluding the diagonal) contains L. The diagonal elements of L are
1302 * unity, and are not stored. The permutation matrix P is encoded in the permutation p. The j-th column of
1303 * the matrix P is given by the k-th column of the identity matrix, where k = p_j the j-th element of the
1304 * permutation vector. The sign of the permutation is given by signum. It has the value (-1)^n, where n is
1305 * the number of interchanges in the permutation.
1306 * The algorithm used in the decomposition is Gaussian Elimination with partial pivoting
1307 * (Golub & Van Loan, Matrix Computations, Algorithm 3.4.1).
1308 */
1309 int sig;
1310 if ( ( gslstat = gsl_linalg_LU_decomp( Mmunu_LU, perm, &sig ) ) ) {
1311 XLAL_ERROR_NULL( XLAL_EFAILED, "gsl_linalg_LU_decomp (Mmunu) failed: %s\n", gsl_strerror( gslstat ) );
1312 }
1313
1314 /* ----- invert M_{mu,nu} to get M^{mu,nu} ---------- */
1315 gsl_matrix *M_MuNu = gsl_matrix_calloc( 4, 4 );
1316 if ( M_MuNu == NULL ) {
1317 XLAL_ERROR_NULL( XLAL_ENOMEM, "\nM_MuNu = gsl_matrix_calloc (4,4) failed.\n" );
1318 }
1319
1320 /* These functions compute the inverse of a matrix A from its LU decomposition (LU,p),
1321 * storing the result in the matrix inverse.
1322 * The inverse is computed by solving the system A x = b for each column of the identity matrix.
1323 * It is preferable to avoid direct use of the inverse whenever possible, as the linear solver
1324 * functions can obtain the same result more efficiently and reliably (consult any introductory
1325 * textbook on numerical linear algebra for details).
1326 */
1327 if ( ( gslstat = gsl_linalg_LU_invert( Mmunu_LU, perm, M_MuNu ) ) ) {
1328 XLAL_ERROR_NULL( XLAL_EFAILED, "gsl_linalg_LU_invert (Mmunu_LU) failed: %s\n", gsl_strerror( gslstat ) );
1329 }
1330
1331 /* ----- compute AMLE^mu = Minv^{mu nu} x_nu ----- */
1332 gsl_matrix *Ah_Mu_i = gsl_matrix_calloc( 4, numDraws );
1333 if ( Ah_Mu_i == NULL ) {
1334 XLAL_ERROR_NULL( XLAL_ENOMEM, "\nAh_Mu_i = gsl_matrix_calloc (%zu,4) failed.\n", numDraws );
1335 }
1336
1337 /* These functions compute the matrix-matrix product and sum C = \alpha op(A) op(B) + \beta C
1338 * where op(A) = A, A^T, A^H for TransA = CblasNoTrans, CblasTrans, CblasConjTrans and similarly
1339 * for the parameter TransB.
1340 */
1341 if ( ( gslstat = gsl_blas_dgemm( CblasNoTrans, CblasTrans, 1.0, M_MuNu, x_mu_i, 0.0, Ah_Mu_i ) ) ) {
1342 XLAL_ERROR_NULL( XLAL_EFAILED, "gsl_blas_dgemm: Ah^mu = M^{mu,nu} x_nu failed: %s\n", gsl_strerror( gslstat ) );
1343 }
1344
1345 /* ----- compute F = 1/2 * x_mu M^{mu nu} x_nu = 1/2 * x_mu A^mu ---------- */
1346 for ( UINT4 iTrial = 0; iTrial < numDraws; iTrial ++ ) {
1347 gsl_vector_const_view x_mu = gsl_matrix_const_row( x_mu_i, iTrial );
1348 gsl_vector_const_view A_Mu = gsl_matrix_const_column( Ah_Mu_i, iTrial );
1349
1350 REAL8 TwoF;
1351 /* Function: int gsl_blas_ddot (const gsl_vector * x, const gsl_vector * y, double * result)
1352 * These functions compute the scalar product x^T y for the vectors x and y, returning the result in result. */
1353 if ( ( gslstat = gsl_blas_ddot( &( x_mu.vector ), &( A_Mu.vector ), &TwoF ) ) ) {
1354 XLAL_ERROR_NULL( XLAL_EFAILED, "iTrial = %d: 2F = gsl_blas_ddot (x_mu, A^mu) failed: %s\n", iTrial, gsl_strerror( gslstat ) );
1355 }
1356
1357 REAL8 Bhat = 0.5 * TwoF;
1358 Bhat += XLALComputeBhatCorrection( &( A_Mu.vector ), M_mu_nu );
1359 if ( xlalErrno ) {
1360 XLAL_ERROR_NULL( XLAL_EFUNC, "\nXLALComputeBhatCorrection() failed for iTrial = %d\n", iTrial );
1361 }
1362
1363
1364 /* write resulting Bstat-values into return vector */
1365 gsl_vector_set( Bhat_i, iTrial, Bhat );
1366
1367 } // for iTrial < numDraws
1368
1369 /* ----- free memory ---------- */
1370 gsl_permutation_free( perm );
1371 gsl_matrix_free( Mmunu_LU );
1372 gsl_matrix_free( M_MuNu );
1373 gsl_matrix_free( Ah_Mu_i );
1374
1375 return Bhat_i;
1376
1377} /* XLALcomputeBhatStatistic() */
1378
1379/**
1380 * Compute 'Bstat' approximate correction terms with respect to F, ie deltaB in Bstat = F + deltaB
1381 */
1382REAL8
1383XLALComputeBhatCorrection( const gsl_vector *A_Mu_in, const gsl_matrix *M_mu_nu )
1384{
1385 int gslstat;
1386
1387 /* ----- check input arguments ----- */
1388 if ( !M_mu_nu || !A_Mu_in ) {
1389 XLAL_ERROR( XLAL_EINVAL, "\nInput M_mu_nu, A_Mu_in must not be NULL.\n" );
1390 }
1391
1392 if ( ( M_mu_nu->size1 != 4 ) || ( M_mu_nu->size2 != 4 ) ) {
1393 XLAL_ERROR( XLAL_EINVAL, "\nAntenna-pattern matrix M_mu_nu must be 4x4.\n" );
1394 }
1395
1396 if ( A_Mu_in->size != 4 ) {
1397 XLAL_ERROR( XLAL_EINVAL, "\nAmplitude vector A_Mu_in must be 4D\n" );
1398 }
1399
1400
1401 /* ----- 'reflection' matrix R_mu_nu ---------- */
1402 REAL8 R_array[4 * 4] = {
1403 0, 0, 0, -1,
1404 0, 0, -1, 0,
1405 0, -1, 0, 0,
1406 -1, 0, 0, 0
1407 };
1408 gsl_matrix_const_view R_mu_nu_view = gsl_matrix_const_view_array( R_array, 4, 4 );
1409 const gsl_matrix *R_mu_nu = &( R_mu_nu_view.matrix );
1410
1411 /* ----- compute 'reflected' \underline{A}_mu vector : AR_mu = R_{mu,nu} A^\nu = (A4,-A3, -A2, A1) ---------- */
1412 REAL8 A1 = gsl_vector_get( A_Mu_in, 1 );
1413 REAL8 A2 = gsl_vector_get( A_Mu_in, 2 );
1414 REAL8 A3 = gsl_vector_get( A_Mu_in, 3 );
1415 REAL8 A4 = gsl_vector_get( A_Mu_in, 4 );
1416
1417 REAL8 A_array[4] = { A1, A2, A3, A4 };
1418 REAL8 AR_array[4] = { A4, -A3, -A2, A1 };
1419 gsl_vector_view A_mu_view = gsl_vector_view_array( A_array, 4 );
1420 gsl_vector_view AR_mu_view = gsl_vector_view_array( AR_array, 4 );
1421
1422 gsl_vector *A_mu = &( A_mu_view.vector );
1423 gsl_vector *AR_mu = &( AR_mu_view.vector );
1424
1425 /* ----- compute intermediate quantities: ka = A_mu A^mu, and ks = AR_mu A^mu ---------- */
1426 REAL8 ks, ka;
1427 /* Function: int gsl_blas_ddot (const gsl_vector * x, const gsl_vector * y, double * result)
1428 * These functions compute the scalar product x^T y for the vectors x and y, returning the result in result. */
1429 if ( ( gslstat = gsl_blas_ddot( A_mu, A_mu, &ks ) ) ) {
1430 XLAL_ERROR( XLAL_EFAILED, "ks = gsl_blas_ddot (A_mu, A^mu) failed: %s\n", gsl_strerror( gslstat ) );
1431 }
1432
1433 if ( ( gslstat = gsl_blas_ddot( AR_mu, A_mu, &ka ) ) ) {
1434 XLAL_ERROR( XLAL_EFAILED, "ka = gsl_blas_ddot (AR_mu, A^mu) failed: %s\n", gsl_strerror( gslstat ) );
1435 }
1436
1437 REAL8 K = SQ( ks ) - SQ( ka );
1438
1439 /* ----- compute intermediate derivatives K_mu = \partial_mu K, and K_{mu,nu} = \partial_{\mu,\nu} K ---------- */
1440 REAL8 tmpV_array[4], tmpM_array [ 4 * 4 ];
1441 gsl_vector_view tmpV_view = gsl_vector_view_array( tmpV_array, 4 );
1442 gsl_matrix_view tmpM_view = gsl_matrix_view_array( tmpM_array, 4, 4 );
1443 gsl_vector *tmpV = &( tmpV_view.vector );
1444 gsl_matrix *tmpM = &( tmpM_view.matrix );
1445
1446 REAL8 K_mu_array [4], K_mu_nu_array[4 * 4];
1447 gsl_vector_view K_mu_view = gsl_vector_view_array( K_mu_array, 4 );
1448 gsl_matrix_view K_mu_nu_view = gsl_matrix_view_array( K_mu_nu_array, 4, 4 );
1449 gsl_vector *K_mu = &( K_mu_view.vector );
1450 gsl_matrix *K_mu_nu = &( K_mu_nu_view.matrix );
1451
1452 /* ----- K_mu ----- */
1453 gsl_vector_memcpy( K_mu, A_mu );
1454 gsl_vector_scale( K_mu, 4.0 * ks ); // K_mu = 4 ks A_mu
1455
1456 gsl_vector_memcpy( tmpV, AR_mu );
1457 gsl_vector_scale( tmpV, - 4.0 * ka );
1458 gsl_vector_add( K_mu, tmpV ); // K_mu += - 4 ka AR_mu;
1459 /* ---------- */
1460
1461 /* ----- K_mu_nu ----- */
1462 gsl_matrix_set_identity( K_mu_nu );
1463 gsl_matrix_scale( K_mu_nu, 4.0 * ks ); // K_mu_nu = 4 ks delta_mu_nu
1464
1465 gsl_matrix_memcpy( tmpM, R_mu_nu );
1466 gsl_matrix_scale( tmpM, - 4.0 * ka );
1467 gsl_matrix_add( K_mu_nu, tmpM ); // K_mu_nu += - 4 ka R_mu_nu
1468
1469 /* --> tensor product A_mu A_nu */
1470 gsl_matrix_const_view A_mat = gsl_matrix_const_view_vector( A_mu, 1, 4 );
1471 if ( ( gslstat = gsl_blas_dgemm( CblasTrans, CblasNoTrans, 1.0, &( A_mat.matrix ), &( A_mat.matrix ), 0.0, tmpM ) ) ) {
1472 XLAL_ERROR( XLAL_EFAILED, "\ngsl_blas_dgemm ( A_mu, A_nu ) failed: %s\n", gsl_strerror( gslstat ) );
1473 }
1474 gsl_matrix_scale( tmpM, 8.0 );
1475 gsl_matrix_add( K_mu_nu, tmpM ); // K_mu_nu += 8 A_mu A_nu
1476
1477 /* --> tensor product AR_mu AR_nu */
1478 gsl_matrix_const_view AR_mat = gsl_matrix_const_view_vector( AR_mu, 1, 4 );
1479 if ( ( gslstat = gsl_blas_dgemm( CblasTrans, CblasNoTrans, 1.0, &( AR_mat.matrix ), &( AR_mat.matrix ), 0.0, tmpM ) ) ) {
1480 XLAL_ERROR( XLAL_EFAILED, "\ngsl_blas_dgemm ( A_mu, A_nu ) failed: %s\n", gsl_strerror( gslstat ) );
1481 }
1482 gsl_matrix_scale( tmpM, - 8.0 );
1483 gsl_matrix_add( K_mu_nu, tmpM ); // K_mu_nu += - 8 AR_mu AR_nu
1484 /* ---------- */
1485
1486 /* ---------- compute alpha derivatives alpha, alpha_mu = \partial_mu alpha, alpha_mu_nu = partial_mu_nu alpha ---------- */
1487 /*REAL8 alpha = - 3.0 / 4.0 * log (K);*/
1488
1489 REAL8 a_mu_array [4], a_mu_nu_array[4 * 4];
1490 gsl_vector_view a_mu_view = gsl_vector_view_array( a_mu_array, 4 );
1491 gsl_matrix_view a_mu_nu_view = gsl_matrix_view_array( a_mu_nu_array, 4, 4 );
1492 gsl_vector *a_mu = &( a_mu_view.vector );
1493 gsl_matrix *a_mu_nu = &( a_mu_nu_view.matrix );
1494
1495 /* ----- a_mu ----- */
1496 gsl_vector_memcpy( a_mu, K_mu );
1497 gsl_vector_scale( a_mu, - 3.0 / ( 4.0 * K ) ); // a_mu = -3/(4K) * K_mu
1498 /* ----- a_mu_nu ----- */
1499 gsl_matrix_memcpy( a_mu_nu, K_mu_nu );
1500 gsl_matrix_scale( a_mu_nu, K ); // a_mu_nu = K * K_mu_nu
1501
1502 gsl_matrix_const_view Kmu_mat = gsl_matrix_const_view_vector( K_mu, 1, 4 );
1503 if ( ( gslstat = gsl_blas_dgemm( CblasTrans, CblasNoTrans, 1.0, &( Kmu_mat.matrix ), &( Kmu_mat.matrix ), 0.0, tmpM ) ) ) {
1504 XLAL_ERROR( XLAL_EFAILED, "\ngsl_blas_dgemm ( K_mu, K_nu ) failed: %s\n", gsl_strerror( gslstat ) );
1505 }
1506 gsl_matrix_sub( a_mu_nu, tmpM ); // a_mu_nu -= K_mu K_nu
1507
1508 gsl_matrix_scale( a_mu_nu, -3.0 / ( 4.0 * SQ( K ) ) ); // a_mu_nu *= -3/(4K^2)
1509
1510 /* ----- modified antenna-pattern matrix N_munu ---------- */
1511 REAL8 N_array[4 * 4];
1512 gsl_matrix_view N_view = gsl_matrix_view_array( N_array, 4, 4 );
1513 gsl_matrix *N_mu_nu = &( N_view.matrix );
1514
1515 gsl_matrix_memcpy( N_mu_nu, M_mu_nu );
1516 gsl_matrix_sub( N_mu_nu, a_mu_nu ); // N_mu_nu = M_mu_nu - alpha_mu_nu
1517
1518 /* ----- N_mu_nu : LU-decompose and compute determinant ---------- */
1519 REAL8 NLU_array[4 * 4];
1520 gsl_matrix_view NLU_view = gsl_matrix_view_array( NLU_array, 4, 4 );
1521 gsl_matrix *NLU_mu_nu = &( NLU_view.matrix );
1522
1523 size_t perm_data[4];
1524 gsl_permutation perm = {4, perm_data };
1525 int sig;
1526
1527 gsl_matrix_memcpy( NLU_mu_nu, N_mu_nu );
1528 if ( ( gslstat = gsl_linalg_LU_decomp( NLU_mu_nu, &perm, &sig ) ) ) {
1529 XLAL_ERROR( XLAL_EFAILED, "\ngsl_linalg_LU_decomp ( N_mu_nu ) failed: %s\n", gsl_strerror( gslstat ) );
1530 }
1531
1532 REAL8 detN;
1533 detN = gsl_linalg_LU_det( NLU_mu_nu, 1 );
1534
1535 /* ----- compute Bstat correction ---------- */
1536 REAL8 deltaB = - 0.5 * log( detN );
1537
1538 return deltaB;
1539
1540} /* XLALComputeBhatCorrection() */
#define __func__
log an I/O error, i.e.
void LALCheckMemoryLeaks(void)
const LALVCSInfoList lalPulsarVCSInfoList
NULL-terminated list of VCS and build information for LALPulsar and its dependencies
ConfigVariables GV
global container for various derived configuration settings
Definition: PredictFstat.c:70
#define STRING(a)
UINT2 A
Definition: SFTnaming.c:46
UINT2 B
Definition: SFTnaming.c:47
#define fprintf
double e
const double w
int XLALAmplitudeParams2Vect(PulsarAmplitudeVect A_Mu, const PulsarAmplitudeParams Amp)
Convert amplitude params from 'physical' coordinates into 'canonical' coordinates .
int XLALAmplitudeVect2Params(PulsarAmplitudeParams *Amp, const PulsarAmplitudeVect A_Mu)
Compute amplitude params from amplitude-vector .
#define LAL_PI_2
#define LAL_TWOPI
#define LAL_PI_4
unsigned char BOOLEAN
double REAL8
#define XLAL_INIT_DECL(var,...)
char CHAR
uint32_t UINT4
int32_t INT4
#define lalDebugLevel
LALINFOBIT
void XLALFree(void *p)
char * XLALVCSInfoString(const LALVCSInfoList vcs_list, const int verbose, const char *prefix)
int XLALfprintfGSLvector(FILE *fp, const char *fmt, const gsl_vector *vect) _LAL_GCC_VPRINTF_FORMAT_(2)
void LogPrintf(LogLevel_t, const char *format,...) _LAL_GCC_PRINTF_FORMAT_(2
LOG_CRITICAL
LOG_DEBUG
REAL8 PulsarAmplitudeVect[4]
Struct for 'canonical' coordinates in amplitude-params space A^mu = {A1, A2, A3, A4}.
int XLALUserVarReadAllInput(BOOLEAN *should_exit, int argc, char *argv[], const LALVCSInfoList vcs_list)
void XLALDestroyUserVars(void)
#define XLALRegisterUvarMember(name, type, option, category,...)
void CHAR * XLALUserVarGetLog(UserVarLogFormat format)
int XLALUserVarWasSet(const void *cvar)
UVAR_LOGFMT_CMDLINE
#define XLAL_ERROR_NULL(...)
#define xlalErrno
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_MAIN(assertion,...)
#define XLAL_ERROR_MAIN(...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
XLAL_ESYS
XLAL_EINVAL
XLAL_EFAILED
row
eta
Signal (amplitude) parameter ranges.
REAL8 h0Nat
h0 in natural units ie h0Nat = h0 * sqrt(T/Sn)
REAL8 SNR
if > 0: alternative to h0Nat/h0NatBand: fix optimal signal SNR
REAL8 h0NatBand
draw h0Nat from Band [h0Nat, h0Nat + Band ]
Configuration settings required for and defining a coherent pulsar search.
gsl_rng * rng
gsl random-number generator
AmpParamsRange_t AmpRange
signal amplitude-parameter ranges: lower bounds + bands
gsl_matrix * M_mu_nu
antenna-pattern matrix and normalization
Type containing the JKS 'amplitude parameters' {h0, cosi, phi0, psi}.
REAL8 aCross
Signal amplitude (cross)
REAL8 psi
polarization angle psi
REAL8 aPlus
Signal amplitude (plus)
REAL8 phi0
initial signal-phase (at some reference time)
const gsl_vector * x_mu
double cosi
only used for inner 2D Gauss-Kronod gsl-integration: value of cosi at which to integrate over psi
int main(int argc, char *argv[])
MAIN function Generates samples of B-stat and F-stat according to their pdfs for given signal-params.
int XLALcomputeBstatisticMC(gsl_vector **Bstat, const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i, gsl_rng *rng, UINT4 numMCpoints)
Compute the B-statistic for given input data, using Monte-Carlo integration for the marginalization o...
double BstatIntegrandInner(double psi, void *p)
log likelihood ratio lnL marginalized over {h0, phi0} (analytical) for given psi and pars->cosi Bstat...
int initUserVars(UserInput_t *uvar)
Register all our "user-variables" that can be specified from cmd-line and/or config-file.
int XLALcomputeFstatistic(gsl_vector **Fstat, gsl_matrix **A_Mu_MLE_i, const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i)
Compute F-statistic for given input data.
int XLALcomputeBstatisticGauss(gsl_vector **Bstat, const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i)
Compute the B-statistic for given input data, using standard Gauss-Kronod integration (gsl_integratio...
int XLALsynthesizeNoise(gsl_matrix **n_mu_i, const gsl_matrix *M_mu_nu, gsl_rng *rng, UINT4 numDraws)
Generate random-noise draws and combine with (FIXME: single!) signal.
int XLALcomputeLogLikelihood(gsl_vector **lnL, const gsl_matrix *A_Mu_i, const gsl_matrix *s_mu_i, const gsl_matrix *x_mu_i)
Compute log-likelihood function for given input data.
int vrbflg
defined in lal/lib/std/LALError.c
#define SQ(x)
int InitCode(ConfigVariables *cfg, const UserInput_t *uvar)
Initialized Fstat-code: handle user-input and set everything up.
double BstatIntegrandOuter(double cosi, void *p)
log likelihood ratio lnL marginalized over {h0, phi0} (analytical) and integrated over psi in [-pi/4,...
int XLALsynthesizeSignals(gsl_matrix **A_Mu_i, gsl_matrix **s_mu_i, gsl_matrix **Amp_i, gsl_vector **rho2, const gsl_matrix *M_mu_nu, AmpParamsRange_t AmpRange, gsl_rng *rnd, UINT4 numDraws)
Generate random signal draws with uniform priors in given bands [h0, cosi, psi, phi0],...
REAL8 XLALComputeBhatCorrection(const gsl_vector *A_Mu, const gsl_matrix *M_mu_nu)
Compute 'Bstat' approximate correction terms with respect to F, ie deltaB in Bstat = F + deltaB.
double BstatIntegrand(double A[], size_t dim, void *p)
compute log likelihood ratio lnL for given Amp = {h0, cosi, psi, phi0} and M_{mu,nu}.
gsl_vector * XLALcomputeBhatStatistic(const gsl_matrix *M_mu_nu, const gsl_matrix *x_mu_i)
Compute an approximation to the full B-statistic, without using any integrations! Returns Bhat vector...