Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-6c6b863
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
UniversalDopplerMetric.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017 Arunava Mukherjee
3 * Copyright (C) 2012--2015 Karl Wette
4 * Copyright (C) 2008, 2009 Reinhard Prix
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with with program; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22/*---------- INCLUDES ----------*/
23#include <math.h>
24#ifdef _OPENMP
25#include <omp.h>
26#endif
27
28/* gsl includes */
29#include <gsl/gsl_block.h>
30#include <gsl/gsl_vector.h>
31#include <gsl/gsl_matrix.h>
32#include <gsl/gsl_linalg.h>
33#include <gsl/gsl_blas.h>
34#include <gsl/gsl_integration.h>
35#include <gsl/gsl_eigen.h>
36
37#include <lal/GetEarthTimes.h>
38#include <lal/ComputeFstat.h>
39#include <lal/XLALGSL.h>
40#include <lal/Factorial.h>
41#include <lal/LogPrintf.h>
42#include <lal/MetricUtils.h>
43
44#include <lal/FstatisticTools.h>
45#include <lal/UniversalDopplerMetric.h>
46#include <lal/MetricUtils.h>
47
48#include <lal/GSLHelpers.h>
49
50/**
51 * \author Reinhard Prix, Karl Wette
52 * \ingroup UniversalDopplerMetric_h
53 * \brief Function to compute the full F-statistic metric, including
54 * antenna-pattern functions from multi-detector, as derived in \cite Prix07 .
55 *
56 */
57
58/*---------- SCALING FACTORS ----------*/
59/** shortcuts for integer powers */
60#define POW2(a) ( (a) * (a) )
61#define POW3(a) ( (a) * (a) * (a) )
62#define POW4(a) ( (a) * (a) * (a) * (a) )
63#define POW5(a) ( (a) * (a) * (a) * (a) * (a) )
64
65/* These constants define an internal scale used within CW_Phi_i().
66 * Distances are normalised by SCALE_R, and times are normalised by SCALE_T.
67 */
68#define SCALE_R (LAL_AU_SI)
69#define SCALE_T (LAL_YRSID_SI)
70
71/*---------- LOOKUP ARRAYS ----------*/
72
73/**
74 * Array of symbolic 'names' for various detector-motions
75 */
76static const struct {
78 const char *const name;
80
81#define DETMOTION_NAMES(orbit_type, spin_orbit_name, nospin_orbit_name) \
82 {DETMOTION_SPIN | orbit_type, "spin" spin_orbit_name}, \
83 {DETMOTION_SPINZ | orbit_type, "spinz" spin_orbit_name}, \
84 {DETMOTION_SPINXY | orbit_type, "spinxy" spin_orbit_name}, \
85 {orbit_type, nospin_orbit_name} /* this must be the last entry in the macro */
86
87 DETMOTION_NAMES( DETMOTION_ORBIT, "+orbit", "orbit" ),
88 DETMOTION_NAMES( DETMOTION_PTOLEORBIT, "+ptoleorbit", "ptoleorbit" ),
89 DETMOTION_NAMES( 0, "", NULL ) /* last entry provides marker for end of list */
90
91#undef DETMOTION_NAMES
92};
93
94/**
95 * Array of descriptor structs for each Doppler coordinate name
96 */
97static const struct {
98 const char *const name; /**< coordinate name */
99 const double scale; /**< multiplicative scaling factor of the coordinate */
100 const char *const help; /**< help string explaining the coordinate's meaning and units */
102
103 [DOPPLERCOORD_FREQ] = {"freq", SCALE_T, "Frequency [Units: Hz]."},
104 [DOPPLERCOORD_F1DOT] = {"f1dot", POW2( SCALE_T ), "First spindown [Units: Hz/s]."},
105 [DOPPLERCOORD_F2DOT] = {"f2dot", POW3( SCALE_T ), "Second spindown [Units: Hz/s^2]."},
106 [DOPPLERCOORD_F3DOT] = {"f3dot", POW4( SCALE_T ), "Third spindown [Units: Hz/s^3]."},
107 [DOPPLERCOORD_F4DOT] = {"f4dot", POW5( SCALE_T ), "Fourth spindown [Units: Hz/s^4]."},
108
109 [DOPPLERCOORD_GC_NU0] = {"gc_nu0", SCALE_T, "Global correlation frequency [Units: Hz]."},
110 [DOPPLERCOORD_GC_NU1] = {"gc_nu1", POW2( SCALE_T ), "Global correlation first spindown [Units: Hz/s]."},
111 [DOPPLERCOORD_GC_NU2] = {"gc_nu2", POW3( SCALE_T ), "Global correlation second spindown [Units: Hz/s^2]."},
112 [DOPPLERCOORD_GC_NU3] = {"gc_nu3", POW4( SCALE_T ), "Global correlation third spindown [Units: Hz/s^3]."},
113 [DOPPLERCOORD_GC_NU4] = {"gc_nu4", POW5( SCALE_T ), "Global correlation fourth spindown [Units: Hz/s^4]."},
114
115 [DOPPLERCOORD_ALPHA] = {"alpha", SCALE_R / LAL_C_SI, "Right ascension [Units: radians]."},
116 [DOPPLERCOORD_DELTA] = {"delta", SCALE_R / LAL_C_SI, "Declination [Units: radians]."},
117
118 [DOPPLERCOORD_N2X_EQU] = {"n2x_equ", SCALE_R / LAL_C_SI, "X component of constrained sky position in equatorial coordinates [Units: none]."},
119 [DOPPLERCOORD_N2Y_EQU] = {"n2y_equ", SCALE_R / LAL_C_SI, "Y component of constrained sky position in equatorial coordinates [Units: none]."},
120
121 [DOPPLERCOORD_N2X_ECL] = {"n2x_ecl", SCALE_R / LAL_C_SI, "X component of constrained sky position in ecliptic coordinates [Units: none]."},
122 [DOPPLERCOORD_N2Y_ECL] = {"n2y_ecl", SCALE_R / LAL_C_SI, "Y component of constrained sky position in ecliptic coordinates [Units: none]."},
123
124 [DOPPLERCOORD_N3X_EQU] = {"n3x_equ", SCALE_R / LAL_C_SI, "X component of unconstrained super-sky position in equatorial coordinates [Units: none]."},
125 [DOPPLERCOORD_N3Y_EQU] = {"n3y_equ", SCALE_R / LAL_C_SI, "Y component of unconstrained super-sky position in equatorial coordinates [Units: none]."},
126 [DOPPLERCOORD_N3Z_EQU] = {"n3z_equ", SCALE_R / LAL_C_SI, "Z component of unconstrained super-sky position in equatorial coordinates [Units: none]."},
127
128 [DOPPLERCOORD_N3X_ECL] = {"n3x_ecl", SCALE_R / LAL_C_SI, "X component of unconstrained super-sky position in ecliptic coordinates [Units: none]."},
129 [DOPPLERCOORD_N3Y_ECL] = {"n3y_ecl", SCALE_R / LAL_C_SI, "Y component of unconstrained super-sky position in ecliptic coordinates [Units: none]."},
130 [DOPPLERCOORD_N3Z_ECL] = {"n3z_ecl", SCALE_R / LAL_C_SI, "Z component of unconstrained super-sky position in ecliptic coordinates [Units: none]."},
131
132 [DOPPLERCOORD_N3SX_EQU] = {"n3sx_equ", SCALE_R / LAL_C_SI, "X spin-component of unconstrained super-sky position in equatorial coordinates [Units: none]."},
133 [DOPPLERCOORD_N3SY_EQU] = {"n3sy_equ", SCALE_R / LAL_C_SI, "Y spin-component of unconstrained super-sky position in equatorial coordinates [Units: none]."},
134
135 [DOPPLERCOORD_N3OX_ECL] = {"n3ox_ecl", SCALE_R / LAL_C_SI, "X orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none]."},
136 [DOPPLERCOORD_N3OY_ECL] = {"n3oy_ecl", SCALE_R / LAL_C_SI, "Y orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none]."},
137 [DOPPLERCOORD_N3OZ_ECL] = {"n3oz_ecl", SCALE_R / LAL_C_SI, "Z orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none]."},
138
139 [DOPPLERCOORD_ASINI] = {"asini", 1, "Projected semimajor axis of binary orbit in small-eccentricy limit (ELL1 model) [Units: light seconds]."},
140 [DOPPLERCOORD_TASC] = {"tasc", 1, "Time of ascension (neutron star crosses line of nodes moving away from observer) for binary orbit (ELL1 model) [Units: GPS seconds]."},
141 [DOPPLERCOORD_PORB] = {"porb", 1, "Period of binary orbit (ELL1 model) [Units: s]."},
142 [DOPPLERCOORD_KAPPA] = {"kappa", 1, "Lagrange parameter 'kappa = ecc * cos(argp)', ('ecc' = eccentricity, 'argp' = argument of periapse) of binary orbit (ELL1 model) [Units: none]."},
143 [DOPPLERCOORD_ETA] = {"eta", 1, "Lagrange parameter 'eta = ecc * sin(argp) of binary orbit (ELL1 model) [Units: none]."},
144
145 [DOPPLERCOORD_DASC] = {"dasc", 1, "Distance traversed on the arc of binary orbit (ELL1 model) 'dasc = 2 * pi * (ap/porb) * tasc' [Units: light second]."},
146 [DOPPLERCOORD_VP] = {"vp", 1, "Rescaled (by asini) differential-coordinate 'dvp = asini * dOMEGA', ('OMEGA' = 2 * pi/'porb') of binary orbit (ELL1 model) [Units: (light second)/(GPS second)]."},
147 [DOPPLERCOORD_KAPPAP] = {"kappap", 1, "Rescaled (by asini) differential-coordinate 'dkappap = asini * dkappa' [Units: light seconds]."},
148 [DOPPLERCOORD_ETAP] = {"etap", 1, "Rescaled (by asini) differential-coordinate 'detap = asini * deta' [Units: light seconds]."}
149
151
152/*---------- DEFINES ----------*/
153#define TRUE (1==1)
154#define FALSE (0==1)
155
156/* get the coordinate ID for a given coordinate index */
157#define GET_COORD_ID(coordSys, coord) ( (coord) >= 0 ? (coordSys)->coordIDs[(coord)] : DOPPLERCOORD_NONE )
158
159/* get the coordinate name and scale associated with a given coordinate index */
160#define GET_COORD_NAME(coordSys, coord) ( (coord) >= 0 ? DopplerCoordinates[GET_COORD_ID(coordSys, coord)].name : "(none)" )
161#define GET_COORD_SCALE(coordSys, coord) ( (coord) >= 0 ? DopplerCoordinates[GET_COORD_ID(coordSys, coord)].scale : 1.0 )
162
163/** copy 3 components of Euklidean vector */
164#define COPY_VECT(dst,src) do { (dst)[0] = (src)[0]; (dst)[1] = (src)[1]; (dst)[2] = (src)[2]; } while(0)
165
166/** Simple Euklidean scalar product for two 3-dim vectors in cartesian coords */
167#define DOT_VECT(u,v) ((u)[0]*(v)[0] + (u)[1]*(v)[1] + (u)[2]*(v)[2])
168
169/** Vector product of two 3-dim vectors in cartesian coords */
170#define CROSS_VECT_0(u,v) ((u)[1]*(v)[2] - (u)[2]*(v)[1])
171#define CROSS_VECT_1(u,v) ((u)[2]*(v)[0] - (u)[0]*(v)[2])
172#define CROSS_VECT_2(u,v) ((u)[0]*(v)[1] - (u)[1]*(v)[0])
173#define CROSS_VECT(x,u,v) do { (x)[0] = CROSS_VECT_0(u,v); (x)[1] = CROSS_VECT_1(u,v); (x)[2] = CROSS_VECT_2(u,v); } while (0)
174
175/** Operations on 3-dim vectors */
176#define ZERO_VECT(v) do{ (v)[0] = 0; (v)[1] = 0; (v)[2] = 0; } while(0)
177#define NORMSQ_VECT(v) DOT_VECT(v,v)
178#define NORM_VECT(v) sqrt(NORMSQ_VECT(v))
179#define MULT_VECT(v,lam) do{ (v)[0] *= (lam); (v)[1] *= (lam); (v)[2] *= (lam); } while(0)
180#define ADD_VECT(dst,src) do { (dst)[0] += (src)[0]; (dst)[1] += (src)[1]; (dst)[2] += (src)[2]; } while(0)
181#define SUB_VECT(dst,src) do { (dst)[0] -= (src)[0]; (dst)[1] -= (src)[1]; (dst)[2] -= (src)[2]; } while(0)
182
183/** Convert 3-D vector from equatorial into ecliptic coordinates */
184#define EQU_VECT_TO_ECL(dst,src) do { \
185 (dst)[0] = (src)[0]; \
186 (dst)[1] = (src)[1]*LAL_COSIEARTH + (src)[2]*LAL_SINIEARTH; \
187 (dst)[2] = (src)[2]*LAL_COSIEARTH - (src)[1]*LAL_SINIEARTH; \
188 } while(0)
189
190/** Convert 3-D vector from ecliptic into equatorial coordinates */
191#define ECL_VECT_TO_EQU(dst,src) do { \
192 (dst)[0] = (src)[0]; \
193 (dst)[1] = (src)[1]*LAL_COSIEARTH - (src)[2]*LAL_SINIEARTH; \
194 (dst)[2] = (src)[2]*LAL_COSIEARTH + (src)[1]*LAL_SINIEARTH; \
195 } while(0)
196
197#define SQUARE(x) ((x) * (x))
198
199/** convert GPS-time to REAL8 */
200#define GPS2REAL8(gps) (1.0 * (gps).gpsSeconds + 1.e-9 * (gps).gpsNanoSeconds )
201
202#define MYMAX(a,b) ( (a) > (b) ? (a) : (b) )
203#define MYMIN(a,b) ( (a) < (b) ? (a) : (b) )
204
205#define RELERR(dx,x) ( (x) == 0 ? (dx) : ( (dx) / (x) ) )
206
207/* highest supported spindown-order */
208#define MAX_SPDNORDER 4
209
210/** 5-point derivative formulas (eg see http://math.fullerton.edu/mathews/articles/2003NumericalDiffFormulae.pdf) */
211#define DERIV5P_1(pm2,pm1,p0,pp1,pp2,h) ( ( (pm2) - 8.0 * (pm1) + 8.0 * (pp1) - (pp2)) / ( 12.0 * (h) ) )
212#define DERIV5P_2(pm2,pm1,p0,pp1,pp2,h) ( (-(pm2) + 16.0 * (pm1) - 30.0 * (p0) + 16.0 * (pp1) - (pp2) ) / ( 12.0 * (h) * (h) ) )
213#define DERIV5P_3(pm2,pm1,p0,pp1,pp2,h) ( (-(pm2) + 2.0 * (pm1) - 2.0 * (pp1) + (pp2) ) / ( 2.0 * (h) * (h) * (h) ) )
214#define DERIV5P_4(pm2,pm1,p0,pp1,pp2,h) ( ( (pm2) - 4.0 * (pm1) + 6.0 * (p0) - 4.0 * (pp1) + (pp2) ) / ( (h) * (h) * (h) * (h) ) )
215
216/*----- SWITCHES -----*/
217/*---------- internal types ----------*/
218
219/**
220 * components of antenna-pattern function: q_l = {a(t), b(t)}
221 */
222typedef enum {
223 AMCOMP_NONE = -1, /**< no antenna pattern function: (equivalent "a = 1") */
224 AMCOMP_A = 0, /**< a(t) */
225 AMCOMP_B, /**< b(t) */
228
229/** parameters for metric-integration */
230typedef struct {
231 int errnum; /**< store XLAL error of any failures within integrator */
232 double epsrel; /**< relative error tolerance for GSL integration routines */
233 double epsabs; /**< absolute error tolerance for GSL integration routines */
234 double intT; /**< length of integration time segments for phase integrals */
235 DetectorMotionType detMotionType; /**< which detector-motion to use in metric integration */
236 const DopplerCoordinateSystem *coordSys;/**< Doppler coordinate system in use */
237 const gsl_matrix *coordTransf; /**< coordinate transform to apply to coordinate system */
238 int coord1, coord2; /**< coordinate indexes of the two components of the derivative-product Phi_i_Phi_j to compute*/
239 int coord; /**< coordinate index of the component for single phase-derivative Phi_i compute */
240 AM_comp_t amcomp1, amcomp2; /**< two AM components q_l q_m */
241 const PulsarDopplerParams *dopplerPoint;/**< Doppler params to compute metric for */
242 REAL8 startTime; /**< GPS start time of observation */
243 REAL8 refTime; /**< GPS reference time for pulsar parameters */
244 REAL8 Tspan; /**< length of observation time in seconds */
245 const LALDetector *site; /**< detector site to compute metric for */
246 const EphemerisData *edat; /**< ephemeris data */
247 vect3Dlist_t *rOrb_n; /**< list of orbital-radius derivatives at refTime of order n = 0, 1, ... */
248 BOOLEAN approxPhase; /**< use an approximate phase-model, neglecting Roemer delay in spindown coordinates (or orders >= 1) */
250
251
252/*---------- Global variables ----------*/
253
254/* Some local constants. */
255#define rOrb_c (LAL_AU_SI / LAL_C_SI)
256#define rEarth_c (LAL_REARTH_SI / LAL_C_SI)
257#define vOrb_c (LAL_TWOPI * LAL_AU_SI / LAL_C_SI / LAL_YRSID_SI)
258
259/*---------- internal prototypes ----------*/
261static gsl_matrix *XLALComputeFisherFromAtoms( const FmetricAtoms_t *atoms, PulsarAmplitudeParams Amp );
262
263static double CW_am1_am2_Phi_i_Phi_j( double tt, void *params );
264static double CW_Phi_i( double tt, void *params );
265
266static double XLALAverage_am1_am2_Phi_i_Phi_j( const intparams_t *params, double *relerr_max );
267static double XLALCovariance_Phi_ij( const MultiLALDetector *multiIFO, const MultiNoiseFloor *multiNoiseFloor, const LALSegList *segList,
268 const intparams_t *params, double *relerr_max );
269
271
272/*==================== FUNCTION DEFINITIONS ====================*/
273
274/// \addtogroup UniversalDopplerMetric_h
275/// @{
276
277/**
278 * Integrate a general quadruple product CW_am1_am2_Phi_i_Phi_j() from 0 to 1.
279 * This implements the expression \f$ \langle<q_1 q_2 \phi_i \phi_j\rangle \f$
280 * for single-IFO average over the observation time.
281 *
282 * The input parameters correspond to CW_am1_am2_Phi_i_Phi_j()
283 */
284static double
286{
287 intparams_t par = ( *params ); /* struct-copy, as the 'coord' field has to be changeable */
288 gsl_function integrand;
289 double epsrel = params->epsrel;
290 double epsabs = params->epsabs;
291 const size_t limit = 512;
292 gsl_integration_workspace *wksp = NULL;
293 int stat;
294
295 integrand.params = ( void * )&par;
296
297 const UINT4 intN = ( UINT4 ) ceil( params->Tspan / params->intT );
298 const REAL8 dT = 1.0 / intN;
299
300 REAL8 res = 0;
301 REAL8 abserr2 = 0;
302
303 /* allocate workspace for adaptive integration */
304 wksp = gsl_integration_workspace_alloc( limit );
305 XLAL_CHECK_REAL8( wksp != NULL, XLAL_EFAULT );
306
307 const double scale12 = GET_COORD_SCALE( par.coordSys, par.coord1 ) * GET_COORD_SCALE( par.coordSys, par.coord2 );
308
309 /* compute <q_1 q_2 phi_i phi_j> as an integral from tt=0 to tt=1 */
310 integrand.function = &CW_am1_am2_Phi_i_Phi_j;
311 for ( UINT4 n = 0; n < intN; n ++ ) {
312 REAL8 ti = 1.0 * n * dT;
313 REAL8 tf = MYMIN( ( n + 1.0 ) * dT, 1.0 );
314 REAL8 err_n, res_n;
315
316 XLAL_CALLGSL( stat = gsl_integration_qag( &integrand, ti, tf, epsabs, epsrel, limit, GSL_INTEG_GAUSS61, wksp, &res_n, &err_n ) );
317 /* NOTE: we don't fail if the requested level of accuracy was not reached, rather we only output a warning
318 * and try to estimate the final accuracy of the integral
319 */
320 if ( stat != 0 ) {
321 XLALPrintWarning( "\n%s: GSL-integration 'gsl_integration_qag()' of <am1_am2_Phi_i Phi_j> did not reach requested precision!\n", __func__ );
322 XLALPrintWarning( "xlalErrno=%i, Segment n=%d, Result = %g, abserr=%g ==> relerr = %.2e > %.2e\n",
323 par.errnum, n, res_n, err_n, fabs( err_n / res_n ), epsrel );
324 /* XLAL_ERROR_REAL8( XLAL_EFUNC ); */
325 }
326
327 res_n *= scale12;
328 err_n *= scale12;
329
330 res += res_n;
331 abserr2 += SQUARE( err_n );
332
333 } /* for n < intN */
334
335 REAL8 relerr = RELERR( sqrt( abserr2 ), fabs( res ) );
336 if ( relerr_max ) {
337 ( *relerr_max ) = relerr;
338 }
339
340 gsl_integration_workspace_free( wksp );
341
342 return res;
343
344} /* XLALAverage_am1_am2_Phi_i_Phi_j() */
345
346
347/**
348 * For gsl-integration: general quadruple product between two antenna-pattern functions
349 * am1, am2 in {a(t),b(t)} and two phase-derivatives phi_i * phi_j,
350 * i.e. compute an expression of the form
351 * \f$ q_1(t) q_2(t) \phi_i(t) \phi_j(t) \f$ , where \f$ q_i = \{a(t), b(t)\} \f$ .
352 *
353 * NOTE: this can be 'truncated' to any sub-expression by using
354 * AMCOMP_NONE for antenna-pattern component and DOPPLERCOORD_NONE for DopplerCoordinate,
355 * eg in this way this function can be used to compute \f$ a^2(t), b^2(t), a(t) b(t) \f$ ,
356 * or \f$ phi_i(t) phi_j(t) \f$ .
357 */
358static double
360{
362 if ( par->errnum ) {
363 return GSL_NAN;
364 }
365
366 REAL8 am1, am2, phi_i, phi_j, ret;
367
368 am1 = am2 = 1.0; /* default */
369 phi_i = phi_j = 1.0;
370
371 /* do we need any antenna-pattern functions in here? */
372 if ( ( par->amcomp1 != AMCOMP_NONE ) || ( par->amcomp1 != AMCOMP_NONE ) ) {
373 REAL8 ttSI;
374 LIGOTimeGPS ttGPS;
375 SkyPosition skypos;
376 REAL8 ai, bi;
377
379 skypos.longitude = par->dopplerPoint->Alpha;
380 skypos.latitude = par->dopplerPoint->Delta;
381
382 ttSI = par->startTime + tt * par->Tspan; /* current GPS time in seconds */
383 XLALGPSSetREAL8( &ttGPS, ttSI );
384
385 int errnum;
386 XLAL_TRY( XLALComputeAntennaPatternCoeffs( &ai, &bi, &skypos, &ttGPS, par->site, par->edat ), errnum );
387 if ( errnum ) {
388 XLALPrintError( "%s: Call to XLALComputeAntennaPatternCoeffs() failed!\n", __func__ );
389 GSL_ERROR_VAL( "Failure in CW_am1_am2_Phi_i_Phi_j", GSL_EFAILED, GSL_NAN );
390 }
391
392 /* first antenna-pattern component */
393 if ( par->amcomp1 == AMCOMP_A ) {
394 am1 = ai;
395 } else if ( par->amcomp1 == AMCOMP_B ) {
396 am1 = bi;
397 }
398 /* second antenna-pattern component */
399 if ( par->amcomp2 == AMCOMP_A ) {
400 am2 = ai;
401 } else if ( par->amcomp2 == AMCOMP_B ) {
402 am2 = bi;
403 }
404
405 } /* if any antenna-pattern components needed */
406
407 /* first Doppler phase derivative */
408 if ( GET_COORD_ID( par->coordSys, par->coord1 ) != DOPPLERCOORD_NONE ) {
409 par->coord = par->coord1;
410 phi_i = CW_Phi_i( tt, params );
411 } else {
412 phi_i = 1.0;
413 }
414
415 /* second Doppler phase derivative */
416 if ( GET_COORD_ID( par->coordSys, par->coord2 ) != DOPPLERCOORD_NONE ) {
417 par->coord = par->coord2;
418 phi_j = CW_Phi_i( tt, params );
419 } else {
420 phi_j = 1.0;
421 }
422
423 ret = am1 * am2 * phi_i * phi_j;
424
426 "amcomp1=%d amcomp2=%d coord1='%s' coord2='%s' tt=%f am1=%f am2=%f phi_i=%f phi_j=%f ret=%f\n",
427 par->amcomp1, par->amcomp2,
428 GET_COORD_NAME( par->coordSys, par->coord1 ), GET_COORD_NAME( par->coordSys, par->coord2 ),
429 tt, am1, am2, phi_i, phi_j, ret );
430
431 return ( ret );
432
433} /* CW_am1_am2_Phi_i_Phi_j() */
434
435
436REAL8
437XLALComputePhaseDerivative( REAL8 t, ///< time 't' to compute derivative at: (effectively interpreted as SSB time if approxPhase given)
438 const PulsarDopplerParams *dopplerPoint, ///< phase-evolution ('doppler') parameters to compute phase-derivative at
439 DopplerCoordinateID coordID, ///< coord-ID of coordinate wrt which to compute phase derivative
440 const EphemerisData *edat, ///< ephemeris data
441 const LALDetector *site, ///< optional detector (if NULL: use H1 as default)
442 BOOLEAN includeRoemer ///< whether to include Roemer-delay correction 'tSSB = t + dRoemer(t)' or not
443 )
444{
445 XLAL_CHECK_REAL8( dopplerPoint != NULL, XLAL_EINVAL );
447 XLAL_CHECK_REAL8( ( coordID > DOPPLERCOORD_NONE ) && ( coordID < DOPPLERCOORD_LAST ), XLAL_EINVAL );
448
449 const DopplerCoordinateSystem coordSys = {
450 .dim = 1,
451 .coordIDs = { coordID },
452 };
453
454 REAL8 refTime8 = XLALGPSGetREAL8( &( dopplerPoint->refTime ) );
455
457 .detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT, // doesn't matter, dummy value
458 .coordSys = &coordSys,
459 .dopplerPoint = dopplerPoint,
460 .startTime = t,
461 .refTime = refTime8,
462 .Tspan = 0, // doesn't matter, dummy value
463 .site = site ? site :&lalCachedDetectors[LAL_LHO_4K_DETECTOR], // fall back to H1 if passed as NULL
464 .edat = edat,
465 .approxPhase = includeRoemer, // whether to include Roemer-delay correction tSSB = t + dRoemer(t)
466 };
467
468 double scale = DopplerCoordinates[coordID].scale;
469
470 return ( REAL8 )( scale * CW_Phi_i( 0, &params ) );
471
472} // XLALComputePhaseDerivativeSSB()
473
474/**
475 * Partial derivative of continuous-wave (CW) phase, with respect
476 * to Doppler coordinate 'i' := intparams_t->phderiv
477 *
478 * Time is in 'natural units' of Tspan, i.e. tt is in [0, 1] corresponding
479 * to GPS-times in [startTime, startTime + Tspan ]
480 *
481 */
482static double
483CW_Phi_i( double tt, void *params )
484{
486 if ( par->errnum ) {
487 return GSL_NAN;
488 }
489
490 vect3D_t nn_equ, nn_ecl; /* skypos unit vector */
491 vect3D_t nDeriv_i; /* derivative of sky-pos vector wrt i */
492
493 /* positions/velocities at time tt: */
494 PosVel3D_t XLAL_INIT_DECL( spin_posvel );
495 PosVel3D_t XLAL_INIT_DECL( orbit_posvel );
496 PosVel3D_t XLAL_INIT_DECL( posvel );
497
498 /* positions in ecliptic plane */
499 vect3D_t XLAL_INIT_DECL( ecl_orbit_pos );
500 vect3D_t XLAL_INIT_DECL( ecl_pos );
501
502 /* get skypos-vector */
503 const REAL8 cosa = cos( par->dopplerPoint->Alpha );
504 const REAL8 sina = sin( par->dopplerPoint->Alpha );
505 const REAL8 cosd = cos( par->dopplerPoint->Delta );
506 const REAL8 sind = sin( par->dopplerPoint->Delta );
507
508 /* ... in an equatorial coordinate-frame */
509 nn_equ[0] = cosd * cosa;
510 nn_equ[1] = cosd * sina;
511 nn_equ[2] = sind;
512
513 /* and in an ecliptic coordinate-frame */
514 EQU_VECT_TO_ECL( nn_ecl, nn_equ );
515
516 /* get current detector position r(t) and velocity v(t) */
517 REAL8 ttSI = par->startTime + tt * par->Tspan; /* current GPS time in seconds */
518 LIGOTimeGPS ttGPS;
519 XLALGPSSetREAL8( &ttGPS, ttSI );
520 if ( XLALDetectorPosVel( &spin_posvel, &orbit_posvel, &ttGPS, par->site, par->edat, par->detMotionType ) != XLAL_SUCCESS ) {
521 par->errnum = xlalErrno;
522 XLALPrintError( "%s: Call to XLALDetectorPosVel() failed!\n", __func__ );
523 return GSL_NAN;
524 }
525
526 /* XLALDetectorPosVel() returns detector positions and velocities from XLALBarycenter(),
527 which are in units of LAL_C_SI, so we multiply by LAL_C_SI to get back to SI units.
528 We then divide by the internal scale SCALE_R. */
529 MULT_VECT( spin_posvel.pos, LAL_C_SI / SCALE_R );
530 MULT_VECT( orbit_posvel.pos, LAL_C_SI / SCALE_R );
531 MULT_VECT( spin_posvel.vel, LAL_C_SI / SCALE_R );
532 MULT_VECT( orbit_posvel.vel, LAL_C_SI / SCALE_R );
533
534 /* calculate detector total motion = spin motion + orbital motion */
535 COPY_VECT( posvel.pos, spin_posvel.pos );
536 ADD_VECT( posvel.pos, orbit_posvel.pos );
537 COPY_VECT( posvel.vel, spin_posvel.vel );
538 ADD_VECT( posvel.vel, orbit_posvel.vel );
539
540 /* compute detector positions projected onto ecliptic plane */
541 EQU_VECT_TO_ECL( ecl_orbit_pos, orbit_posvel.pos );
542 EQU_VECT_TO_ECL( ecl_pos, posvel.pos );
543
544 /* get frequency of Doppler point */
545 const REAL8 Freq = par->dopplerPoint->fkdot[0];
546
547 /* get time span, normalised by internal scale SCALE_R */
548 const REAL8 Tspan = par->Tspan / SCALE_T;
549
550 /* account for referenceTime != startTime, in units of SCALE_T */
551 REAL8 tau0 = ( par->startTime - par->refTime ) / SCALE_T;
552
553 /* barycentric time-delay since reference time, in units of SCALE_T */
554 REAL8 tau = tau0 + ( tt * Tspan );
555
556 /* correct for time-delay from SSB to detector (Roemer delay), neglecting relativistic effects */
557 if ( !par->approxPhase ) {
558 /* SSB time-delay in internal scaled units */
559 REAL8 dTRoemer = DOT_VECT( nn_equ, posvel.pos ) * ( SCALE_R / LAL_C_SI / SCALE_T );
560
561 tau += dTRoemer;
562 }
563
564 /* get 'reduced' detector position of order 'n': r_n(t) [passed in as argument]
565 * defined as: r_n(t) = r(t) - dot{r_orb}(tau_ref) tau - 1/2! ddot{r_orb}(tau_re) tau^2 - ....
566 */
567 vect3D_t rr_ord_Equ, rr_ord_Ecl;
568 UINT4 i, n;
569 COPY_VECT( rr_ord_Equ, posvel.pos ); /* 0th order */
570 if ( par->rOrb_n ) {
571 /* par->rOrb_n are derivatives with SI time units, so multiply tau by SCALE_T */
572 const double tauSI = tau * SCALE_T;
573 for ( n = 0; n < par->rOrb_n->length; n ++ ) {
574 /* par->rOrb_n->data[n][i] is calculated from detector positions given by XLALBarycenter(),
575 which are in units of LAL_C_SI, so we multiply by LAL_C_SI to get back to SI units.
576 We then divide by the internal scale SCALE_R. */
577 REAL8 pre_n = LAL_FACT_INV[n] * pow( tauSI, n ) * ( LAL_C_SI / SCALE_R );
578 for ( i = 0; i < 3; i++ ) {
579 rr_ord_Equ[i] -= pre_n * par->rOrb_n->data[n][i];
580 }
581 }
582 } /* if rOrb_n */
583 EQU_VECT_TO_ECL( rr_ord_Ecl, rr_ord_Equ ); /* convert into ecliptic coordinates */
584
585 // ---------- prepare shortcuts for binary orbital parameters ----------
586 // See Leaci, Prix, PRD91, 102003 (2015): DOI:10.1103/PhysRevD.91.102003
587 REAL8 orb_asini = par->dopplerPoint->asini;
588 REAL8 orb_Omega = ( LAL_TWOPI / par->dopplerPoint->period );
589 REAL8 orb_kappa = par->dopplerPoint->ecc * cos( par->dopplerPoint->argp ); // Eq.(33)
590 REAL8 orb_eta = par->dopplerPoint->ecc * sin( par->dopplerPoint->argp ); // Eq.(34)
591
592 REAL8 orb_phase = par->dopplerPoint->argp + orb_Omega * ( ttSI - XLALGPSGetREAL8( &( par->dopplerPoint->tp ) ) ); // Eq.(35),(36)
593 REAL8 sinPsi = sin( orb_phase );
594 REAL8 cosPsi = cos( orb_phase );
595 REAL8 sin2Psi = sin( 2.0 * orb_phase );
596 REAL8 cos2Psi = cos( 2.0 * orb_phase );
597
598 /* now compute the requested (possibly linear combination of) phase derivative(s) */
599 REAL8 phase_deriv = 0.0;
600 for ( int coord = 0; coord < ( int )par->coordSys->dim; ++coord ) {
601
602 /* get the coefficient used to multiply phase derivative term */
603 REAL8 coeff = 0.0;
604 if ( par->coordTransf != NULL ) {
605 coeff = gsl_matrix_get( par->coordTransf, par->coord, coord );
606 } else if ( par->coord == coord ) {
607 coeff = 1.0;
608 }
609 if ( coeff == 0.0 ) {
610 continue;
611 }
612 coeff *= GET_COORD_SCALE( par->coordSys, coord ) / GET_COORD_SCALE( par->coordSys, par->coord );
613
614 /* compute the phase derivative term */
615 REAL8 ret = 0.0;
616 const DopplerCoordinateID deriv = GET_COORD_ID( par->coordSys, coord );
617 switch ( deriv ) {
618
619 case DOPPLERCOORD_FREQ: /**< Frequency [Units: Hz]. */
620 case DOPPLERCOORD_GC_NU0: /**< Global correlation frequency [Units: Hz]. Activates 'reduced' detector position. */
621 ret = LAL_TWOPI * tau * LAL_FACT_INV[1];
622 break;
623 case DOPPLERCOORD_F1DOT: /**< First spindown [Units: Hz/s]. */
624 case DOPPLERCOORD_GC_NU1: /**< Global correlation first spindown [Units: Hz/s]. Activates 'reduced' detector position. */
625 ret = LAL_TWOPI * POW2( tau ) * LAL_FACT_INV[2];
626 break;
627 case DOPPLERCOORD_F2DOT: /**< Second spindown [Units: Hz/s^2]. */
628 case DOPPLERCOORD_GC_NU2: /**< Global correlation second spindown [Units: Hz/s^2]. Activates 'reduced' detector position. */
629 ret = LAL_TWOPI * POW3( tau ) * LAL_FACT_INV[3];
630 break;
631 case DOPPLERCOORD_F3DOT: /**< Third spindown [Units: Hz/s^3]. */
632 case DOPPLERCOORD_GC_NU3: /**< Global correlation third spindown [Units: Hz/s^3]. Activates 'reduced' detector position. */
633 ret = LAL_TWOPI * POW4( tau ) * LAL_FACT_INV[4];
634 break;
635 case DOPPLERCOORD_F4DOT: /**< Fourth spindown [Units: Hz/s^4]. */
636 case DOPPLERCOORD_GC_NU4: /**< Global correlation fourth spindown [Units: Hz/s^4]. Activates 'reduced' detector position. */
637 ret = LAL_TWOPI * POW5( tau ) * LAL_FACT_INV[5];
638 break;
639
640 case DOPPLERCOORD_ALPHA: /**< Right ascension [Units: radians]. Uses 'reduced' detector position. */
641 nDeriv_i[0] = - cosd * sina;
642 nDeriv_i[1] = cosd * cosa;
643 nDeriv_i[2] = 0;
644 ret = LAL_TWOPI * Freq * DOT_VECT( rr_ord_Equ, nDeriv_i );
645 break;
646 case DOPPLERCOORD_DELTA: /**< Declination [Units: radians]. Uses 'reduced' detector position. */
647 nDeriv_i[0] = - sind * cosa;
648 nDeriv_i[1] = - sind * sina;
649 nDeriv_i[2] = cosd;
650 ret = LAL_TWOPI * Freq * DOT_VECT( rr_ord_Equ, nDeriv_i );
651 break;
652
653 case DOPPLERCOORD_N2X_EQU: /**< X component of constrained sky position in equatorial coordinates [Units: none]. Uses 'reduced' detector position. */
654 ret = LAL_TWOPI * Freq * ( rr_ord_Equ[0] - ( nn_equ[0] / nn_equ[2] ) * rr_ord_Equ[2] );
655 break;
656 case DOPPLERCOORD_N2Y_EQU: /**< Y component of constrained sky position in equatorial coordinates [Units: none]. Uses 'reduced' detector position. */
657 ret = LAL_TWOPI * Freq * ( rr_ord_Equ[1] - ( nn_equ[1] / nn_equ[2] ) * rr_ord_Equ[2] );
658 break;
659
660 case DOPPLERCOORD_N2X_ECL: /**< X component of constrained sky position in ecliptic coordinates [Units: none]. Uses 'reduced' detector position. */
661 ret = LAL_TWOPI * Freq * ( rr_ord_Ecl[0] - ( nn_ecl[0] / nn_ecl[2] ) * rr_ord_Ecl[2] );
662 break;
663 case DOPPLERCOORD_N2Y_ECL: /**< Y component of constrained sky position in ecliptic coordinates [Units: none]. Uses 'reduced' detector position. */
664 ret = LAL_TWOPI * Freq * ( rr_ord_Ecl[1] - ( nn_ecl[1] / nn_ecl[2] ) * rr_ord_Ecl[2] );
665 break;
666
667 case DOPPLERCOORD_N3X_EQU: /**< X component of unconstrained super-sky position in equatorial coordinates [Units: none]. */
668 ret = LAL_TWOPI * Freq * posvel.pos[0];
669 break;
670 case DOPPLERCOORD_N3Y_EQU: /**< Y component of unconstrained super-sky position in equatorial coordinates [Units: none]. */
671 ret = LAL_TWOPI * Freq * posvel.pos[1];
672 break;
673 case DOPPLERCOORD_N3Z_EQU: /**< Z component of unconstrained super-sky position in equatorial coordinates [Units: none]. */
674 ret = LAL_TWOPI * Freq * posvel.pos[2];
675 break;
676
677 case DOPPLERCOORD_N3X_ECL: /**< X component of unconstrained super-sky position in ecliptic coordinates [Units: none]. */
678 ret = LAL_TWOPI * Freq * ecl_pos[0];
679 break;
680 case DOPPLERCOORD_N3Y_ECL: /**< Y component of unconstrained super-sky position in ecliptic coordinates [Units: none]. */
681 ret = LAL_TWOPI * Freq * ecl_pos[1];
682 break;
683 case DOPPLERCOORD_N3Z_ECL: /**< Z component of unconstrained super-sky position in ecliptic coordinates [Units: none]. */
684 ret = LAL_TWOPI * Freq * ecl_pos[2];
685 break;
686
687 case DOPPLERCOORD_N3SX_EQU: /**< X spin-component of unconstrained super-sky position in equatorial coordinates [Units: none]. */
688 ret = LAL_TWOPI * Freq * spin_posvel.pos[0];
689 break;
690 case DOPPLERCOORD_N3SY_EQU: /**< Y spin-component of unconstrained super-sky position in equatorial coordinates [Units: none]. */
691 ret = LAL_TWOPI * Freq * spin_posvel.pos[1];
692 break;
693
694 case DOPPLERCOORD_N3OX_ECL: /**< X orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none]. */
695 ret = LAL_TWOPI * Freq * ecl_orbit_pos[0];
696 break;
697 case DOPPLERCOORD_N3OY_ECL: /**< Y orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none]. */
698 ret = LAL_TWOPI * Freq * ecl_orbit_pos[1];
699 break;
700 case DOPPLERCOORD_N3OZ_ECL: /**< Z orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none]. */
701 ret = LAL_TWOPI * Freq * ecl_orbit_pos[2];
702 break;
703
704 // ---------- binary orbital parameters ----------
705 // Phase derivates taken from Eq.(39) in Leaci, Prix, PRD91, 102003 (2015): DOI:10.1103/PhysRevD.91.102003
706 case DOPPLERCOORD_ASINI: /**< Projected semimajor axis of binary orbit in small-eccentricy limit (ELL1 model) [Units: light seconds]. */
707 ret = - LAL_TWOPI * Freq * ( sinPsi + 0.5 * orb_kappa * sin2Psi - 0.5 * orb_eta * cos2Psi );
708 break;
709 case DOPPLERCOORD_TASC: /**< Time of ascension (neutron star crosses line of nodes moving away from observer) for binary orbit (ELL1 model) [Units: GPS s]. */
710 ret = LAL_TWOPI * Freq * orb_asini * orb_Omega * ( cosPsi + orb_kappa * cos2Psi + orb_eta * sin2Psi );
711 break;
712 case DOPPLERCOORD_PORB: /**< Period of binary orbit (ELL1 model) [Units: s]. */
713 ret = Freq * orb_asini * orb_Omega * orb_phase * ( cosPsi + orb_kappa * cos2Psi + orb_eta * sin2Psi );
714 break;
715 case DOPPLERCOORD_KAPPA: /**< Lagrange parameter 'kappa = ecc * cos(argp)', ('ecc' = eccentricity, 'argp' = argument of periapse) of binary orbit (ELL1 model) [Units: none] */
716 ret = - LAL_PI * Freq * orb_asini * sin2Psi;
717 break;
718 case DOPPLERCOORD_ETA: /**< Lagrange parameter 'eta = ecc * sin(argp) of binary orbit (ELL1 model) [Units: none] */
719 ret = LAL_PI * Freq * orb_asini * cos2Psi;
720 break;
721
722 // --------- rescaled binary orbital parameters for (approximately) flat metric
723 case DOPPLERCOORD_DASC: /**< Distance traversed on the arc of binary orbit (ELL1 model) 'dasc = 2 * pi * (ap/porb) * tasc' [Units: light second]." */
724 ret = LAL_TWOPI * Freq * ( cosPsi + orb_kappa * cos2Psi + orb_eta * sin2Psi );
725 break;
726
727 case DOPPLERCOORD_VP: /**< Rescaled (by asini) differential-coordinate 'dvp = asini * dOMEGA', ('OMEGA' = 2 * pi/'porb') of binary orbit (ELL1 model) [Units: (light second)/(GPS second)]. */
728 ret = - LAL_TWOPI * Freq * ( orb_phase / orb_Omega ) * ( cosPsi + orb_kappa * cos2Psi + orb_eta * sin2Psi );
729 break;
730
731 case DOPPLERCOORD_KAPPAP: /**< Rescaled (by asini) differential-coordinate 'dkappap = asini * dkappa' [Units: light seconds]. */
732 ret = - LAL_PI * Freq * sin2Psi;
733 break;
734
735 case DOPPLERCOORD_ETAP: /**< Rescaled (by asini) differential-coordinate 'detap = asini * deta' [Units: light seconds]. */
736 ret = LAL_PI * Freq * cos2Psi;
737 break;
738
739 // ------------------------------------------------
740 default:
741 par->errnum = XLAL_EINVAL;
742 XLALPrintError( "%s: Unknown phase-derivative type '%d'\n", __func__, deriv );
743 return GSL_NAN;
744 break;
745
746 } /* switch deriv */
747
748 phase_deriv += coeff * ret;
749
750 }
751
752 return phase_deriv;
753
754} /* CW_Phi_i() */
755
756
757/**
758 * Given a GPS time and detector, return the current position (and velocity) of the detector.
759 */
760int
761XLALDetectorPosVel( PosVel3D_t *spin_posvel, /**< [out] instantaneous sidereal position and velocity vector */
762 PosVel3D_t *orbit_posvel, /**< [out] instantaneous orbital position and velocity vector */
763 const LIGOTimeGPS *tGPS, /**< [in] GPS time */
764 const LALDetector *site, /**< [in] detector info */
765 const EphemerisData *edat, /**< [in] ephemeris data */
766 DetectorMotionType detMotionType /**< [in] detector motion type */
767 )
768{
769 EarthState earth;
770 BarycenterInput XLAL_INIT_DECL( baryinput );
772 PosVel3D_t Det_wrt_Earth;
773 PosVel3D_t PtoleOrbit;
774 PosVel3D_t Spin_z, Spin_xy;
775 const vect3D_t eZ = {0, -LAL_SINIEARTH, LAL_COSIEARTH}; /* ecliptic z-axis in equatorial coordinates */
776
777 XLAL_CHECK( tGPS, XLAL_EFAULT );
780
781 XLAL_CHECK( detMotionType > 0, XLAL_EINVAL, "Invalid detector motion type '%d'", detMotionType );
782
783 /* ----- find ephemeris-based position of Earth wrt to SSB at this moment */
785
786 /* ----- find ephemeris-based position of detector wrt to SSB */
787 baryinput.tgps = *tGPS;
788 baryinput.site = *site;
789 baryinput.site.location[0] /= LAL_C_SI;
790 baryinput.site.location[1] /= LAL_C_SI;
791 baryinput.site.location[2] /= LAL_C_SI;
792 baryinput.alpha = 0;
793 baryinput.delta = 0;
794 baryinput.dInv = 0;
795 XLAL_CHECK( XLALBarycenter( &emit, &baryinput, &earth ) == XLAL_SUCCESS, XLAL_EFUNC );
796
797 /* ----- determine position-vector of detector wrt center of Earth */
798 COPY_VECT( Det_wrt_Earth.pos, emit.rDetector );
799 SUB_VECT( Det_wrt_Earth.pos, earth.posNow );
800 COPY_VECT( Det_wrt_Earth.vel, emit.vDetector );
801 SUB_VECT( Det_wrt_Earth.vel, earth.velNow );
802
803 /* compute ecliptic-z projected spin motion */
804 REAL8 pz = DOT_VECT( Det_wrt_Earth.pos, eZ );
805 REAL8 vz = DOT_VECT( Det_wrt_Earth.vel, eZ );
806 COPY_VECT( Spin_z.pos, eZ );
807 MULT_VECT( Spin_z.pos, pz );
808 COPY_VECT( Spin_z.vel, eZ );
809 MULT_VECT( Spin_z.vel, vz );
810
811 /* compute ecliptic-xy projected spin motion */
812 COPY_VECT( Spin_xy.pos, Det_wrt_Earth.pos );
813 SUB_VECT( Spin_xy.pos, Spin_z.pos );
814 COPY_VECT( Spin_xy.vel, Det_wrt_Earth.vel );
815 SUB_VECT( Spin_xy.vel, Spin_z.vel );
816
817 /* ----- Ptolemaic special case: orbital motion on a circle */
818 if ( detMotionType & DETMOTION_PTOLEORBIT ) {
819 XLAL_CHECK( XLALPtolemaicPosVel( &PtoleOrbit, tGPS ) == XLAL_SUCCESS, XLAL_EFUNC );
820 }
821
822 /* ----- return the requested type of detector motion */
823 if ( spin_posvel ) {
824 switch ( detMotionType & DETMOTION_MASKSPIN ) {
825
826 case 0: /**< No spin motion */
827 ZERO_VECT( spin_posvel->pos );
828 ZERO_VECT( spin_posvel->vel );
829 break;
830
831 case DETMOTION_SPIN: /**< Full spin motion */
832 COPY_VECT( spin_posvel->pos, Det_wrt_Earth.pos );
833 COPY_VECT( spin_posvel->vel, Det_wrt_Earth.vel );
834 break;
835
836 case DETMOTION_SPINZ: /**< Ecliptic-Z component of spin motion only */
837 COPY_VECT( spin_posvel->pos, Spin_z.pos );
838 COPY_VECT( spin_posvel->vel, Spin_z.vel );
839 break;
840
841 case DETMOTION_SPINXY: /**< Ecliptic-X+Y components of spin motion only */
842 COPY_VECT( spin_posvel->pos, Spin_xy.pos );
843 COPY_VECT( spin_posvel->vel, Spin_xy.vel );
844 break;
845
846 default:
847 XLAL_ERROR( XLAL_EINVAL, "%s: Illegal spin motion '%d'\n\n", __func__, detMotionType & DETMOTION_MASKSPIN );
848 break;
849 }
850 }
851 if ( orbit_posvel ) {
852 switch ( detMotionType & DETMOTION_MASKORBIT ) {
853
854 case 0: /**< No orbital motion */
855 ZERO_VECT( orbit_posvel->pos );
856 ZERO_VECT( orbit_posvel->vel );
857 break;
858
859 case DETMOTION_ORBIT: /**< Ephemeris-based orbital motion */
860 COPY_VECT( orbit_posvel->pos, earth.posNow );
861 COPY_VECT( orbit_posvel->vel, earth.velNow );
862 break;
863
864 case DETMOTION_PTOLEORBIT: /**< Ptolemaic (circular) orbital motion */
865 COPY_VECT( orbit_posvel->pos, PtoleOrbit.pos );
866 COPY_VECT( orbit_posvel->vel, PtoleOrbit.vel );
867 break;
868
869 default:
870 XLAL_ERROR( XLAL_EINVAL, "%s: Illegal orbit motion '%d'\n\n", __func__, detMotionType & DETMOTION_MASKORBIT );
871 break;
872 }
873 }
874
875 return XLAL_SUCCESS;
876
877} /* XLALDetectorPosVel() */
878
879
880
881/**
882 * Compute position and velocity assuming a purely "Ptolemaic" orbital motion
883 * (i.e. on a circle) around the sun, approximating Earth's orbit
884 */
885int
886XLALPtolemaicPosVel( PosVel3D_t *posvel, /**< [out] instantaneous position and velocity vector */
887 const LIGOTimeGPS *tGPS /**< [in] GPS time */
888 )
889{
890 REAL8 tMidnight, tAutumn;
891 REAL8 phiOrb; /* Earth orbital revolution angle, in radians. */
892 REAL8 sinOrb, cosOrb;
893
894 if ( !posvel || !tGPS ) {
895 XLALPrintError( "%s: Illegal NULL pointer passed!\n", __func__ );
897 }
898
899 XLAL_CHECK( XLALGetEarthTimes( tGPS, &tMidnight, &tAutumn ) == XLAL_SUCCESS, XLAL_EFUNC );
900
901 phiOrb = - LAL_TWOPI * tAutumn / LAL_YRSID_SI;
902 sinOrb = sin( phiOrb );
903 cosOrb = cos( phiOrb );
904
905 /* Get instantaneous position. */
906 posvel->pos[0] = rOrb_c * cosOrb;
907 posvel->pos[1] = rOrb_c * sinOrb * LAL_COSIEARTH;
908 posvel->pos[2] = rOrb_c * sinOrb * LAL_SINIEARTH;
909
910 /* Get instantaneous velocity. */
911 posvel->vel[0] = -vOrb_c * sinOrb;
912 posvel->vel[1] = vOrb_c * cosOrb * LAL_COSIEARTH;
913 posvel->vel[2] = vOrb_c * cosOrb * LAL_SINIEARTH;
914
915 return XLAL_SUCCESS;
916
917} /* XLALPtolemaicPosVel() */
918
919
920
921/**
922 * Compute a pure phase-deriv covariance \f$ [\phi_i, \phi_j] = \langle phi_i phi_j\rangle - \langle phi_i\rangle\langle phi_j\rangle \f$
923 * which gives a component of the "phase metric".
924 *
925 * NOTE: for passing unit noise-weights, set MultiNoiseFloor->length=0 (but multiNoiseFloor==NULL is invalid)
926 */
927static double
928XLALCovariance_Phi_ij( const MultiLALDetector *multiIFO, //!< [in] detectors to use
929 const MultiNoiseFloor *multiNoiseFloor, //!< [in] corresponding noise floors for weights, NULL means unit-weights
930 const LALSegList *segList, //!< [in] segment list
931 const intparams_t *params, //!< [in] integration parameters
932 double *relerr_max //!< [in] maximal error for integration
933 )
934{
935 XLAL_CHECK_REAL8( multiIFO != NULL, XLAL_EINVAL );
936 UINT4 numDet = multiIFO->length;
938
939 // either no noise-weights given (multiNoiseFloor->length=0) or same number of detectors
940 XLAL_CHECK_REAL8( multiNoiseFloor != NULL, XLAL_EINVAL );
941 BOOLEAN haveNoiseWeights = ( multiNoiseFloor->length > 0 );
942 XLAL_CHECK_REAL8( !haveNoiseWeights || ( multiNoiseFloor->length == numDet ), XLAL_EINVAL );
943
945 UINT4 Nseg = segList->length;
946
947 /* sanity-check: don't allow any AM-coeffs being turned on here! */
948 if ( params->amcomp1 != AMCOMP_NONE || params->amcomp2 != AMCOMP_NONE ) {
949 XLALPrintError( "%s: Illegal input, amcomp[12] must be set to AMCOMP_NONE!\n", __func__ );
951 }
952
953 /* store detector weights and accumulate total weight */
954 REAL8 total_weight = 0.0, weights[numDet];
955 for ( UINT4 X = 0; X < numDet; X ++ ) {
956 weights[X] = haveNoiseWeights ? multiNoiseFloor->sqrtSn[X] : 1.0;
957 total_weight += weights[X];
958 }
959 XLAL_CHECK_REAL8( total_weight > 0, XLAL_EDOM, "Detectors noise-floors given but all zero!" );
960
961 /* ---------- set up GSL integration ---------- */
962
963 /* constants passed to GSL integration function */
964 const double epsrel = params->epsrel;
965 const double epsabs = params->epsabs;
966 const size_t limit = 512;
967
968 /* array of structs storing input and output info for GSL integration */
969 UINT4 intN[Nseg][numDet];
970 typedef struct {
971 intparams_t par; /* integration parameters */
972 double ti; /* integration start time */
973 double tf; /* integration end time */
974 gsl_integration_workspace *wksp ; /* GSL integration workspace */
975 double av_ij; /* value of integral <phi_i phi_j> */
976 double av_i; /* value of integral <phi_i> */
977 double av_j; /* value of integral <phi_j> */
978 double av_ij_err_sq; /* squared error in value of integral <phi_i phi_j> */
979 double av_i_err_sq; /* squared error in value of integral <phi_i> */
980 double av_j_err_sq; /* squared error in value of integral <phi_j> */
981 } InputOutputInfo;
982 InputOutputInfo *intInOut[Nseg][numDet];
983
984 // loop over segments and detectors
985 for ( size_t k = 0; k < Nseg; ++k ) {
986 for ( size_t X = 0; X < numDet; ++X ) {
987
988 intparams_t par = ( *params ); /* struct-copy, as the 'coord' field has to be changeable */
989
990 // set start time and time span for this segment
991 const LIGOTimeGPS *startTime = &( segList->segs[k].start );
992 const LIGOTimeGPS *endTime = &( segList->segs[k].end );
993 const REAL8 Tspan = XLALGPSDiff( endTime, startTime );
994 par.startTime = XLALGPSGetREAL8( startTime );
995 par.Tspan = Tspan;
996
997 // set detector for phase integrals
998 par.site = &multiIFO->sites[X];
999
1000 // calculate how many 'units' integral is split into
1001 intN[k][X] = ( UINT4 ) ceil( par.Tspan / par.intT );
1002
1003 // allocate memory of input/output info
1004 intInOut[k][X] = XLALCalloc( intN[k][X], sizeof( *intInOut[k][X] ) );
1005 XLAL_CHECK_REAL8( intInOut[k][X] != NULL, XLAL_ENOMEM );
1006
1007 // initialise input info
1008 for ( size_t n = 0; n < intN[k][X]; ++n ) {
1009
1010 InputOutputInfo *io = &intInOut[k][X][n];
1011
1012 io->par = par;
1013
1014 const double dT = 1.0 / intN[k][X];
1015 io->ti = 1.0 * n * dT;
1016 io->tf = MYMIN( ( n + 1.0 ) * dT, 1.0 );
1017
1018 XLAL_CHECK_REAL8( ( io->wksp = gsl_integration_workspace_alloc( limit ) ) != NULL, XLAL_ENOMEM );
1019
1020 } /* for n < intN */
1021
1022 } // for X < numDet
1023 } // for k < Nseg
1024
1025 /* ---------- perform GSL integration ---------- */
1026
1027 // turn off GSL error handling
1028 gsl_error_handler_t *saveGSLErrorHandler;
1029 saveGSLErrorHandler = gsl_set_error_handler_off();
1030
1031 // loop over segments, detectors, and integration 'units'
1032 // together using a single index, for parallelisation
1033 {
1034 size_t index_max = 0;
1035 for ( size_t k = 0; k < Nseg; ++k ) {
1036 for ( size_t X = 0; X < numDet; ++X ) {
1037 index_max += intN[k][X];
1038 }
1039 }
1040 #pragma omp parallel for schedule(static)
1041 for ( size_t indx = 0; indx < index_max; ++indx ) {
1042 // break single index into 'k', 'X', and 'n'
1043 size_t k = 0, X = 0, n = 0, index_break = indx + 1;
1044 for ( k = 0; k < Nseg; ++k ) {
1045 for ( X = 0; X < numDet; ++X ) {
1046 if ( index_break > intN[k][X] ) {
1047 index_break -= intN[k][X];
1048 } else {
1049 n = index_break - 1;
1050 index_break = 0;
1051 break;
1052 }
1053 }
1054 if ( index_break == 0 ) {
1055 break;
1056 }
1057 }
1058
1059 InputOutputInfo *io = &intInOut[k][X][n];
1060
1061 gsl_function integrand;
1062 integrand.params = ( void * ) & ( io->par );
1063
1064 int stat;
1065 double res, abserr;
1066
1067 const double scale1 = GET_COORD_SCALE( io->par.coordSys, io->par.coord1 );
1068 const double scale2 = GET_COORD_SCALE( io->par.coordSys, io->par.coord2 );
1069 const double scale12 = scale1 * scale2;
1070
1071 /* compute <phi_i phi_j> */
1072 integrand.function = &CW_am1_am2_Phi_i_Phi_j;
1073 stat = gsl_integration_qag( &integrand, io->ti, io->tf, epsabs, epsrel, limit, GSL_INTEG_GAUSS61, io->wksp, &res, &abserr );
1074 if ( stat != 0 ) {
1075 XLALPrintWarning( "\n%s: GSL-integration 'gsl_integration_qag()' of <Phi_i Phi_j> did not reach requested precision!\n", __func__ );
1076 XLALPrintWarning( "xlalErrno=%i, seg=%zu, av_ij_n=%g, abserr=%g\n", io->par.errnum, n, res, abserr );
1077 io->av_ij = GSL_NAN;
1078 } else {
1079 io->av_ij = scale12 * res;
1080 io->av_ij_err_sq = SQUARE( scale12 * abserr );
1081 }
1082
1083 /* compute <phi_i> */
1084 integrand.function = &CW_Phi_i;
1085 io->par.coord = io->par.coord1;
1086 stat = gsl_integration_qag( &integrand, io->ti, io->tf, epsabs, epsrel, limit, GSL_INTEG_GAUSS61, io->wksp, &res, &abserr );
1087 if ( stat != 0 ) {
1088 XLALPrintWarning( "\n%s: GSL-integration 'gsl_integration_qag()' of <Phi_i> did not reach requested precision!\n", __func__ );
1089 XLALPrintWarning( "xlalErrno=%i, seg=%zu, av_i_n=%g, abserr=%g\n", io->par.errnum, n, res, abserr );
1090 io->av_i = GSL_NAN;
1091 } else {
1092 io->av_i = scale1 * res;
1093 io->av_i_err_sq = SQUARE( scale1 * abserr );
1094 }
1095
1096 /* compute <phi_j> */
1097 integrand.function = &CW_Phi_i;
1098 io->par.coord = io->par.coord2;
1099 stat = gsl_integration_qag( &integrand, io->ti, io->tf, epsabs, epsrel, limit, GSL_INTEG_GAUSS61, io->wksp, &res, &abserr );
1100 if ( stat != 0 ) {
1101 XLALPrintWarning( "\n%s: GSL-integration 'gsl_integration_qag()' of <Phi_j> did not reach requested precision!\n", __func__ );
1102 XLALPrintWarning( "xlalErrno=%i, seg=%zu, av_j_n=%g, abserr=%g\n", io->par.errnum, n, res, abserr );
1103 io->av_j = GSL_NAN;
1104 } else {
1105 io->av_j = scale2 * res;
1106 io->av_j_err_sq = SQUARE( scale2 * abserr );
1107 }
1108
1109 } /* for indx < index_max */
1110 }
1111
1112 // restore GSL error handling
1113 gsl_set_error_handler( saveGSLErrorHandler );
1114
1115 /* ---------- compute final result ---------- */
1116
1117 double ret = 0, relerr_max_sq = 0;
1118
1119 // loop over segments
1120 for ( UINT4 k = 0; k < Nseg; k ++ ) {
1121
1122 double av_ij = 0, av_ij_err_sq = 0;
1123 double av_i = 0, av_i_err_sq = 0;
1124 double av_j = 0, av_j_err_sq = 0;
1125
1126 // loop over detectors and integration 'units'
1127 for ( UINT4 X = 0; X < numDet; X ++ ) {
1128 for ( size_t n = 0; n < intN[k][X]; ++n ) {
1129
1130 const InputOutputInfo *io = &intInOut[k][X][n];
1131
1132 /* accumulate <phi_i phi_j> */
1133 av_ij += weights[X] * io->av_ij;
1134 av_ij_err_sq += weights[X] * io->av_ij_err_sq;
1135
1136 /* accumulate <phi_i> */
1137 av_i += weights[X] * io->av_i;
1138 av_i_err_sq += weights[X] * io->av_i_err_sq;
1139
1140 /* accumulate <phi_j> */
1141 av_j += weights[X] * io->av_j;
1142 av_j_err_sq += weights[X] * io->av_j_err_sq;
1143
1144 } /* for n < intN */
1145
1146 } // for X < numDet
1147
1148 // normalise by total weight
1149 av_ij /= total_weight;
1150 av_i /= total_weight;
1151 av_j /= total_weight;
1152 av_ij_err_sq /= total_weight;
1153 av_i_err_sq /= total_weight;
1154 av_j_err_sq /= total_weight;
1155
1156 // work out maximum relative error for this segment
1157 const double av_ij_relerr = RELERR( sqrt( av_ij_err_sq ), fabs( av_ij ) );
1158 const double av_i_relerr = RELERR( sqrt( av_i_err_sq ), fabs( av_i ) );
1159 const double av_j_relerr = RELERR( sqrt( av_j_err_sq ), fabs( av_j ) );
1160 const double relerr_max_k = MYMAX( av_ij_relerr, MYMAX( av_i_relerr, av_j_relerr ) );
1161
1162 ret += av_ij - av_i * av_j;
1163 relerr_max_sq += SQUARE( relerr_max_k );
1164
1165 } // for k < Nseg
1166
1167 ret /= Nseg;
1168 relerr_max_sq /= Nseg;
1169
1170 if ( relerr_max ) {
1171 ( *relerr_max ) = sqrt( relerr_max_sq );
1172 }
1173
1174 /* ----- cleanup ----- */
1175
1176 for ( size_t k = 0; k < Nseg; ++k ) {
1177 for ( size_t X = 0; X < numDet; ++X ) {
1178 for ( size_t n = 0; n < intN[k][X]; ++n ) {
1179 InputOutputInfo *io = &intInOut[k][X][n];
1180 gsl_integration_workspace_free( io->wksp );
1181 }
1182 XLALFree( intInOut[k][X] );
1183 }
1184 }
1185
1186 return ret;
1187
1188} /* XLALCovariance_Phi_ij() */
1189
1190
1191/**
1192 * Calculate an approximate "phase-metric" with the specified parameters.
1193 *
1194 * Note: if this function is called with multiple detectors, the phase components
1195 * are averaged over detectors as well as time. This is a somewhat ad-hoc approach;
1196 * if you want a more rigorous multi-detector metric you need to use the full
1197 * Fstat-metric, as computed by XLALComputeDopplerFstatMetric().
1198 *
1199 * Return NULL on error.
1200 */
1202XLALComputeDopplerPhaseMetric( const DopplerMetricParams *metricParams, /**< input parameters determining the metric calculation */
1203 const EphemerisData *edat /**< ephemeris data */
1204 )
1205{
1206 intparams_t XLAL_INIT_DECL( intparams );
1207
1208 /* ---------- sanity/consistency checks ---------- */
1209 XLAL_CHECK_NULL( metricParams != NULL, XLAL_EINVAL );
1210 XLAL_CHECK_NULL( edat != NULL, XLAL_EINVAL );
1211 XLAL_CHECK_NULL( XLALSegListIsInitialized( &( metricParams->segmentList ) ), XLAL_EINVAL, "Passed un-initialzied segment list 'metricParams->segmentList'\n" );
1212 UINT4 Nseg = metricParams->segmentList.length;
1213
1214 UINT4 dim = metricParams->coordSys.dim;
1215 const DopplerCoordinateSystem *coordSys = &( metricParams->coordSys );
1216 // ----- check that {n2x_equ, n2y_equ} are not used at the equator (delta=0), as metric is undefined there
1217 BOOLEAN have_n2xy = 0;
1218 for ( UINT4 i = 0; i < dim; i ++ ) {
1219 if ( ( coordSys->coordIDs[i] == DOPPLERCOORD_N2X_EQU ) || ( coordSys->coordIDs[i] == DOPPLERCOORD_N2Y_EQU ) ) {
1220 have_n2xy = 1;
1221 }
1222 }
1223 BOOLEAN at_equator = ( metricParams->signalParams.Doppler.Delta == 0 );
1224 XLAL_CHECK_NULL( !( at_equator && have_n2xy ), XLAL_EINVAL, "Can't use 'n2x_equ','n2y_equ' at equator (Delta=0): metric is singular there" );
1225
1226 // ----- allocate output DopplerPhaseMetric() struct
1227 DopplerPhaseMetric *metric = XLALCalloc( 1, sizeof( *metric ) );
1229
1230 // ----- compute segment-list midTime
1231 LIGOTimeGPS midTime;
1232 {
1233 const LIGOTimeGPS *startTime = &( metricParams->segmentList.segs[0].start );
1234 const LIGOTimeGPS *endTime = &( metricParams->segmentList.segs[Nseg - 1].end );
1235 const REAL8 Tspan = XLALGPSDiff( endTime, startTime );
1236 midTime = *startTime;
1237 XLALGPSAdd( &midTime, 0.5 * Tspan );
1238 }
1239
1240 /* ---------- prepare output metric ---------- */
1241 if ( ( metric->g_ij = gsl_matrix_calloc( dim, dim ) ) == NULL ) {
1242 XLALPrintError( "%s: gsl_matrix_calloc(%d, %d) failed.\n\n", __func__, dim, dim );
1244 }
1245
1246 /* ---------- set up integration parameters ---------- */
1247 intparams.coordSys = coordSys;
1248 intparams.edat = edat;
1249 intparams.refTime = XLALGPSGetREAL8( &midTime ); /* always compute metric at midTime, transform to refTime later */
1250 intparams.dopplerPoint = &( metricParams->signalParams.Doppler );
1251 intparams.detMotionType = metricParams->detMotionType;
1252 intparams.approxPhase = metricParams->approxPhase;
1253 /* deactivate antenna-patterns for phase-metric */
1254 intparams.amcomp1 = AMCOMP_NONE;
1255 intparams.amcomp2 = AMCOMP_NONE;
1256
1257 /* if using 'global correlation' frequency variables, determine the highest spindown order: */
1258 UINT4 maxorder = findHighestGCSpinOrder( coordSys );
1259 if ( maxorder > 0 ) {
1260
1261 /* compute rOrb(t) derivatives at reference time */
1262 if ( ( intparams.rOrb_n = XLALComputeOrbitalDerivatives( maxorder, &intparams.dopplerPoint->refTime, edat ) ) == NULL ) {
1263 XLALPrintError( "%s: XLALComputeOrbitalDerivatives() failed.\n", __func__ );
1265 }
1266 if ( lalDebugLevel & LALINFOBIT ) {
1267 /* diagnostic / debug output */
1268 fprintf( stderr, "%s: rOrb_n(%d) = [ ", __func__, intparams.dopplerPoint->refTime.gpsSeconds );
1269 for ( UINT4 n = 0; n < intparams.rOrb_n->length; n++ ) {
1270 fprintf( stderr, "[%g, %g, %g]%s", intparams.rOrb_n->data[n][0], intparams.rOrb_n->data[n][1], intparams.rOrb_n->data[n][2],
1271 ( n < intparams.rOrb_n->length - 1 ) ? ", " : " ]\n" );
1272 }
1273 }
1274
1275 }
1276
1277 metric->maxrelerr = 0;
1278 double err = 0;
1279
1280 /* ========== use numerically-robust method to compute metric ========== */
1281
1282 /* allocate memory for coordinate transform */
1283 gsl_matrix *transform = gsl_matrix_alloc( dim, dim );
1284 XLAL_CHECK_NULL( transform != NULL, XLAL_ENOMEM );
1285 gsl_matrix_set_identity( transform );
1286 intparams.coordTransf = transform;
1287
1288 for ( size_t n = 1; n <= dim; ++n ) {
1289
1290 /* NOTE: this level of accuracy is only achievable *without* AM-coefficients involved
1291 * which are computed in REAL4 precision. For the current function this is OK, as this
1292 * function is only supposed to compute *pure* phase-derivate covariances.
1293 */
1294 intparams.epsrel = 1e-6;
1295 /* we need an abs-cutoff as well, as epsrel can be too restrictive for small integrals */
1296 intparams.epsabs = 1e-3;
1297 /* NOTE: this numerical integration still runs into problems when integrating over
1298 * long durations (~O(23d)), as the integrands are oscillatory functions on order of ~1d
1299 * and convergence degrades.
1300 * As a solution, we split the integral into 'intN' units of ~1 day duration, and compute
1301 * the final integral as a sum over partial integrals.
1302 * It is VERY important to ensure that 'intT' is not exactly 1 day, since then an integrand
1303 * with period ~1 day may integrate to zero, which is both slower and MUCH more difficult
1304 * for the numerical integration functions (since the integrand them becomes small with
1305 * respect to any integration errors).
1306 */
1307 intparams.intT = 0.9 * LAL_DAYSID_SI;
1308
1309 /* allocate memory for Cholesky decomposition */
1310 gsl_matrix *cholesky = gsl_matrix_alloc( n, n );
1311 XLAL_CHECK_NULL( cholesky != NULL, XLAL_ENOMEM );
1312
1313 /* create views of n-by-n submatrices of metric and coordinate transform */
1314 gsl_matrix_view g_ij_n = gsl_matrix_submatrix( metric->g_ij, 0, 0, n, n );
1315 gsl_matrix_view transform_n = gsl_matrix_submatrix( transform, 0, 0, n, n );
1316
1317 /* try this loop a certain number of times */
1318 const size_t max_tries = 64;
1319 size_t tries = 0;
1320 while ( ++tries <= max_tries ) {
1321
1322 /* ----- compute last row/column of n-by-n submatrix of metric ----- */
1323 for ( size_t i = 0; i < n; ++i ) {
1324 const size_t j = n - 1;
1325
1326 /* g_ij = [Phi_i, Phi_j] */
1327 intparams.coord1 = i;
1328 intparams.coord2 = j;
1329 REAL8 gg = XLALCovariance_Phi_ij( &metricParams->multiIFO, &metricParams->multiNoiseFloor, &metricParams->segmentList,
1330 &intparams, &err );
1331 XLAL_CHECK_NULL( !gsl_isnan( gg ), XLAL_EFUNC, "%s: integration of phase metric g_{i=%zu,j=%zu} failed (n=%zu, tries=%zu)", __func__, i, j, n, tries );
1332 gsl_matrix_set( &g_ij_n.matrix, i, j, gg );
1333 gsl_matrix_set( &g_ij_n.matrix, j, i, gg );
1334 metric->maxrelerr = MYMAX( metric->maxrelerr, err );
1335
1336 } /* for i < n */
1337
1338 /* ----- compute L D L^T Cholesky decomposition of metric ----- */
1339 XLAL_CHECK_NULL( XLALCholeskyLDLTDecompMetric( &cholesky, &g_ij_n.matrix ) == XLAL_SUCCESS, XLAL_EFUNC );
1340 gsl_vector_view D = gsl_matrix_diagonal( cholesky );
1341 if ( ( tries > 1 ) && ( lalDebugLevel & LALINFOBIT ) ) {
1342 /* diagnostic / debug output */
1343 fprintf( stdout, "%s: n=%zu, try=%zu, Cholesky diagonal =", __func__, n, tries );
1344 XLALfprintfGSLvector( stdout, "%0.2e", &D.vector );
1345 }
1346
1347 /* ----- check that all diagonal elements D are positive after at least 1 try; if so, exit try loop */
1348 if ( ( tries > 1 ) && ( gsl_vector_min( &D.vector ) > 0.0 ) ) {
1349 break;
1350 }
1351
1352 /* zero out all but last row of L, since we do not want to coordinates before 'n' */
1353 if ( n > 1 ) {
1354 gsl_matrix_view cholesky_nm1 = gsl_matrix_submatrix( cholesky, 0, 0, n - 1, n );
1355 gsl_matrix_set_identity( &cholesky_nm1.matrix );
1356 }
1357
1358 /* multiply transform by inverse of L (with unit diagonal), to transform 'n'th coordinates so that metric is diagonal */
1359 gsl_blas_dtrsm( CblasLeft, CblasLower, CblasNoTrans, CblasUnit, 1.0, cholesky, &transform_n.matrix );
1360
1361 /* decrease relative error tolerances; don't do this too quickly, since
1362 too-stringent tolerances may make GSL integration fail to converge */
1363 intparams.epsrel = intparams.epsrel * 0.9;
1364 /* decrease absolute error tolerances; don't do this too quickly, since
1365 too-stringent tolerances may make GSL integration fail to converge,
1366 and only after a certain number of tries, otherwise small integrals
1367 fail to converge */
1368 if ( tries >= 8 ) {
1369 intparams.epsabs = intparams.epsabs * 0.9;
1370 }
1371 /* reduce the length of integration time units, but stop at 900s,
1372 and ensure that 'intT' does NOT become divisible by 1/day, for
1373 the same reason given at the initialisation of 'intT' above */
1374 intparams.intT = MYMAX( 900, intparams.intT * 0.9 );
1375
1376 }
1377 XLAL_CHECK_NULL( tries <= max_tries, XLAL_EMAXITER, "%s: convergence of phase metric failed (n=%zu)", __func__, n );
1378
1379 /* free memory which is then re-allocated in next loop */
1380 gsl_matrix_free( cholesky );
1381
1382 }
1383
1384 /* apply inverse of transform^T to metric, to get back original coordinates */
1385 gsl_matrix_transpose( transform );
1387
1388 /* transform phase metric reference time from midTime to refTime */
1389 const REAL8 Dtau = XLALGPSDiff( &( metricParams->signalParams.Doppler.refTime ), &midTime );
1390 XLAL_CHECK_NULL( XLALChangeMetricReferenceTime( &metric->g_ij, NULL, metric->g_ij, &( metricParams->coordSys ), Dtau ) == XLAL_SUCCESS, XLAL_EFUNC );
1391
1392 /* ----- if requested, project g_ij onto coordinate 'projectCoord' */
1393 if ( metricParams->projectCoord >= 0 ) {
1394 UINT4 projCoord = ( UINT4 )metricParams->projectCoord;
1395 if ( XLALProjectMetric( &metric->g_ij, metric->g_ij, projCoord ) != XLAL_SUCCESS ) {
1396 XLALPrintError( "%s: failed to project g_ij onto coordinate '%d'. errno=%d\n", __func__, projCoord, xlalErrno );
1398 }
1399 } /* if projectCoordinate >= 0 */
1400
1401 /* ---- check that metric is positive definite, by checking determinants of submatrices */
1402 for ( size_t n = 1; n <= dim; ++n ) {
1403 gsl_matrix_view g_ij_n = gsl_matrix_submatrix( metric->g_ij, 0, 0, n, n );
1404 const double det_n = XLALMetricDeterminant( &g_ij_n.matrix );
1405 XLAL_CHECK_NULL( det_n > 0, XLAL_EFAILED, "%s: could not compute a positive-definite phase metric (n=%zu, det_n=%0.3e)", __func__, n, det_n );
1406 }
1407 if ( lalDebugLevel & LALINFOBIT ) {
1408 /* diagnostic / debug output */
1409 fprintf( stdout, "%s: phase metric:", __func__ );
1410 XLALfprintfGSLmatrix( stdout, "%0.15e", metric->g_ij );
1411 }
1412
1413 /* attach the metricParams struct as 'meta-info' to the output */
1414 metric->meta = ( *metricParams );
1415
1416 /* free memory */
1417 XLALDestroyVect3Dlist( intparams.rOrb_n );
1418 gsl_matrix_free( transform );
1419
1420 return metric;
1421
1422} /* XLALComputeDopplerPhaseMetric() */
1423
1424
1425/** Free a DopplerPhaseMetric structure */
1426void
1428{
1429 if ( !metric ) {
1430 return;
1431 }
1432
1433 gsl_matrix_free( metric->g_ij );
1434
1435 XLALFree( metric );
1436
1437 return;
1438
1439} /* XLALDestroyDopplerPhaseMetric() */
1440
1441
1442/**
1443 * Calculate the general (single-segment coherent, or multi-segment semi-coherent)
1444 * *full* (multi-IFO) Fstat-metrix and the Fisher-matrix derived in \cite Prix07 .
1445 *
1446 * The semi-coherent metrics \f$ g_{ij} \f$ over \f$ N \f$ segments are computed according to
1447 *
1448 * \f[ \overline{g}_{ij} \equiv \frac{1}{N} \sum_{k=1}^{N} g_{ij,k} \f]
1449 *
1450 * where \f$ g_{ij,k} \f$ is the coherent single-segment metric of segment k
1451 *
1452 * Note: The returned DopplerFstatMetric struct contains the matrices
1453 * g_ij (the phase metric), gF_ij (the F-metric), gFav_ij (the average F-metric),
1454 * m1_ij, m2_ij, m3_ij (auxiliary matrices)
1455 * and Fisher_ab (the full 4+n dimensional Fisher matrix).
1456 *
1457 * The returned metric struct also carries the meta-info about
1458 * the metrics in the field 'DopplerMetricParams meta'.
1459 *
1460 * Note2: for backwards-compatibility, we treat params->Nseg==0 equivalent to Nseg==1, ie
1461 * compute the coherent, single-segment metrics
1462 *
1463 * Return NULL on error.
1464 */
1466XLALComputeDopplerFstatMetric( const DopplerMetricParams *metricParams, /**< input parameters determining the metric calculation */
1467 const EphemerisData *edat /**< ephemeris data */
1468 )
1469{
1470 XLAL_CHECK_NULL( metricParams, XLAL_EINVAL, "Invalid NULL input 'metricParams'\n" );
1471 XLAL_CHECK_NULL( XLALSegListIsInitialized( &( metricParams->segmentList ) ), XLAL_EINVAL, "Passed un-initialzied segment list 'metricParams->segmentList'\n" );
1472
1473 UINT4 dim = metricParams->coordSys.dim;
1474 const DopplerCoordinateSystem *coordSys = &( metricParams->coordSys );
1475 // ----- check that {n2x_equ, n2y_equ} are not used at the equator (delta=0), as metric is undefined there
1476 BOOLEAN have_n2xy = 0;
1477 for ( UINT4 i = 0; i < dim; i ++ ) {
1478 if ( ( coordSys->coordIDs[i] == DOPPLERCOORD_N2X_EQU ) || ( coordSys->coordIDs[i] == DOPPLERCOORD_N2Y_EQU ) ) {
1479 have_n2xy = 1;
1480 }
1481 }
1482 BOOLEAN at_equator = ( metricParams->signalParams.Doppler.Delta == 0 );
1483 XLAL_CHECK_NULL( !( at_equator && have_n2xy ), XLAL_EINVAL, "Can't use 'n2x_equ','n2y_equ' at equator (Delta=0): metric is singular there" );
1484
1485 UINT4 Nseg = metricParams->segmentList.length; // number of semi-coherent segments to average metrics over
1486 XLAL_CHECK_NULL( Nseg >= 1, XLAL_EINVAL, "Got empty segment list metricParams->segmentList, needs to contain at least 1 segments\n" );
1487
1488 DopplerFstatMetric *metric = NULL;
1489
1490 LALSegList segList_k;
1491 LALSeg segment_k;
1492 XLALSegListInit( &segList_k ); // prepare single-segment list containing segment k
1493 segList_k.arraySize = 1;
1494 segList_k.length = 1;
1495 segList_k.segs = &segment_k;
1496
1497 DopplerMetricParams metricParams_k = ( *metricParams ); // *copy* of input parameters to be used for single-segment coherent metrics
1498 metricParams_k.segmentList = segList_k;
1499
1500 for ( UINT4 k = 0; k < Nseg; k ++ ) {
1501 DopplerFstatMetric *metric_k; // per-segment coherent metric
1502 FmetricAtoms_t *atoms = NULL;
1503
1504 // setup 1-segment segment-list pointing k-th segment
1505 metricParams_k.segmentList.segs[0] = metricParams->segmentList.segs[k];
1506
1507 /* ---------- compute Fmetric 'atoms', ie the averaged <a^2>, <a b Phi_i>, <a^2 Phi_i Phi_j>, etc ---------- */
1508 if ( ( atoms = XLALComputeAtomsForFmetric( &metricParams_k, edat ) ) == NULL ) {
1509 XLALPrintError( "%s: XLALComputeAtomsForFmetric() failed. errno = %d\n\n", __func__, xlalErrno );
1511 }
1512
1513 /* ----- compute the F-metric gF_ij and related matrices ---------- */
1514 REAL8 h0 = metricParams->signalParams.Amp.aPlus + sqrt( POW2( metricParams->signalParams.Amp.aPlus ) - POW2( metricParams->signalParams.Amp.aCross ) );
1515 REAL8 cosi;
1516 if ( h0 > 0 ) {
1517 cosi = metricParams->signalParams.Amp.aCross / h0;
1518 } else {
1519 cosi = 0;
1520 }
1521 REAL8 psi = metricParams->signalParams.Amp.psi;
1522
1523 if ( ( metric_k = XLALComputeFmetricFromAtoms( atoms, cosi, psi ) ) == NULL ) {
1524 XLALPrintError( "%s: XLALComputeFmetricFromAtoms() failed, errno = %d\n\n", __func__, xlalErrno );
1525 XLALDestroyFmetricAtoms( atoms );
1527 }
1528
1529 /* ----- compute the full 4+n dimensional Fisher matrix ---------- */
1530 if ( ( metric_k->Fisher_ab = XLALComputeFisherFromAtoms( atoms, metricParams->signalParams.Amp ) ) == NULL ) {
1531 XLALPrintError( "%s: XLALComputeFisherFromAtoms() failed. errno = %d\n\n", __func__, xlalErrno );
1532 XLALDestroyFmetricAtoms( atoms );
1535 }
1536
1537 XLALDestroyFmetricAtoms( atoms );
1538
1539 /* ---- add DopplerFstatMetric results over segments ----- */
1540 if ( metric == NULL ) {
1541 metric = metric_k; // just use DopplerFstatMetric from 1st segment
1542 } else {
1543
1544 // add matrices
1545 gsl_matrix_add( metric->gF_ij, metric_k->gF_ij );
1546 gsl_matrix_add( metric->gFav_ij, metric_k->gFav_ij );
1547 gsl_matrix_add( metric->m1_ij, metric_k->m1_ij );
1548 gsl_matrix_add( metric->m2_ij, metric_k->m2_ij );
1549 gsl_matrix_add( metric->m3_ij, metric_k->m3_ij );
1550 gsl_matrix_add( metric->Fisher_ab, metric_k->Fisher_ab );
1551
1552 // add errors in quadrature
1553 metric->maxrelerr = sqrt( SQUARE( metric->maxrelerr ) + SQUARE( metric_k->maxrelerr ) );
1554
1555 // add SNR^2
1556 metric->rho2 += metric_k->rho2;
1557
1559
1560 }
1561
1562 } // for k < Nseg
1563
1564 // semi-coherent metric: <g_ij> = (1/Nseg) sum_{k=1}^Nseg g_{k,ij}
1565 {
1566 const double scale = 1.0 / Nseg;
1567
1568 // scale matrices
1569 gsl_matrix_scale( metric->gF_ij, scale );
1570 gsl_matrix_scale( metric->gFav_ij, scale );
1571 gsl_matrix_scale( metric->m1_ij, scale );
1572 gsl_matrix_scale( metric->m2_ij, scale );
1573 gsl_matrix_scale( metric->m3_ij, scale );
1574 gsl_matrix_scale( metric->Fisher_ab, scale );
1575
1576 // scale errors
1577 metric->maxrelerr *= scale;
1578
1579 // scale SNR^2
1580 metric->rho2 *= scale;
1581 }
1582
1583 /* ----- if requested, project gF_ij and gFav_ij onto coordinate 'projectCoord' */
1584 if ( metricParams->projectCoord >= 0 ) {
1585 UINT4 projCoord = ( UINT4 )metricParams->projectCoord;
1586 if ( XLALProjectMetric( &metric->gF_ij, metric->gF_ij, projCoord ) != XLAL_SUCCESS ) {
1587 XLALPrintError( "%s: failed to project gF_ij onto coordinate '%d'. errno=%d\n", __func__, projCoord, xlalErrno );
1589 }
1590 if ( XLALProjectMetric( &metric->gFav_ij, metric->gFav_ij, projCoord ) != XLAL_SUCCESS ) {
1591 XLALPrintError( "%s: failed to project gFav_ij onto coordinate '%d'. errno=%d\n", __func__, projCoord, xlalErrno );
1593 }
1594 } /* if projectCoordinate >= 0 */
1595
1596 /* attach the metricParams struct as 'meta-info' to the output */
1597 metric->meta = ( *metricParams );
1598
1599 return metric;
1600
1601} /* XLALComputeDopplerFstatMetric() */
1602
1603
1604/** Free a DopplerFstatMetric structure */
1605void
1607{
1608 if ( !metric ) {
1609 return;
1610 }
1611
1612 gsl_matrix_free( metric->gF_ij );
1613 gsl_matrix_free( metric->gFav_ij );
1614 gsl_matrix_free( metric->m1_ij );
1615 gsl_matrix_free( metric->m2_ij );
1616 gsl_matrix_free( metric->m3_ij );
1617 gsl_matrix_free( metric->Fisher_ab );
1618
1619 XLALFree( metric );
1620
1621 return;
1622
1623} /* XLALDestroyDopplerFstatMetric() */
1624
1625
1626/**
1627 * Function to the compute the FmetricAtoms_t, from which the F-metric and Fisher-matrix can be computed.
1628 *
1629 * NOTE: if MultiNoiseFloor.length=0, unit noise weights are assumed.
1630 */
1632XLALComputeAtomsForFmetric( const DopplerMetricParams *metricParams, /**< input parameters determining the metric calculation */
1633 const EphemerisData *edat /**< ephemeris data */
1634 )
1635{
1636 FmetricAtoms_t *ret; /* return struct */
1637 intparams_t XLAL_INIT_DECL( intparams );
1638
1639 UINT4 dim, i = -1, j = -1, X; /* index counters */
1640 REAL8 A, B, C; /* antenna-pattern coefficients (gsl-integrated) */
1641
1642 const DopplerCoordinateSystem *coordSys;
1643
1644 REAL8 max_relerr = 0;
1645 REAL8 relerr_thresh = 1e-2; /* relatively tolerant integration-threshold */
1646
1647 /* ---------- sanity/consistency checks ---------- */
1648 if ( !metricParams || !edat ) {
1649 XLALPrintError( "\n%s: Illegal NULL pointer passed!\n\n", __func__ );
1651 }
1652 UINT4 numDet = metricParams->multiIFO.length;
1654 XLAL_CHECK_NULL( XLALSegListIsInitialized( &( metricParams->segmentList ) ), XLAL_EINVAL, "Passed un-initialzied segment list 'metricParams->segmentList'\n" );
1655 UINT4 Nseg = metricParams->segmentList.length;
1656 XLAL_CHECK_NULL( Nseg == 1, XLAL_EINVAL, "Segment list must only contain Nseg=1 segments, got Nseg=%d", Nseg );
1657
1658 BOOLEAN haveNoiseWeights = ( metricParams->multiNoiseFloor.length > 0 );
1659 XLAL_CHECK_NULL( !haveNoiseWeights || metricParams->multiNoiseFloor.length == numDet, XLAL_EINVAL );
1660
1661 LIGOTimeGPS *startTime = &( metricParams->segmentList.segs[0].start );
1662 LIGOTimeGPS *endTime = &( metricParams->segmentList.segs[0].end );
1663 REAL8 Tspan = XLALGPSDiff( endTime, startTime );
1664
1665 const LIGOTimeGPS *refTime = &( metricParams->signalParams.Doppler.refTime );
1666
1667 dim = metricParams->coordSys.dim; /* shorthand: number of Doppler dimensions */
1668 coordSys = &( metricParams->coordSys );
1669
1670 /* ----- create output structure ---------- */
1671 XLAL_CHECK_NULL( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) != NULL, XLAL_ENOMEM, "%s: XLALCalloc(1,%zu) failed.\n", __func__, sizeof( *ret ) );
1672 XLAL_CHECK_NULL( ( ret->a_a_i = gsl_vector_calloc( dim ) ) != NULL, XLAL_ENOMEM, "%s: a_a_i = gsl_vector_calloc (%d) failed.\n", __func__, dim );
1673 XLAL_CHECK_NULL( ( ret->a_b_i = gsl_vector_calloc( dim ) ) != NULL, XLAL_ENOMEM, "%s: a_b_i = gsl_vector_calloc (%d) failed.\n", __func__, dim );
1674 XLAL_CHECK_NULL( ( ret->b_b_i = gsl_vector_calloc( dim ) ) != NULL, XLAL_ENOMEM, "%s: b_b_i = gsl_vector_calloc (%d) failed.\n", __func__, dim );
1675 XLAL_CHECK_NULL( ( ret->a_a_i_j = gsl_matrix_calloc( dim, dim ) ) != NULL, XLAL_ENOMEM, "%s: a_a_i_j = gsl_matrix_calloc (%d,%d) failed.\n", __func__, dim, dim );
1676 XLAL_CHECK_NULL( ( ret->a_b_i_j = gsl_matrix_calloc( dim, dim ) ) != NULL, XLAL_ENOMEM, "%s: a_b_i_j = gsl_matrix_calloc (%d,%d) failed.\n", __func__, dim, dim );
1677 XLAL_CHECK_NULL( ( ret->b_b_i_j = gsl_matrix_calloc( dim, dim ) ) != NULL, XLAL_ENOMEM, "%s: b_b_i_j = gsl_matrix_calloc (%d,%d) failed.\n", __func__, dim, dim );
1678
1679 /* ---------- set up integration parameters ---------- */
1680 intparams.coordSys = coordSys;
1681 intparams.detMotionType = metricParams->detMotionType;
1682 intparams.dopplerPoint = &metricParams->signalParams.Doppler;
1683 intparams.startTime = XLALGPSGetREAL8( startTime );
1684 intparams.refTime = XLALGPSGetREAL8( refTime );
1685 intparams.Tspan = Tspan;
1686 intparams.edat = edat;
1687
1688 /* NOTE: this level of accuracy should be compatible with AM-coefficients involved
1689 * which are computed in REAL4 precision. We therefor cannot go lower than this it seems,
1690 * otherwise the gsl-integration fails to converge in some cases.
1691 */
1692 intparams.epsrel = 1e-4;
1693 intparams.epsabs = 0;
1694 /* NOTE: this numerical integration runs into problems when integrating over
1695 * several days (~O(5d)), as the integrands are oscillatory functions on order of ~1/4d
1696 * and convergence degrades.
1697 * As a solution, we split the integral into 'intN' units of 1/4 day duration, and compute
1698 * the final integral as a sum over partial integrals.
1699 */
1700 intparams.intT = 0.25 * LAL_DAYSID_SI;
1701
1702 /* if using 'global correlation' frequency variables, determine the highest spindown order: */
1703 UINT4 maxorder = findHighestGCSpinOrder( coordSys );
1704 if ( maxorder > 0 ) {
1705
1706 /* compute rOrb(t) derivatives at reference time */
1707 if ( ( intparams.rOrb_n = XLALComputeOrbitalDerivatives( maxorder, &intparams.dopplerPoint->refTime, edat ) ) == NULL ) {
1708 XLALPrintError( "%s: XLALComputeOrbitalDerivatives() failed.\n", __func__ );
1710 }
1711
1712 }
1713
1714 /* ----- integrate antenna-pattern coefficients A, B, C */
1715 REAL8 sum_weights = 0;
1716 A = B = C = 0;
1717 for ( X = 0; X < numDet; X ++ ) {
1718 REAL8 weight = haveNoiseWeights ? metricParams->multiNoiseFloor.sqrtSn[X] : 1.0;
1719 sum_weights += weight;
1720 REAL8 av, relerr;
1721 intparams.site = &( metricParams->multiIFO.sites[X] );
1722
1723 intparams.coord1 = -1;
1724 intparams.coord2 = -1;
1725
1726 /* A = < a^2 > (67)*/
1727 intparams.amcomp1 = AMCOMP_A;
1728 intparams.amcomp2 = AMCOMP_A;
1729 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1730 max_relerr = MYMAX( max_relerr, relerr );
1731 if ( xlalErrno ) {
1732 goto failed;
1733 }
1734 A += weight * av;
1735
1736 /* B = < b^2 > (67) */
1737 intparams.amcomp1 = AMCOMP_B;
1738 intparams.amcomp2 = AMCOMP_B;
1739 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1740 max_relerr = MYMAX( max_relerr, relerr );
1741 if ( xlalErrno ) {
1742 goto failed;
1743 }
1744 B += weight * av;
1745
1746 /* C = < a b > (67) */
1747 intparams.amcomp1 = AMCOMP_A;
1748 intparams.amcomp2 = AMCOMP_B;
1749 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1750 max_relerr = MYMAX( max_relerr, relerr );
1751 if ( xlalErrno ) {
1752 goto failed;
1753 }
1754 C += weight * av;
1755
1756 } /* for X < numDetectors */
1757
1758 REAL8 norm_weight = 1.0 / sum_weights;
1759
1760 A *= norm_weight;
1761 B *= norm_weight;
1762 C *= norm_weight;
1763
1764 ret->a_a = A;
1765 ret->b_b = B;
1766 ret->a_b = C;
1767
1768 /* ---------- compute components of the phase-metric ---------- */
1769 for ( i = 0; i < dim; i ++ ) {
1770 for ( j = 0; j <= i; j ++ ) {
1771 REAL8 a_a_i_j, b_b_i_j, a_b_i_j;
1772 REAL8 a_a_i, b_b_i, a_b_i;
1773
1774 a_a_i_j = b_b_i_j = a_b_i_j = 0;
1775 a_a_i = b_b_i = a_b_i = 0;
1776
1777 for ( X = 0; X < numDet; X ++ ) {
1778 REAL8 weight = haveNoiseWeights ? metricParams->multiNoiseFloor.sqrtSn[X] : 1.0;
1779 REAL8 av, relerr;
1780 intparams.site = &( metricParams->multiIFO.sites[X] );
1781
1782 /* ------------------------------ */
1783 intparams.coord1 = i;
1784 intparams.coord2 = j;
1785
1786 /* <a^2 Phi_i Phi_j> */
1787 intparams.amcomp1 = AMCOMP_A;
1788 intparams.amcomp2 = AMCOMP_A;
1789 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1790 max_relerr = MYMAX( max_relerr, relerr );
1791 if ( xlalErrno ) {
1792 goto failed;
1793 }
1794 a_a_i_j += weight * av;
1795
1796 /* <b^2 Phi_i Phi_j> */
1797 intparams.amcomp1 = AMCOMP_B;
1798 intparams.amcomp2 = AMCOMP_B;
1799 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1800 max_relerr = MYMAX( max_relerr, relerr );
1801 if ( xlalErrno ) {
1802 goto failed;
1803 }
1804 b_b_i_j += weight * av;
1805
1806 /* <a b Phi_i Phi_j> */
1807 intparams.amcomp1 = AMCOMP_A;
1808 intparams.amcomp2 = AMCOMP_B;
1809 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1810 max_relerr = MYMAX( max_relerr, relerr );
1811 if ( xlalErrno ) {
1812 goto failed;
1813 }
1814 a_b_i_j += weight * av;
1815
1816 /* ------------------------------ */
1817 intparams.coord1 = i;
1818 intparams.coord2 = -1;
1819
1820 /* <a^2 Phi_i> */
1821 intparams.amcomp1 = AMCOMP_A;
1822 intparams.amcomp2 = AMCOMP_A;
1823 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1824 max_relerr = MYMAX( max_relerr, relerr );
1825 if ( xlalErrno ) {
1826 goto failed;
1827 }
1828 a_a_i += weight * av;
1829
1830 /* <b^2 Phi_i> */
1831 intparams.amcomp1 = AMCOMP_B;
1832 intparams.amcomp2 = AMCOMP_B;
1833 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1834 max_relerr = MYMAX( max_relerr, relerr );
1835 if ( xlalErrno ) {
1836 goto failed;
1837 }
1838 b_b_i += weight * av;
1839
1840 /* <a b Phi_i> */
1841 intparams.amcomp1 = AMCOMP_A;
1842 intparams.amcomp2 = AMCOMP_B;
1843 av = XLALAverage_am1_am2_Phi_i_Phi_j( &intparams, &relerr );
1844 max_relerr = MYMAX( max_relerr, relerr );
1845 if ( xlalErrno ) {
1846 goto failed;
1847 }
1848 a_b_i += weight * av;
1849
1850 } /* for X < numDetectors */
1851
1852 gsl_vector_set( ret->a_a_i, i, a_a_i * norm_weight );
1853 gsl_vector_set( ret->a_b_i, i, a_b_i * norm_weight );
1854 gsl_vector_set( ret->b_b_i, i, b_b_i * norm_weight );
1855
1856 gsl_matrix_set( ret->a_a_i_j, i, j, a_a_i_j * norm_weight );
1857 gsl_matrix_set( ret->a_a_i_j, j, i, a_a_i_j * norm_weight );
1858
1859 gsl_matrix_set( ret->a_b_i_j, i, j, a_b_i_j * norm_weight );
1860 gsl_matrix_set( ret->a_b_i_j, j, i, a_b_i_j * norm_weight );
1861
1862 gsl_matrix_set( ret->b_b_i_j, i, j, b_b_i_j * norm_weight );
1863 gsl_matrix_set( ret->b_b_i_j, j, i, b_b_i_j * norm_weight );
1864
1865 } /* for j <= i */
1866
1867 } /* for i < dim */
1868
1869 /* return error-estimate */
1870 ret->maxrelerr = max_relerr;
1871
1872 /* free memory */
1873 XLALDestroyVect3Dlist( intparams.rOrb_n );
1874
1875 /* FIXME: should probably not be hardcoded */
1876 if ( max_relerr > relerr_thresh ) {
1877 XLALPrintError( "Maximal relative F-metric error too high: %.2e > %.2e\n", max_relerr, relerr_thresh );
1880 } else {
1881 XLALPrintInfo( "\nMaximal relative error in F-metric: %.2e\n", max_relerr );
1882 }
1883
1884 return ret;
1885
1886failed:
1888 XLALPrintError( "%s: XLALAverage_am1_am2_Phi_i_Phi_j() FAILED with errno = %d: am1 = %d, am2 = %d, coord1 = '%s', coord2 = '%s'\n",
1889 __func__, xlalErrno, intparams.amcomp1, intparams.amcomp2,
1890 GET_COORD_NAME( intparams.coordSys, intparams.coord1 ), GET_COORD_NAME( intparams.coordSys, intparams.coord2 )
1891 );
1893
1894} /* XLALComputeAtomsForFmetric() */
1895
1896
1897/**
1898 * Parse a detector-motion type string into the corresponding enum-number,
1899 */
1900int
1901XLALParseDetectorMotionString( const CHAR *detMotionString )
1902{
1903
1904 XLAL_CHECK( detMotionString, XLAL_EINVAL );
1905
1906 for ( int i = 0; DetectorMotionNames[i].type > 0; ++i ) {
1907 if ( strcmp( detMotionString, DetectorMotionNames[i].name ) != 0 ) {
1908 continue;
1909 }
1910 return DetectorMotionNames[i].type; /* found the right entry */
1911 }
1912
1913 XLAL_ERROR( XLAL_EINVAL, "Could not parse '%s' into a valid detector-motion type!", detMotionString );
1914
1915} /* XLALParseDetectorMotionString() */
1916
1917
1918/**
1919 * Provide a pointer to a static string containing the DopplerCoordinate-name
1920 * cooresponding to the enum DopplerCoordinateID
1921 */
1922const CHAR *
1924{
1925
1926 for ( int i = 0; DetectorMotionNames[i].type > 0; ++i ) {
1927 if ( DetectorMotionNames[i].type != detMotionType ) {
1928 continue;
1929 }
1930 return DetectorMotionNames[i].name; /* found the right entry */
1931 }
1932
1933 XLAL_ERROR_NULL( XLAL_EINVAL, "Could not parse '%d' into a valid detector-motion name!", detMotionType );
1934
1935} /* XLALDetectorMotionName() */
1936
1937
1938
1939/**
1940 * Parse a DopplerCoordinate-name into the corresponding DopplerCoordinateID
1941 */
1942int
1944{
1945 int i;
1946
1947 if ( !coordName ) {
1949 }
1950
1951 for ( i = 0; i < DOPPLERCOORD_LAST; i ++ ) {
1952 if ( DopplerCoordinates[i].name && strcmp( coordName, DopplerCoordinates[i].name ) ) {
1953 continue;
1954 }
1955 return i; /* found the right entry */
1956 }
1957
1958 XLALPrintError( "\nCould not parse '%s' into a valid coordinate-ID!\n\n", coordName );
1960
1961} /* XLALParseDopplerCoordinateString() */
1962
1963/**
1964 * Given a LALStringVector of coordinate-names, parse them into a
1965 * 'DopplerCoordinateSystem', namely a list of coordinate-IDs
1966 */
1967int
1968XLALDopplerCoordinateNames2System( DopplerCoordinateSystem *coordSys, /**< [out] pointer to coord-system struct */
1969 const LALStringVector *coordNames /**< [in] list of coordinate names */
1970 )
1971{
1972 UINT4 i;
1973
1974 if ( !coordSys || !coordNames ) {
1976 }
1977
1978 coordSys->dim = coordNames->length;
1979 for ( i = 0; i < coordNames->length; i++ ) {
1980 coordSys->coordIDs[i] = ( DopplerCoordinateID )XLALParseDopplerCoordinateString( coordNames->data[i] );
1981 if ( xlalErrno ) {
1983 }
1984 }
1985
1986 return XLAL_SUCCESS;
1987
1988} /* XLALDopplerCoordinateNames2System() */
1989
1990
1991
1992/**
1993 * Given a coordinate ID 'coordID', return its dimension within the given coordinate system 'coordSys',
1994 * or return -1 if 'coordID' is not found
1995 */
1997{
1998 for ( int i = 0; i < ( ( int )coordSys->dim ); ++i ) {
1999 if ( coordSys->coordIDs[i] == coordID ) {
2000 return i;
2001 }
2002 }
2003 return -1;
2004}
2005
2006
2007
2008/**
2009 * Provide a pointer to a static string containing the DopplerCoordinate-name
2010 * cooresponding to the enum DopplerCoordinateID
2011 */
2012const CHAR *
2014{
2015 if ( coordID >= DOPPLERCOORD_LAST ) {
2016 XLAL_ERROR_NULL( XLAL_EINVAL, "coordID '%d' outside valid range [0, %d]\n\n", coordID, DOPPLERCOORD_LAST - 1 );
2017 }
2018
2019 if ( !DopplerCoordinates[coordID].name ) {
2020 XLAL_ERROR_NULL( XLAL_EINVAL, "coordID '%d' has no associated name\n\n", coordID );
2021 }
2022
2023 return ( DopplerCoordinates[coordID].name );
2024
2025} /* XLALDopplerCoordinateName() */
2026
2027
2028/**
2029 * Provide a pointer to a static string containing the a descriptive
2030 * 'help-string' describing the coordinate DopplerCoordinateID
2031 */
2032const CHAR *
2034{
2035 if ( coordID >= DOPPLERCOORD_LAST ) {
2036 XLAL_ERROR_NULL( XLAL_EINVAL, "coordID '%d' outside valid range [0, %d]\n\n", coordID, DOPPLERCOORD_LAST - 1 );
2037 }
2038
2039 if ( !DopplerCoordinates[coordID].help ) {
2040 XLAL_ERROR_NULL( XLAL_EINVAL, "coordID '%d' has no associated help text\n\n", coordID );
2041 }
2042
2043 return ( DopplerCoordinates[coordID].help );
2044
2045} /* XLALDopplerCoordinateHelp() */
2046
2047/**
2048 * Return a string (allocated here) containing a full name - helpstring listing
2049 * for all doppler-coordinates DopplerCoordinateID allowed by UniversalDopplerMetric.c
2050 */
2051CHAR *
2053{
2054 CHAR *helpstr;
2055 const CHAR *name;
2056 const CHAR *help;
2057 UINT4 i, len, maxlen = 0;
2058 CHAR buf[512];
2059 CHAR fmt[512];
2060
2061#define HEADER "Doppler-coordinate names and explanations:\n--------------------------------------------------\n"
2062 if ( ( helpstr = XLALCalloc( strlen( HEADER ) + 1, sizeof( CHAR ) ) ) == NULL ) {
2064 }
2065 strcpy( helpstr, HEADER );
2066 len = strlen( helpstr );
2067
2068 /* get maximal field-length of coordinate names */
2069 for ( i = 0; i < DOPPLERCOORD_LAST; i ++ ) {
2070 if ( ( name = XLALDopplerCoordinateName( ( DopplerCoordinateID ) i ) ) == NULL ) {
2072 }
2073 maxlen = MYMAX( maxlen, strlen( name ) );
2074 sprintf( fmt, "%%-%ds: %%s\n", maxlen + 2 );
2075 }
2076
2077 /* assemble help-lines */
2078 for ( i = 0; i < DOPPLERCOORD_LAST; i ++ ) {
2079 if ( ( name = XLALDopplerCoordinateName( ( DopplerCoordinateID ) i ) ) == NULL ) {
2081 }
2082 if ( ( help = XLALDopplerCoordinateHelp( ( DopplerCoordinateID ) i ) ) == NULL ) {
2084 }
2085
2086 snprintf( buf, sizeof( buf ) - 1, fmt, name, help );
2087 len += strlen( buf ) + 1;
2088 if ( ( helpstr = XLALRealloc( helpstr, len ) ) == NULL ) {
2090 }
2091
2092 helpstr = strcat( helpstr, buf );
2093
2094 } /* for i < DOPPLERCOORD_LAST */
2095
2096 return ( helpstr );
2097
2098} /* XLALDopplerCoordinateHelpAll() */
2099
2100/**
2101 * Free a FmetricAtoms_t structure, allowing any pointers to be NULL
2102 */
2103void
2105{
2106 if ( !atoms ) {
2107 return;
2108 }
2109
2110 if ( atoms->a_a_i ) {
2111 gsl_vector_free( atoms->a_a_i );
2112 }
2113 if ( atoms->a_b_i ) {
2114 gsl_vector_free( atoms->a_b_i );
2115 }
2116 if ( atoms->b_b_i ) {
2117 gsl_vector_free( atoms->b_b_i );
2118 }
2119
2120 if ( atoms->a_a_i_j ) {
2121 gsl_matrix_free( atoms->a_a_i_j );
2122 }
2123 if ( atoms->a_b_i_j ) {
2124 gsl_matrix_free( atoms->a_b_i_j );
2125 }
2126 if ( atoms->b_b_i_j ) {
2127 gsl_matrix_free( atoms->b_b_i_j );
2128 }
2129
2130 XLALFree( atoms );
2131
2132 return;
2133
2134} /* XLALDestroyFmetricAtoms() */
2135
2136
2137/**
2138 * Compute the 'F-metric' gF_ij (and also gFav_ij, m1_ij, m2_ij, m3_ij)
2139 * from the given FmetricAtoms and the signal amplitude parameters.
2140 *
2141 */
2142static DopplerFstatMetric *
2144{
2145 DopplerFstatMetric *metric; /* output matrix */
2146
2147 UINT4 dim, i, j; /* Doppler index counters */
2148 REAL8 A, B, C, D; /* 'standard' antenna-pattern coefficients (gsl-integrated, though) */
2149 REAL8 alpha1, alpha2, alpha3, eta2, cos2psi, sin2psi;
2150
2151 if ( !atoms ) {
2152 XLALPrintError( "%s: illegal NULL input.\n\n", __func__ );
2154 }
2155
2156 if ( !atoms->a_a_i || !atoms->a_b_i || !atoms->b_b_i || !atoms->a_a_i_j || !atoms->a_b_i_j || !atoms->b_b_i_j ) {
2157 XLALPrintError( "%s: input Fmetric-atoms not fully allocated.\n\n", __func__ );
2159 }
2160
2161 dim = atoms->a_a_i->size;
2162
2163 /* allocate output metric structure */
2164 if ( ( metric = XLALCalloc( 1, sizeof( *metric ) ) ) == NULL ) {
2165 XLALPrintError( "%s: XLALCalloc ( 1, %zu) failed.\n\n", __func__, sizeof( *metric ) );
2167 }
2168 metric->gF_ij = gsl_matrix_calloc( dim, dim );
2169 metric->gFav_ij = gsl_matrix_calloc( dim, dim );
2170 metric->m1_ij = gsl_matrix_calloc( dim, dim );
2171 metric->m2_ij = gsl_matrix_calloc( dim, dim );
2172 metric->m3_ij = gsl_matrix_calloc( dim, dim );
2173
2174 if ( !metric->gF_ij || !metric->gFav_ij || !metric->m1_ij || !metric->m2_ij || !metric->m3_ij ) {
2175 XLALPrintError( "%s: failed to gsl_matrix_calloc(%d,%d) for gF_ij, gFav_ij, m1_ij, m2_ij, m3_ij\n\n", __func__, dim, dim );
2178 }
2179
2180 A = atoms->a_a;
2181 B = atoms->b_b;
2182 C = atoms->a_b;
2183
2184 D = A * B - C * C; /* determinant of [A, C; C, B] */
2185
2186 /* get amplitude-parameter factors alpha_1, alpha_2, alpha_3 */
2187 eta2 = SQUARE( cosi );
2188 cos2psi = cos( 2.0 * psi );
2189 sin2psi = sin( 2.0 * psi );
2190 alpha1 = 0.25 * SQUARE( 1.0 + eta2 ) * SQUARE( cos2psi ) + eta2 * SQUARE( sin2psi );
2191 alpha2 = 0.25 * SQUARE( 1.0 + eta2 ) * SQUARE( sin2psi ) + eta2 * SQUARE( cos2psi );
2192 alpha3 = 0.25 * SQUARE( 1.0 - eta2 ) * sin2psi * cos2psi;
2193
2194 metric->rho2 = alpha1 * A + alpha2 * B + 2.0 * alpha3 * C;
2195
2196 metric->maxrelerr = atoms->maxrelerr;
2197
2198 /* ---------- compute components of the metric ---------- */
2199 for ( i = 0; i < dim; i ++ ) {
2200 REAL8 a_a_i, b_b_i, a_b_i;
2201
2202 a_a_i = gsl_vector_get( atoms->a_a_i, i );
2203 a_b_i = gsl_vector_get( atoms->a_b_i, i );
2204 b_b_i = gsl_vector_get( atoms->b_b_i, i );
2205
2206 for ( j = 0; j <= i; j ++ ) {
2207 REAL8 a_a_i_j, b_b_i_j, a_b_i_j;
2208 REAL8 a_a_j, b_b_j, a_b_j;
2209
2210 REAL8 P1_ij, P2_ij, P3_ij; /* ingredients to m_r_ij */
2211 REAL8 Q1_ij, Q2_ij, Q3_ij; /* ingredients to m_r_ij */
2212 REAL8 gg;
2213
2214 a_a_j = gsl_vector_get( atoms->a_a_i, j );
2215 a_b_j = gsl_vector_get( atoms->a_b_i, j );
2216 b_b_j = gsl_vector_get( atoms->b_b_i, j );
2217
2218 a_a_i_j = gsl_matrix_get( atoms->a_a_i_j, i, j );
2219 a_b_i_j = gsl_matrix_get( atoms->a_b_i_j, i, j );
2220 b_b_i_j = gsl_matrix_get( atoms->b_b_i_j, i, j );
2221
2222 /* trivial assignments, see Eq.(76) in \cite Prix07 */
2223 P1_ij = a_a_i_j;
2224 P2_ij = b_b_i_j;
2225 P3_ij = a_b_i_j;
2226
2227 /* bit more involved, see Eq.(80)-(82) in \cite Prix07 [includes *explicit* index-symmetrization!!] */
2228 Q1_ij = A * a_b_i * a_b_j + B * a_a_i * a_a_j - C * ( a_a_i * a_b_j + a_a_j * a_b_i ); /* (80) symmetrized */
2229 Q1_ij /= D;
2230
2231 Q2_ij = A * b_b_i * b_b_j + B * a_b_i * a_b_j - C * ( a_b_i * b_b_j + a_b_j * b_b_i ); /* (81) symmetrized */
2232 Q2_ij /= D;
2233
2234 Q3_ij = 0.5 * A * ( a_b_i * b_b_j + a_b_j * b_b_i )
2235 + 0.5 * B * ( a_b_i * a_a_j + a_b_j * a_a_i )
2236 - 0.5 * C * ( b_b_i * a_a_j + b_b_j * a_a_i + 2.0 * a_b_i * a_b_j ); /* (83) symmetrized */
2237 Q3_ij /= D;
2238
2239 /* put the pieces together to compute m1_ij, m2_ij and m3_ij according to (85) */
2240 gg = P1_ij - Q1_ij;
2241 gsl_matrix_set( metric->m1_ij, i, j, gg );
2242 gsl_matrix_set( metric->m1_ij, j, i, gg );
2243
2244 gg = P2_ij - Q2_ij;
2245 gsl_matrix_set( metric->m2_ij, i, j, gg );
2246 gsl_matrix_set( metric->m2_ij, j, i, gg );
2247
2248 gg = P3_ij - Q3_ij;
2249 gsl_matrix_set( metric->m3_ij, i, j, gg );
2250 gsl_matrix_set( metric->m3_ij, j, i, gg );
2251
2252
2253 /* assemble the 'full' F-stat metric from these ingredients, see Eq.(87) */
2254 gg = alpha1 * gsl_matrix_get( metric->m1_ij, i, j ) + alpha2 * gsl_matrix_get( metric->m2_ij, i, j )
2255 + 2.0 * alpha3 * gsl_matrix_get( metric->m3_ij, i, j );
2256 gg /= metric->rho2;
2257
2258 gsl_matrix_set( metric->gF_ij, i, j, gg );
2259 gsl_matrix_set( metric->gF_ij, j, i, gg );
2260
2261 /* compute 'average' F-stat metric as given by Eq.(93) */
2262 gg = B * gsl_matrix_get( metric->m1_ij, i, j ) + A * gsl_matrix_get( metric->m2_ij, i, j )
2263 - 2.0 * C * gsl_matrix_get( metric->m3_ij, i, j );
2264 gg /= 2.0 * D;
2265
2266 gsl_matrix_set( metric->gFav_ij, i, j, gg );
2267 gsl_matrix_set( metric->gFav_ij, j, i, gg );
2268
2269 } /* for j <= i */
2270
2271 } /* for i < dim */
2272
2273 return metric;
2274
2275} /* XLALComputeFmetricFromAtoms() */
2276
2277
2278/**
2279 * Function to compute *full* 4+n dimensional Fisher matric for the
2280 * full CW parameter-space of Amplitude + Doppler parameters !
2281 */
2282static gsl_matrix *
2284{
2285 gsl_matrix *fisher = NULL; /* output matrix */
2286
2287 UINT4 dimDoppler, dimFull, i, j;
2288 REAL8 al1, al2, al3;
2289
2290 /* check input consistency */
2291 if ( !atoms ) {
2292 XLALPrintError( "%s: illegal NULL input.\n\n", __func__ );
2294 }
2295
2296 if ( !atoms->a_a_i || !atoms->a_b_i || !atoms->b_b_i || !atoms->a_a_i_j || !atoms->a_b_i_j || !atoms->b_b_i_j ) {
2297 XLALPrintError( "%s: input Fmetric-atoms not fully allocated.\n\n", __func__ );
2299 }
2300
2301 REAL8 A1, A2, A3, A4;
2302 {
2304 if ( XLALAmplitudeParams2Vect( Amu, Amp ) != XLAL_SUCCESS ) {
2305 XLALPrintError( "%s: XLALAmplitudeParams2Vect() failed with errno = %d\n\n", __func__, xlalErrno );
2307 }
2308
2309 A1 = Amu[0];
2310 A2 = Amu[1];
2311 A3 = Amu[2];
2312 A4 = Amu[3];
2313 }
2314
2315 dimDoppler = atoms->a_a_i->size;
2316 dimFull = 4 + dimDoppler; /* 4 amplitude params + n Doppler params */
2317
2318 if ( ( fisher = gsl_matrix_calloc( dimFull, dimFull ) ) == NULL ) {
2319 XLALPrintError( "%s: gsl_matric_calloc(%d,%d) failed.\n\n", __func__, dimFull, dimFull );
2321 }
2322
2323 /* ----- set pure Amplitude block 4x4: M_mu_nu ---------- */
2324 {
2325 REAL8 A, B, C;
2326 A = atoms->a_a;
2327 B = atoms->b_b;
2328 C = atoms->a_b;
2329
2330 gsl_matrix_set( fisher, 0, 0, A );
2331 gsl_matrix_set( fisher, 2, 2, A );
2332
2333 gsl_matrix_set( fisher, 1, 1, B );
2334 gsl_matrix_set( fisher, 3, 3, B );
2335
2336 gsl_matrix_set( fisher, 0, 1, C );
2337 gsl_matrix_set( fisher, 1, 0, C );
2338 gsl_matrix_set( fisher, 2, 3, C );
2339 gsl_matrix_set( fisher, 3, 2, C );
2340 } /* amplitude-param block M_mu_nu */
2341
2342
2343 /* ----- set Doppler block (4+i,4+j) ---------- */
2344 al1 = SQUARE( A1 ) + SQUARE( A3 );
2345 al2 = A1 * A2 + A3 * A4;
2346 al3 = SQUARE( A2 ) + SQUARE( A4 );
2347
2348 for ( i = 0; i < dimDoppler; i ++ ) {
2349 for ( j = 0; j <= i; j ++ ) {
2350 REAL8 gg, a_a_i_j, a_b_i_j, b_b_i_j;
2351
2352 a_a_i_j = gsl_matrix_get( atoms->a_a_i_j, i, j );
2353 a_b_i_j = gsl_matrix_get( atoms->a_b_i_j, i, j );
2354 b_b_i_j = gsl_matrix_get( atoms->b_b_i_j, i, j );
2355
2356 gg = al1 * a_a_i_j + 2.0 * al2 * a_b_i_j + al3 * b_b_i_j;
2357
2358 gsl_matrix_set( fisher, 4 + i, 4 + j, gg );
2359 gsl_matrix_set( fisher, 4 + j, 4 + i, gg );
2360
2361 } /* for j <= i */
2362 } /* for i < dimDoppler */
2363
2364
2365 /* ----- compute mixed Amplitude-Doppler block ( non-square ) */
2366 for ( i = 0; i < dimDoppler; i ++ ) {
2367 REAL8 a_a_i, a_b_i, b_b_i;
2368 REAL8 AR[4];
2369 UINT4 mu;
2370
2371 a_a_i = gsl_vector_get( atoms->a_a_i, i );
2372 a_b_i = gsl_vector_get( atoms->a_b_i, i );
2373 b_b_i = gsl_vector_get( atoms->b_b_i, i );
2374
2375 AR[0] = A3 * a_a_i + A4 * a_b_i;
2376 AR[1] = A3 * a_b_i + A4 * b_b_i;
2377 AR[2] = -A1 * a_a_i - A2 * a_b_i;
2378 AR[3] = -A1 * a_b_i - A2 * b_b_i;
2379
2380 for ( mu = 0; mu < 4; mu ++ ) {
2381 gsl_matrix_set( fisher, mu, 4 + i, AR[mu] );
2382 gsl_matrix_set( fisher, 4 + i, mu, AR[mu] );
2383 }
2384
2385 } /* for i < dimDoppler */
2386
2387
2388 return fisher;
2389
2390} /* XLALComputeFisherFromAtoms() */
2391
2392
2393/** Convert 3-D vector from equatorial into ecliptic coordinates */
2394void
2396{
2397 static mat33_t rotEqu2Ecl = { { 1.0, 0, 0 },
2398 { 0.0, LAL_COSIEARTH, LAL_SINIEARTH },
2399 { 0.0, -LAL_SINIEARTH, LAL_COSIEARTH }
2400 };
2401
2402 XLALmatrix33_in_vect3( out, rotEqu2Ecl, in );
2403
2404} /* XLALequatorialVect2ecliptic() */
2405
2406/** Convert 3-D vector from ecliptic into equatorial coordinates */
2407void
2409{
2410 static mat33_t rotEcl2Equ = { { 1.0, 0, 0 },
2411 { 0.0, LAL_COSIEARTH, -LAL_SINIEARTH },
2413 };
2414
2415 XLALmatrix33_in_vect3( out, rotEcl2Equ, in );
2416
2417} /* XLALeclipticVect2equatorial() */
2418
2419/** compute matrix product mat . vect */
2420void
2422{
2423
2424 UINT4 i, j;
2425 for ( i = 0; i < 3; i ++ ) {
2426 out[i] = 0;
2427 for ( j = 0; j < 3; j ++ ) {
2428 out[i] += mat[i][j] * in[j];
2429 }
2430 }
2431
2432} /* XLALmatrix33_in_vect3() */
2433
2434/**
2435 * Compute time-derivatives up to 'maxorder' of the Earths' orbital position vector
2436 * \f$ r_{\mathrm{orb}}(t) \f$ .
2437 *
2438 * Algorithm: using 5-point differentiation expressions on r_orb(t) returned from XLALBarycenterEarth().
2439 *
2440 * Returns a vector of derivatives \f$ \frac{d^n\,r_{\mathrm{orb}}}{d\,t^n} \f$ at the given
2441 * GPS time. Note, the return vector includes the zeroth-order derivative, so we return
2442 * (maxorder + 1) derivatives: n = 0 ... maxorder
2443 *
2444 */
2446XLALComputeOrbitalDerivatives( UINT4 maxorder, /**< [in] highest derivative-order to compute */
2447 const LIGOTimeGPS *tGPS, /**< [in] GPS time at which to compute the derivatives */
2448 const EphemerisData *edat /**< [in] ephemeris data */
2449 )
2450{
2451 EarthState earth;
2452 LIGOTimeGPS ti;
2453 REAL8 h = 0.5 * 86400.0; /* finite-differencing step-size for rOrb. Before CAREFUL before changing this! */
2454 vect3D_t r0m2h, r0mh, r0, r0_h, r0_2h;
2455 vect3Dlist_t *ret = NULL;
2456
2457 /* check input consistency */
2458 if ( maxorder > MAX_SPDNORDER ) {
2459 XLALPrintError( "%s: maxorder = %d too large, currently supports only up to maxorder = %d.\n", __func__, maxorder, MAX_SPDNORDER );
2461 }
2462
2463 if ( !tGPS ) {
2464 XLALPrintError( "%s: invalid NULL pointer received for 'tGPS'.\n", __func__ );
2466 }
2467 if ( !edat ) {
2468 XLALPrintError( "%s: invalid NULL pointer received for 'edat'.\n", __func__ );
2470 }
2471
2472
2473 /* ----- find Earth's position at the 5 points: t0 -2h, t0-h, t0, t0+h, t0 + 2h ----- */
2474
2475 /* t = t0 */
2476 ti = ( *tGPS );
2477 if ( XLALBarycenterEarth( &earth, &ti, edat ) != XLAL_SUCCESS ) {
2478 XLALPrintError( "%s: call to XLALBarycenterEarth() failed!\n\n", __func__ );
2480 }
2481 COPY_VECT( r0, earth.posNow );
2482
2483 /* t = t0 - h*/
2484 ti.gpsSeconds = ( *tGPS ).gpsSeconds - h;
2485 if ( XLALBarycenterEarth( &earth, &ti, edat ) != XLAL_SUCCESS ) {
2486 XLALPrintError( "%s: call to XLALBarycenterEarth() failed!\n\n", __func__ );
2488 }
2489 COPY_VECT( r0mh, earth.posNow );
2490
2491 /* t = t0 - 2h*/
2492 ti.gpsSeconds = ( *tGPS ).gpsSeconds - 2 * h;
2493 if ( XLALBarycenterEarth( &earth, &ti, edat ) != XLAL_SUCCESS ) {
2494 XLALPrintError( "%s: call to XLALBarycenterEarth() failed!\n\n", __func__ );
2496 }
2497 COPY_VECT( r0m2h, earth.posNow );
2498
2499 /* t = t0 + h*/
2500 ti.gpsSeconds = ( *tGPS ).gpsSeconds + h;
2501 if ( XLALBarycenterEarth( &earth, &ti, edat ) != XLAL_SUCCESS ) {
2502 XLALPrintError( "%s: call to XLALBarycenterEarth() failed!\n\n", __func__ );
2504 }
2505 COPY_VECT( r0_h, earth.posNow );
2506
2507 /* t = t0 + 2h*/
2508 ti.gpsSeconds = ( *tGPS ).gpsSeconds + 2 * h;
2509 if ( XLALBarycenterEarth( &earth, &ti, edat ) != XLAL_SUCCESS ) {
2510 XLALPrintError( "%s: call to XLALBarycenterEarth() failed!\n\n", __func__ );
2512 }
2513 COPY_VECT( r0_2h, earth.posNow );
2514
2515 /* use these 5 points to estimate derivatives */
2516 UINT4 i;
2517 vect3D_t rdn[MAX_SPDNORDER + 1];
2518 COPY_VECT( rdn[0], r0 ); // 0th order is imply r_orb(t0)
2519 for ( i = 0; i < 3; i ++ ) {
2520 rdn[1][i] = DERIV5P_1( r0m2h[i], r0mh[i], r0[i], r0_h[i], r0_2h[i], h );
2521 rdn[2][i] = DERIV5P_2( r0m2h[i], r0mh[i], r0[i], r0_h[i], r0_2h[i], h );
2522 rdn[3][i] = DERIV5P_3( r0m2h[i], r0mh[i], r0[i], r0_h[i], r0_2h[i], h );
2523 rdn[4][i] = DERIV5P_4( r0m2h[i], r0mh[i], r0[i], r0_h[i], r0_2h[i], h );
2524 } /* for i < 3 */
2525
2526 /* allocate return list */
2527 if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
2528 XLALPrintError( "%s: failed to XLALCalloc(1,%zu)\n", __func__, sizeof( *ret ) );
2530 }
2531 ret->length = maxorder + 1;
2532 if ( ( ret->data = XLALCalloc( ret->length, sizeof( *ret->data ) ) ) == NULL ) {
2533 XLALPrintError( "%s: failed to XLALCalloc(%d,%zu)\n", __func__, ret->length, sizeof( *ret->data ) );
2534 XLALFree( ret );
2536 }
2537
2538 UINT4 n;
2539 for ( n = 0; n <= maxorder; n ++ ) {
2540 COPY_VECT( ret->data[n], rdn[n] );
2541 }
2542
2543 return ret;
2544
2545} /* XLALComputeOrbitalDerivatives() */
2546
2547void
2549{
2550 if ( !list ) {
2551 return;
2552 }
2553
2554 if ( list->data ) {
2555 XLALFree( list->data );
2556 }
2557
2558 XLALFree( list );
2559
2560 return;
2561
2562} /* XLALDestroyVect3Dlist() */
2563
2564/**
2565 * Return the highest 'global-correlation' spindown order found in this coordinate system.
2566 * Counting nu0 = order1, nu1 = order2, nu2 = order3, ...,
2567 * order = 0 therefore means there are no GC spin coordinates at all
2568 */
2569static UINT4
2571{
2572
2573 UINT4 maxorder = 0;
2574 UINT4 i;
2575
2576 for ( i = 0; i < coordSys->dim; i ++ ) {
2577 UINT4 order = 0;
2578 if ( coordSys->coordIDs[i] == DOPPLERCOORD_GC_NU0 ) {
2579 order = 1;
2580 }
2581 if ( coordSys->coordIDs[i] == DOPPLERCOORD_GC_NU1 ) {
2582 order = 2;
2583 }
2584 if ( coordSys->coordIDs[i] == DOPPLERCOORD_GC_NU2 ) {
2585 order = 3;
2586 }
2587 if ( coordSys->coordIDs[i] == DOPPLERCOORD_GC_NU3 ) {
2588 order = 4;
2589 }
2590 if ( coordSys->coordIDs[i] == DOPPLERCOORD_GC_NU4 ) {
2591 order = 5;
2592 }
2593 maxorder = MYMAX( maxorder, order );
2594 }
2595
2596 return maxorder;
2597} /* findHighestSpinOrder() */
2598
2599/// @}
#define __func__
log an I/O error, i.e.
int j
int k
#define D(j)
UINT2 A
Definition: SFTnaming.c:46
UINT2 B
Definition: SFTnaming.c:47
#define fprintf
#define GET_COORD_SCALE(coordSys, coord)
#define COPY_VECT(dst, src)
copy 3 components of Euklidean vector
#define POW4(a)
#define MAX_SPDNORDER
#define DERIV5P_2(pm2, pm1, p0, pp1, pp2, h)
const double scale
multiplicative scaling factor of the coordinate
#define vOrb_c
#define DERIV5P_1(pm2, pm1, p0, pp1, pp2, h)
5-point derivative formulas (eg see http://math.fullerton.edu/mathews/articles/2003NumericalDiffFormu...
const DetectorMotionType type
#define DERIV5P_4(pm2, pm1, p0, pp1, pp2, h)
#define ZERO_VECT(v)
Operations on 3-dim vectors
#define MYMIN(a, b)
#define SUB_VECT(dst, src)
#define rOrb_c
#define POW5(a)
static const struct @10 DopplerCoordinates[DOPPLERCOORD_LAST]
Array of descriptor structs for each Doppler coordinate name.
static const struct @9 DetectorMotionNames[]
Array of symbolic 'names' for various detector-motions.
#define DOT_VECT(u, v)
Simple Euklidean scalar product for two 3-dim vectors in cartesian coords.
#define SCALE_R
#define RELERR(dx, x)
const char *const help
help string explaining the coordinate's meaning and units
#define EQU_VECT_TO_ECL(dst, src)
Convert 3-D vector from equatorial into ecliptic coordinates.
#define SQUARE(x)
#define HEADER
#define POW3(a)
#define DETMOTION_NAMES(orbit_type, spin_orbit_name, nospin_orbit_name)
const char *const name
coordinate name
#define ADD_VECT(dst, src)
#define MULT_VECT(v, lam)
AM_comp_t
components of antenna-pattern function: q_l = {a(t), b(t)}
@ AMCOMP_NONE
no antenna pattern function: (equivalent "a = 1")
@ AMCOMP_B
b(t)
@ AMCOMP_A
a(t)
#define GET_COORD_NAME(coordSys, coord)
#define GET_COORD_ID(coordSys, coord)
#define MYMAX(a, b)
#define SCALE_T
#define DERIV5P_3(pm2, pm1, p0, pp1, pp2, h)
#define XLAL_CALLGSL(statement)
double e
REAL8 coeff(qfvars *vars, REAL8 x)
Definition: cdfwchisq.c:620
void order(qfvars *vars)
Definition: cdfwchisq.c:56
const double vz
const LALDetector lalCachedDetectors[LAL_NUM_DETECTORS]
static const REAL8 LAL_FACT_INV[]
int XLALAmplitudeParams2Vect(PulsarAmplitudeVect A_Mu, const PulsarAmplitudeParams Amp)
Convert amplitude params from 'physical' coordinates into 'canonical' coordinates .
int XLALGetEarthTimes(const LIGOTimeGPS *tepoch, REAL8 *tMidnight, REAL8 *tAutumn)
This function takes a GPS time from tepoch and uses it to assign tAutumn and tMidnight,...
Definition: GetEarthTimes.c:76
int XLALBarycenterEarth(EarthState *earth, const LIGOTimeGPS *tGPS, const EphemerisData *edat)
Computes the position and orientation of the Earth, at some arrival time , specified LIGOTimeGPS inp...
Definition: LALBarycenter.c:78
int XLALBarycenter(EmissionTime *emit, const BarycenterInput *baryinput, const EarthState *earth)
Transforms from detector arrival time in GPS (as specified in the LIGOTimeGPS structure) to pulse em...
int XLALComputeAntennaPatternCoeffs(REAL8 *ai, REAL8 *bi, const SkyPosition *skypos, const LIGOTimeGPS *tGPS, const LALDetector *site, const EphemerisData *edat)
Compute single time-stamp antenna-pattern coefficients a(t), b(t) Note: this function uses REAL8 prec...
Definition: LALComputeAM.c:79
#define LAL_COSIEARTH
#define LAL_DAYSID_SI
#define LAL_PI
#define LAL_YRSID_SI
#define LAL_TWOPI
#define LAL_SINIEARTH
unsigned char BOOLEAN
double REAL8
#define XLAL_INIT_DECL(var,...)
char CHAR
uint32_t UINT4
#define lalDebugLevel
LALINFOBIT
LAL_LHO_4K_DETECTOR
void * XLALCalloc(size_t m, size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
void void int XLALfprintfGSLmatrix(FILE *fp, const char *fmt, const gsl_matrix *gij) _LAL_GCC_VPRINTF_FORMAT_(2)
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_DETAIL
int XLALChangeMetricReferenceTime(gsl_matrix **p_gpr_ij, gsl_matrix **p_transform, const gsl_matrix *g_ij, const DopplerCoordinateSystem *coordSys, const double Dtau)
Compute the transform which changes the metric reference time .
Definition: MetricUtils.c:578
int XLALProjectMetric(gsl_matrix **p_gpr_ij, const gsl_matrix *g_ij, const UINT4 c)
Calculate the projected metric onto the subspace orthogonal to coordinate-axis c, namely ,...
Definition: MetricUtils.c:182
int XLALCholeskyLDLTDecompMetric(gsl_matrix **p_cholesky, const gsl_matrix *g_ij)
Decompose a metric as , where is a lower-triangular matrix with unit diagonal, and is a diagonal ...
Definition: MetricUtils.c:231
int XLALInverseTransformMetric(gsl_matrix **p_gpr_ij, const gsl_matrix *transform, const gsl_matrix *g_ij)
Apply the inverse of a transform to a metric such that , or equivalently .
Definition: MetricUtils.c:341
double XLALMetricDeterminant(const gsl_matrix *g_ij)
Compute the determinant of a metric .
Definition: MetricUtils.c:98
REAL8 PulsarAmplitudeVect[4]
Struct for 'canonical' coordinates in amplitude-params space A^mu = {A1, A2, A3, A4}.
int XLALSegListInit(LALSegList *seglist)
int XLALSegListIsInitialized(const LALSegList *seglist)
COORDINATESYSTEM_EQUATORIAL
int XLALDetectorPosVel(PosVel3D_t *spin_posvel, PosVel3D_t *orbit_posvel, const LIGOTimeGPS *tGPS, const LALDetector *site, const EphemerisData *edat, DetectorMotionType detMotionType)
Given a GPS time and detector, return the current position (and velocity) of the detector.
static double XLALAverage_am1_am2_Phi_i_Phi_j(const intparams_t *params, double *relerr_max)
Integrate a general quadruple product CW_am1_am2_Phi_i_Phi_j() from 0 to 1.
int XLALDopplerCoordinateNames2System(DopplerCoordinateSystem *coordSys, const LALStringVector *coordNames)
Given a LALStringVector of coordinate-names, parse them into a 'DopplerCoordinateSystem',...
const CHAR * XLALDetectorMotionName(DetectorMotionType detMotionType)
Provide a pointer to a static string containing the DopplerCoordinate-name cooresponding to the enum ...
static double XLALCovariance_Phi_ij(const MultiLALDetector *multiIFO, const MultiNoiseFloor *multiNoiseFloor, const LALSegList *segList, const intparams_t *params, double *relerr_max)
Compute a pure phase-deriv covariance which gives a component of the "phase metric".
REAL8 vect3D_t[3]
3D vector
static UINT4 findHighestGCSpinOrder(const DopplerCoordinateSystem *coordSys)
Return the highest 'global-correlation' spindown order found in this coordinate system.
DopplerCoordinateID
enum listing symbolic 'names' for all Doppler Coordinates supported by the metric codes in FstatMetri...
CHAR * XLALDopplerCoordinateHelpAll(void)
Return a string (allocated here) containing a full name - helpstring listing for all doppler-coordina...
static gsl_matrix * XLALComputeFisherFromAtoms(const FmetricAtoms_t *atoms, PulsarAmplitudeParams Amp)
Function to compute full 4+n dimensional Fisher matric for the full CW parameter-space of Amplitude +...
static double CW_am1_am2_Phi_i_Phi_j(double tt, void *params)
For gsl-integration: general quadruple product between two antenna-pattern functions am1,...
void XLALDestroyFmetricAtoms(FmetricAtoms_t *atoms)
Free a FmetricAtoms_t structure, allowing any pointers to be NULL.
DetectorMotionType
Bitfield of different types of detector-motion to use in order to compute the Doppler-metric.
void XLALeclipticVect2equatorial(vect3D_t out, const vect3D_t in)
Convert 3-D vector from ecliptic into equatorial coordinates.
static DopplerFstatMetric * XLALComputeFmetricFromAtoms(const FmetricAtoms_t *atoms, REAL8 cosi, REAL8 psi)
Compute the 'F-metric' gF_ij (and also gFav_ij, m1_ij, m2_ij, m3_ij) from the given FmetricAtoms and ...
REAL8 XLALComputePhaseDerivative(REAL8 t, const PulsarDopplerParams *dopplerPoint, DopplerCoordinateID coordID, const EphemerisData *edat, const LALDetector *site, BOOLEAN includeRoemer)
FmetricAtoms_t * XLALComputeAtomsForFmetric(const DopplerMetricParams *metricParams, const EphemerisData *edat)
Function to the compute the FmetricAtoms_t, from which the F-metric and Fisher-matrix can be computed...
int XLALFindDopplerCoordinateInSystem(const DopplerCoordinateSystem *coordSys, const DopplerCoordinateID coordID)
Given a coordinate ID 'coordID', return its dimension within the given coordinate system 'coordSys',...
void XLALDestroyDopplerFstatMetric(DopplerFstatMetric *metric)
Free a DopplerFstatMetric structure.
const CHAR * XLALDopplerCoordinateHelp(DopplerCoordinateID coordID)
Provide a pointer to a static string containing the a descriptive 'help-string' describing the coordi...
static double CW_Phi_i(double tt, void *params)
Partial derivative of continuous-wave (CW) phase, with respect to Doppler coordinate 'i' := intparams...
void XLALmatrix33_in_vect3(vect3D_t out, mat33_t mat, const vect3D_t in)
compute matrix product mat .
void XLALDestroyDopplerPhaseMetric(DopplerPhaseMetric *metric)
Free a DopplerPhaseMetric structure.
REAL8 mat33_t[3][3]
3x3 matrix, useful for spatial 3D vector operations
const CHAR * XLALDopplerCoordinateName(DopplerCoordinateID coordID)
Provide a pointer to a static string containing the DopplerCoordinate-name cooresponding to the enum ...
void XLALequatorialVect2ecliptic(vect3D_t out, const vect3D_t in)
Convert 3-D vector from equatorial into ecliptic coordinates.
vect3Dlist_t * XLALComputeOrbitalDerivatives(UINT4 maxorder, const LIGOTimeGPS *tGPS, const EphemerisData *edat)
Compute time-derivatives up to 'maxorder' of the Earths' orbital position vector .
int XLALParseDetectorMotionString(const CHAR *detMotionString)
Parse a detector-motion type string into the corresponding enum-number,.
DopplerFstatMetric * XLALComputeDopplerFstatMetric(const DopplerMetricParams *metricParams, const EphemerisData *edat)
Calculate the general (single-segment coherent, or multi-segment semi-coherent) full (multi-IFO) Fsta...
#define POW2(a)
Function to compute the full F-statistic metric, including antenna-pattern functions from multi-detec...
int XLALPtolemaicPosVel(PosVel3D_t *posvel, const LIGOTimeGPS *tGPS)
Compute position and velocity assuming a purely "Ptolemaic" orbital motion (i.e.
void XLALDestroyVect3Dlist(vect3Dlist_t *list)
int XLALParseDopplerCoordinateString(const CHAR *coordName)
Parse a DopplerCoordinate-name into the corresponding DopplerCoordinateID.
DopplerPhaseMetric * XLALComputeDopplerPhaseMetric(const DopplerMetricParams *metricParams, const EphemerisData *edat)
Calculate an approximate "phase-metric" with the specified parameters.
@ DOPPLERCOORD_N3SX_EQU
X spin-component of unconstrained super-sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_N2X_ECL
X component of contrained sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_ETA
Lagrange parameter 'eta = ecc * sin(argp) of binary orbit (ELL1 model) [Units: none].
@ DOPPLERCOORD_N3X_ECL
X component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_KAPPA
Lagrange parameter 'kappa = ecc * cos(argp)', ('ecc' = eccentricity, 'argp' = argument of periapse) o...
@ DOPPLERCOORD_TASC
Time of ascension (neutron star crosses line of nodes moving away from observer) for binary orbit (EL...
@ DOPPLERCOORD_N3X_EQU
X component of unconstrained super-sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_N3OY_ECL
Y orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_ETAP
Rescaled (by asini) differential-coordinate 'detap = asini * deta' [Units: light seconds].
@ DOPPLERCOORD_KAPPAP
Rescaled (by asini) differential-coordinate 'dkappap = asini * dkappa' [Units: light seconds].
@ DOPPLERCOORD_ASINI
Projected semimajor axis of binary orbit in small-eccentricy limit (ELL1 model) [Units: light seconds...
@ DOPPLERCOORD_N3Z_EQU
Z component of unconstrained super-sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_GC_NU4
Global correlation fourth spindown [Units: Hz/s^4].
@ DOPPLERCOORD_F2DOT
Second spindown [Units: Hz/s^2].
@ DOPPLERCOORD_DASC
Distance traversed on the arc of binary orbit (ELL1 model) 'dasc = 2 * pi * (ap/porb) * tasc' [Units:...
@ DOPPLERCOORD_N2X_EQU
X component of contrained sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_DELTA
Declination [Units: radians].
@ DOPPLERCOORD_N2Y_ECL
Y component of contrained sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_LAST
@ DOPPLERCOORD_GC_NU1
Global correlation first spindown [Units: Hz/s].
@ DOPPLERCOORD_GC_NU0
Global correlation frequency [Units: Hz].
@ DOPPLERCOORD_N3OZ_ECL
Z orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_N3Y_EQU
Y component of unconstrained super-sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_F1DOT
First spindown [Units: Hz/s].
@ DOPPLERCOORD_N2Y_EQU
Y component of contrained sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_F4DOT
Fourth spindown [Units: Hz/s^4].
@ DOPPLERCOORD_GC_NU2
Global correlation second spindown [Units: Hz/s^2].
@ DOPPLERCOORD_GC_NU3
Global correlation third spindown [Units: Hz/s^3].
@ DOPPLERCOORD_ALPHA
Right ascension [Units: radians].
@ DOPPLERCOORD_NONE
No Doppler component.
@ DOPPLERCOORD_VP
Rescaled (by asini) differential-coordinate 'dvp = asini * dOMEGA', ('OMEGA' = 2 * pi/'porb') of bina...
@ DOPPLERCOORD_N3Y_ECL
Y component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_PORB
Period of binary orbit (ELL1 model) [Units: s].
@ DOPPLERCOORD_F3DOT
Third spindown [Units: Hz/s^3].
@ DOPPLERCOORD_N3OX_ECL
X orbit-component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_N3Z_ECL
Z component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ DOPPLERCOORD_N3SY_EQU
Y spin-component of unconstrained super-sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_FREQ
Frequency [Units: Hz].
@ DETMOTION_SPIN
Full spin motion.
@ DETMOTION_MASKSPIN
Mask for spin motion bits.
@ DETMOTION_PTOLEORBIT
Ptolemaic (circular) orbital motion.
@ DETMOTION_SPINXY
Ecliptic-X+Y components of spin motion only.
@ DETMOTION_MASKORBIT
Mask for orbital motion bits.
@ DETMOTION_SPINZ
Ecliptic-Z component of spin motion only.
@ DETMOTION_ORBIT
Ephemeris-based orbital motion.
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR_NULL(...)
#define xlalErrno
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_TRY(statement, errnum)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK_REAL8(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EMAXITER
XLAL_EDOM
XLAL_EINVAL
XLAL_EFAILED
LIGOTimeGPS * XLALGPSSetREAL8(LIGOTimeGPS *epoch, REAL8 t)
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
REAL8 XLALGPSGetREAL8(const LIGOTimeGPS *epoch)
REAL8 XLALGPSDiff(const LIGOTimeGPS *t1, const LIGOTimeGPS *t0)
list mu
n
out
list weights
Basic input structure to LALBarycenter.c.
type describing a Doppler coordinate system: lists the number of dimensions and the symbolic names of...
DopplerCoordinateID coordIDs[DOPPLERMETRIC_MAX_DIM]
coordinate 'names'
UINT4 dim
number of dimensions covered
Struct to hold the output of XLALComputeDopplerFstatMetric(), including meta-info on the number of di...
gsl_matrix * m3_ij
Fstat-metric sub components.
double maxrelerr
estimate for largest relative error in Fmetric component integrations
gsl_matrix * gFav_ij
'average' Fstat-metric
gsl_matrix * gF_ij
full F-statistic metric gF_ij, including antenna-pattern effects (see )
REAL8 rho2
signal SNR rho^2 = A^mu M_mu_nu A^nu
gsl_matrix * Fisher_ab
Full 4+n dimensional Fisher matrix, ie amplitude + Doppler space.
meta-info specifying a Doppler-metric
MultiLALDetector multiIFO
detectors to compute metric for
DetectorMotionType detMotionType
the type of detector-motion assumed: full spin+orbit, pure orbital, Ptole, ...
BOOLEAN approxPhase
use an approximate phase-model, neglecting Roemer delay in spindown coordinates
PulsarParams signalParams
parameter-space point to compute metric for (doppler + amplitudes)
INT4 projectCoord
project metric onto subspace orthogonal to this axis (-1 = none, 0 = 1st coordinate,...
LALSegList segmentList
segment list: Nseg segments of the form (startGPS endGPS numSFTs)
MultiNoiseFloor multiNoiseFloor
and associated per-detector noise-floors to be used for weighting.
DopplerCoordinateSystem coordSys
number of dimensions and coordinate-IDs of Doppler-metric
Struct to hold the output of XLALComputeDopplerPhaseMetric(), including meta-info on the number of di...
Basic output structure of LALBarycenterEarth.c.
REAL8 velNow[3]
dimensionless velocity of Earth's center at tgps, extrapolated from JPL DE405 ephemeris
REAL8 posNow[3]
Cartesian coords of Earth's center at tgps, extrapolated from JPL DE405 ephemeris; units= sec.
Basic output structure produced by LALBarycenter.c.
This structure contains all information about the center-of-mass positions of the Earth and Sun,...
Struct to hold the 'atoms', ie weighted phase-derivative averages like from which the F-metric is co...
double maxrelerr
estimate for largest relative error in metric component integrations
LIGOTimeGPS end
LIGOTimeGPS start
UINT4 length
LALSeg * segs
size_t arraySize
array of detectors definitions 'LALDetector'
UINT4 length
number of detectors
LALDetector sites[PULSAR_MAX_DETECTORS]
array of site information
array of detector-specific 'noise floors' (ie PSD values), assumed constant over the frequency-band o...
REAL8 sqrtSn[PULSAR_MAX_DETECTORS]
per-IFO sqrt(PSD) values , where
UINT4 length
number of detectors
Small Container to hold two 3D vectors: position and velocity.
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)
Type containing the 'Doppler-parameters' affecting the time-evolution of the phase.
REAL8 Delta
Sky position: DEC (latitude) in equatorial coords and radians.
LIGOTimeGPS refTime
Reference time of pulsar parameters (in SSB!)
PulsarAmplitudeParams Amp
'Amplitude-parameters': h0, cosi, phi0, psi
PulsarDopplerParams Doppler
'Phase-evolution parameters': {skypos, fkdot, orbital params }
REAL8 longitude
REAL8 latitude
CoordinateSystem system
parameters for metric-integration
const DopplerCoordinateSystem * coordSys
Doppler coordinate system in use.
REAL8 startTime
GPS start time of observation.
int coord
coordinate index of the component for single phase-derivative Phi_i compute
double intT
length of integration time segments for phase integrals
double epsabs
absolute error tolerance for GSL integration routines
const PulsarDopplerParams * dopplerPoint
Doppler params to compute metric for.
BOOLEAN approxPhase
use an approximate phase-model, neglecting Roemer delay in spindown coordinates (or orders >= 1)
DetectorMotionType detMotionType
which detector-motion to use in metric integration
double epsrel
relative error tolerance for GSL integration routines
vect3Dlist_t * rOrb_n
list of orbital-radius derivatives at refTime of order n = 0, 1, ...
const EphemerisData * edat
ephemeris data
int errnum
store XLAL error of any failures within integrator
const gsl_matrix * coordTransf
coordinate transform to apply to coordinate system
const LALDetector * site
detector site to compute metric for
REAL8 Tspan
length of observation time in seconds
REAL8 refTime
GPS reference time for pulsar parameters.
variable-length list of 3D vectors
vect3D_t * data
array of 3D vectors
UINT4 length
number of elements
enum @4 site