Loading [MathJax]/extensions/TeX/AMSmath.js
LALPulsar 7.1.1.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
UniversalDopplerMetricTest.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017 Arunava Mukherjee
3 * Copyright (C) 2015 Karl Wette
4 * Copyright (C) 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#include <math.h>
23#include <sys/times.h>
24
25#include <lal/LALMalloc.h>
26#include <lal/LALInitBarycenter.h>
27#include <lal/PulsarDataTypes.h>
28#include <lal/LALConstants.h>
29#include <lal/StringVector.h>
30#include <lal/LogPrintf.h>
31
32#include <lal/PtoleMetric.h>
33#include <lal/UniversalDopplerMetric.h>
34#include <lal/MetricUtils.h>
35
36#include <lal/GSLHelpers.h>
37
38/**
39 * \author Reinhard Prix
40 * \file
41 * \ingroup UniversalDopplerMetric_h
42 * \brief Tests for exported functions in UniversalDopplerMetric
43 *
44 */
45
46// ---------- defines --------------------
47
48// ---------- Macros --------------------
49
50// copy 3 components of Euklidean vector
51#define COPY_VECT(dst,src) do { (dst)[0] = (src)[0]; (dst)[1] = (src)[1]; (dst)[2] = (src)[2]; } while(0)
52// compute norm of Euklidean 3-vector
53#define NORM(v) ( sqrt ( (v)[0]*(v)[0] + (v)[1]*(v)[1] + (v)[2]*(v)[2] ) )
54// compute scalar division of Euklidean 3-vector by div
55#define DIV_VECT(dst,src,div) do { (dst)[0] = (src)[0]/(div); (dst)[1] = (src)[1]/(div); (dst)[2] = (src)[2]/(div); } while(0)
56#define SUB_VECT(dst,src) do { (dst)[0] -= (src)[0]; (dst)[1] -= (src)[1]; (dst)[2] -= (src)[2]; } while(0)
57#define MULT_VECT(v,lam) do{ (v)[0] *= (lam); (v)[1] *= (lam); (v)[2] *= (lam); } while(0)
58
59// ---------- global variables --------------------
60
61// ---------- local types --------------------
62
63typedef enum {
64 OLDMETRIC_TYPE_PHASE = 0, /**< compute phase metric only */
65 OLDMETRIC_TYPE_FSTAT = 1, /**< compute full F-metric only */
66 OLDMETRIC_TYPE_ALL = 2, /**< compute both F-metric and phase-metric */
69
70typedef struct tagOldDopplerMetric {
71 DopplerMetricParams meta; /**< "meta-info" describing/specifying the type of Doppler metric */
72
73 gsl_matrix *g_ij; /**< symmetric matrix holding the phase-metric, averaged over segments */
74 gsl_matrix *g_ij_seg; /**< the phase-metric for each segment, concatenated by column: [g_ij_1, g_ij_2, ...] */
75
76 gsl_matrix *gF_ij; /**< full F-statistic metric gF_ij, including antenna-pattern effects (see \cite Prix07) */
77 gsl_matrix *gFav_ij; /**< 'average' Fstat-metric */
78 gsl_matrix *m1_ij, *m2_ij, *m3_ij; /**< Fstat-metric sub components */
79
80 gsl_matrix *Fisher_ab; /**< Full 4+n dimensional Fisher matrix, ie amplitude + Doppler space */
81
82 double maxrelerr_gPh; /**< estimate for largest relative error in phase-metric component integrations */
83 double maxrelerr_gF; /**< estimate for largest relative error in Fmetric component integrations */
84
85 REAL8 rho2; /**< signal SNR rho^2 = A^mu M_mu_nu A^nu */
87
88// ---------- local prototypes
89static int test_XLALComputeOrbitalDerivatives( void );
90static int test_XLALComputeDopplerMetrics( void );
91
94int XLALAddOldDopplerMetric( OldDopplerMetric **metric1, const OldDopplerMetric *metric2 );
96
97// ---------- function definitions --------------------
98/**
99 * MAIN function: calls a number of unit-tests
100 */
101int main( void )
102{
103 INT4 ret;
104
106 XLAL_CHECK( ret == XLAL_SUCCESS, XLAL_EFUNC, "test_XLALComputeDopplerMetrics() failed with status = %d.\n", ret );
107
109 XLAL_CHECK( ret == XLAL_SUCCESS, XLAL_EFUNC, "test_XLALComputeOrbitalDerivatives() failed with status = %d.\n", ret );
110
111 /* check for memory leaks */
113
114 /* all tests passed */
115 return XLAL_SUCCESS;
116
117} /* main() */
118
119
120/**
121 * Unit test for metric functions XLALComputeDopplerPhaseMetric()
122 * and XLALComputeDopplerFstatMetric()
123 *
124 * Initially modelled afer testMetricCodes.py script:
125 * Check metric codes 'getMetric' 'FstatMetric' and 'FstatMetric_v2' by
126 * comparing them against each other.
127 * Given that they represent 3 very different implementations of
128 * metric calculations, this provides a very powerful consistency test
129 *
130 */
131static int
133{
134 int ret;
135 const REAL8 tolPh = 0.01; // 1% tolerance on phase metrics [taken from testMetricCodes.py]
136
137 // ----- load ephemeris
138 const char earthEphem[] = TEST_PKG_DATA_DIR "earth00-40-DE405.dat.gz";
139 const char sunEphem[] = TEST_PKG_DATA_DIR "sun00-40-DE405.dat.gz";
140 EphemerisData *edat = XLALInitBarycenter( earthEphem, sunEphem );
141 XLAL_CHECK( edat != NULL, XLAL_EFUNC, "XLALInitBarycenter('%s','%s') failed with xlalErrno = %d\n", earthEphem, sunEphem, xlalErrno );
142
143 // ----- set test-parameters ----------
144 const LIGOTimeGPS startTimeGPS = { 792576013, 0 };
145 const REAL8 Tseg = 60000;
146
147 const REAL8 Alpha = 1.0;
148 const REAL8 Delta = 0.5;
149 const REAL8 Freq = 100;
150 const REAL8 f1dot = 0;// -1e-8;
151
152 LALStringVector *detNames = XLALCreateStringVector( "H1", "L1", "V1", NULL );
153 LALStringVector *sqrtSX = XLALCreateStringVector( "1.0", "0.5", "1.5", NULL );
154
155 MultiLALDetector multiIFO;
156 XLAL_CHECK( XLALParseMultiLALDetector( &multiIFO, detNames ) == XLAL_SUCCESS, XLAL_EFUNC );
157 XLALDestroyStringVector( detNames );
158
159 MultiNoiseFloor multiNoiseFloor;
160 XLAL_CHECK( XLALParseMultiNoiseFloor( &multiNoiseFloor, sqrtSX, multiIFO.length ) == XLAL_SUCCESS, XLAL_EFUNC );
162
163 // prepare metric parameters for modern XLALComputeDopplerFstatMetric() and mid-old XLALOldDopplerFstatMetric()
165 //const PulsarAmplitudeParams Amp = { 0.03, -0.3, 0.5, 0.0 }; // h0, cosi, psi, phi0
166 const PulsarAmplitudeParams Amp = { 0.5, 0.0, 0.01635, -0.009 }; // psi, phi0, aPlus, aCross
167 const PulsarDopplerParams dop = {
168 .refTime = startTimeGPS,
169 .Alpha = Alpha,
170 .Delta = Delta,
171 .fkdot = { Freq, f1dot },
172 };
173
175 ret = XLALSegListInitSimpleSegments( &segList, startTimeGPS, 1, Tseg );
176 XLAL_CHECK( ret == XLAL_SUCCESS, XLAL_EFUNC, "XLALSegListInitSimpleSegments() failed with xlalErrno = %d\n", xlalErrno );
177
178 const DopplerMetricParams master_pars2 = {
179 .coordSys = coordSys,
180 .detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT,
181 .segmentList = segList,
182 .multiIFO = multiIFO,
183 .multiNoiseFloor = multiNoiseFloor,
184 .signalParams = { .Amp = Amp, .Doppler = dop },
185 .projectCoord = - 1, // -1==no projection
186 .approxPhase = 0,
187 };
188
189
190 // ========== BEGINNING OF TEST CALLS ==========
191
192
193 XLALPrintWarning( "\n---------- ROUND 1: ephemeris-based, single-IFO phase metrics ----------\n" );
194 {
195 OldDopplerMetric *metric1;
196 DopplerPhaseMetric *metric2P;
197 REAL8 diff_2_1;
198
199 DopplerMetricParams pars2 = master_pars2;
200
201 pars2.multiIFO.length = 1; // truncate to first detector
202 pars2.multiNoiseFloor.length = 1; // truncate to first detector
203
204 // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric()
205 XLAL_CHECK( ( metric1 = XLALOldDopplerFstatMetric( OLDMETRIC_TYPE_PHASE, &pars2, edat ) ) != NULL, XLAL_EFUNC );
206 // 2) compute metric using modern UniversalDopplerMetric module: (used in lalpulsar_FstatMetric_v2)
207 XLAL_CHECK( ( metric2P = XLALComputeDopplerPhaseMetric( &pars2, edat ) ) != NULL, XLAL_EFUNC );
208
209 // compare metrics against each other:
210 XLAL_CHECK( ( diff_2_1 = XLALCompareMetrics( metric2P->g_ij, metric1->g_ij ) ) < tolPh, XLAL_ETOL, "Error(g2,g1)= %g exceeds tolerance of %g\n", diff_2_1, tolPh );
211 XLALPrintWarning( "diff_2_1 = %e\n", diff_2_1 );
212
215 }
216
217
218 XLALPrintWarning( "\n---------- ROUND 2: Ptolemaic-based, single-IFO phase metrics ----------\n" );
219 {
220 OldDopplerMetric *metric1;
221 DopplerPhaseMetric *metric2P;
222 REAL8 diff_2_1;
223
224 DopplerMetricParams pars2 = master_pars2;
225
226 pars2.multiIFO.length = 1; // truncate to first detector
227 pars2.multiNoiseFloor.length = 1; // truncate to first detector
228
230
231 // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric()
232 XLAL_CHECK( ( metric1 = XLALOldDopplerFstatMetric( OLDMETRIC_TYPE_PHASE, &pars2, edat ) ) != NULL, XLAL_EFUNC );
233 // 2) compute metric using modern UniversalDopplerMetric module: (used in lalpulsar_FstatMetric_v2)
234 XLAL_CHECK( ( metric2P = XLALComputeDopplerPhaseMetric( &pars2, edat ) ) != NULL, XLAL_EFUNC );
235
236 // compare all 3 metrics against each other:
237 XLAL_CHECK( ( diff_2_1 = XLALCompareMetrics( metric2P->g_ij, metric1->g_ij ) ) < tolPh, XLAL_ETOL, "Error(g2,g1)= %g exceeds tolerance of %g\n", diff_2_1, tolPh );
238 XLALPrintWarning( "diff_2_1 = %e\n", diff_2_1 );
239
242 }
243
244
245 XLALPrintWarning( "\n---------- ROUND 3: ephemeris-based, multi-IFO F-stat metrics ----------\n" );
246 {
247 OldDopplerMetric *metric1;
248 DopplerFstatMetric *metric2F;
249 REAL8 diff_2_1;
250
251 DopplerMetricParams pars2 = master_pars2;
252
254 pars2.multiIFO = multiIFO; // 3 IFOs
255 pars2.multiNoiseFloor = multiNoiseFloor;// 3 IFOs
256
257 // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric()
258 XLAL_CHECK( ( metric1 = XLALOldDopplerFstatMetric( OLDMETRIC_TYPE_FSTAT, &pars2, edat ) ) != NULL, XLAL_EFUNC );
259 // 2) compute metric using modern UniversalDopplerMetric module: (used in lalpulsar_FstatMetric_v2)
260 XLAL_CHECK( ( metric2F = XLALComputeDopplerFstatMetric( &pars2, edat ) ) != NULL, XLAL_EFUNC );
261
262 // compare both metrics against each other:
263 XLAL_CHECK( ( diff_2_1 = XLALCompareMetrics( metric2F->gF_ij, metric1->gF_ij ) ) < tolPh, XLAL_ETOL, "Error(gF2,gF1)= %e exceeds tolerance of %e\n", diff_2_1, tolPh );
264 XLALPrintWarning( "gF: diff_2_1 = %e\n", diff_2_1 );
265 XLAL_CHECK( ( diff_2_1 = XLALCompareMetrics( metric2F->gFav_ij, metric1->gFav_ij ) ) < tolPh, XLAL_ETOL, "Error(gFav2,gFav1)= %e exceeds tolerance of %e\n", diff_2_1, tolPh );
266 XLALPrintWarning( "gFav: diff_2_1 = %e\n", diff_2_1 );
267
270 }
271
272
273 XLALPrintWarning( "\n---------- ROUND 4: compare analytic {f,f1dot,f2dot,f3dot} phase metric vs XLALComputeDopplerPhaseMetric() ----------\n" );
274 {
275 DopplerPhaseMetric *metric2P;
276 REAL8 diff_2_1;
277
278 DopplerMetricParams pars2 = master_pars2;
279
280 pars2.multiIFO.length = 1; // truncate to 1st detector
281 pars2.multiNoiseFloor.length = 1; // truncate to 1st detector
283 pars2.approxPhase = 1; // use same phase-approximation as in analytic solution to improve comparison
284
286 pars2.coordSys = coordSys2;
287 gsl_matrix *gN_ij;
288
289 // a) compute metric at refTime = startTime
290 pars2.signalParams.Doppler.refTime = startTimeGPS;
291 XLAL_CHECK( ( metric2P = XLALComputeDopplerPhaseMetric( &pars2, edat ) ) != NULL, XLAL_EFUNC );
292 gN_ij = NULL;
293 XLAL_CHECK( XLALNaturalizeMetric( &gN_ij, NULL, metric2P->g_ij, &pars2 ) == XLAL_SUCCESS, XLAL_EFUNC );
294
295 REAL8 gStart_ij[] = { 1.0 / 3, 2.0 / 3, 6.0 / 5, 32.0 / 15, \
296 2.0 / 3, 64.0 / 45, 8.0 / 3, 512.0 / 105, \
297 6.0 / 5, 8.0 / 3, 36.0 / 7, 48.0 / 5, \
298 32.0 / 15, 512.0 / 105, 48.0 / 5, 4096.0 / 225
299 };
300 const gsl_matrix_view gStart = gsl_matrix_view_array( gStart_ij, 4, 4 );
301
302 // compare natural-units metric against analytic solution
303 XLAL_CHECK( ( diff_2_1 = XLALCompareMetrics( gN_ij, &( gStart.matrix ) ) ) < tolPh, XLAL_ETOL,
304 "RefTime=StartTime: Error(g_ij,g_analytic)= %e exceeds tolerance of %e\n", diff_2_1, tolPh );
305 XLALPrintWarning( "Analytic (refTime=startTime): diff_2_1 = %e\n", diff_2_1 );
306
308 gsl_matrix_free( gN_ij );
309
310 // b) compute metric at refTime = midTime
311 pars2.signalParams.Doppler.refTime = startTimeGPS;
312 pars2.signalParams.Doppler.refTime.gpsSeconds += Tseg / 2;
313
314 XLAL_CHECK( ( metric2P = XLALComputeDopplerPhaseMetric( &pars2, edat ) ) != NULL, XLAL_EFUNC );
315 gN_ij = NULL;
316 XLAL_CHECK( XLALNaturalizeMetric( &gN_ij, NULL, metric2P->g_ij, &pars2 ) == XLAL_SUCCESS, XLAL_EFUNC );
317
318 REAL8 gMid_ij[] = { 1.0 / 3, 0, 1.0 / 5, 0, \
319 0, 4.0 / 45, 0, 8.0 / 105, \
320 1.0 / 5, 0, 1.0 / 7, 0, \
321 0, 8.0 / 105, 0, 16.0 / 225
322 };
323 const gsl_matrix_view gMid = gsl_matrix_view_array( gMid_ij, 4, 4 );
324
325 // compare natural-units metric against analytic solution
326 XLAL_CHECK( ( diff_2_1 = XLALCompareMetrics( gN_ij, &( gMid.matrix ) ) ) < tolPh, XLAL_ETOL,
327 "RefTime=MidTime: Error(g_ij,g_analytic)= %e exceeds tolerance of %e\n", diff_2_1, tolPh );
328 XLALPrintWarning( "Analytic (refTime=midTime): diff_2_1 = %e\n\n", diff_2_1 );
329
331 gsl_matrix_free( gN_ij );
332 }
333
334
335 XLALPrintWarning( "\n---------- ROUND 5: ephemeris-based, single-IFO, segment-averaged phase metrics ----------\n" );
336 {
337 OldDopplerMetric *metric1;
338 DopplerPhaseMetric *metric2P;
339 REAL8 diff_2_1;
340
341 DopplerMetricParams pars2 = master_pars2;
342
344 pars2.multiIFO.length = 1; // truncate to first detector
345 pars2.multiNoiseFloor.length = 1; // truncate to first detector
346 pars2.approxPhase = 1;
347
348 const UINT4 Nseg = 10;
349 LALSegList XLAL_INIT_DECL( NsegList );
350 ret = XLALSegListInitSimpleSegments( &NsegList, startTimeGPS, Nseg, Tseg );
351 XLAL_CHECK( ret == XLAL_SUCCESS, XLAL_EFUNC, "XLALSegListInitSimpleSegments() failed with xlalErrno = %d\n", xlalErrno );
352 pars2.segmentList = NsegList;
353
354 LALSegList XLAL_INIT_DECL( segList_k );
355 LALSeg segment_k;
356 XLALSegListInit( &segList_k ); // prepare single-segment list containing segment k
357 segList_k.arraySize = 1;
358 segList_k.length = 1;
359 segList_k.segs = &segment_k;
360
361 // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric()
362 metric1 = NULL;
363 for ( UINT4 k = 0; k < Nseg; ++k ) {
364 // setup 1-segment segment-list pointing k-th segment
365 DopplerMetricParams pars2_k = pars2;
366 pars2_k.segmentList = segList_k;
367 pars2_k.segmentList.segs[0] = pars2.segmentList.segs[k];
368 // XLALOldDopplerFstatMetric() does not agree numerically with UniversalDopplerMetric when using refTime != startTime
369 pars2_k.signalParams.Doppler.refTime = pars2_k.segmentList.segs[0].start;
370
371 OldDopplerMetric *metric1_k; // per-segment coherent metric
372 XLAL_CHECK( ( metric1_k = XLALOldDopplerFstatMetric( OLDMETRIC_TYPE_PHASE, &pars2_k, edat ) ) != NULL, XLAL_EFUNC );
373
374 // manually correct reference time of metric1_k->g_ij; see Prix, "Frequency metric for CW searches" (2014-08-17), p. 4
375 const double dt = XLALGPSDiff( &( pars2_k.signalParams.Doppler.refTime ), &( pars2.signalParams.Doppler.refTime ) );
376 const double gFF = gsl_matrix_get( metric1_k->g_ij, 0, 0 );
377 const double gFA = gsl_matrix_get( metric1_k->g_ij, 0, 1 );
378 const double gFD = gsl_matrix_get( metric1_k->g_ij, 0, 2 );
379 const double gFf = gsl_matrix_get( metric1_k->g_ij, 0, 3 );
380 const double gAf = gsl_matrix_get( metric1_k->g_ij, 1, 3 );
381 const double gDf = gsl_matrix_get( metric1_k->g_ij, 2, 3 );
382 const double gff = gsl_matrix_get( metric1_k->g_ij, 3, 3 );
383 gsl_matrix_set( metric1_k->g_ij, 0, 3, gFf + gFF * dt );
384 gsl_matrix_set( metric1_k->g_ij, 3, 0, gsl_matrix_get( metric1_k->g_ij, 0, 3 ) );
385 gsl_matrix_set( metric1_k->g_ij, 1, 3, gAf + gFA * dt );
386 gsl_matrix_set( metric1_k->g_ij, 3, 1, gsl_matrix_get( metric1_k->g_ij, 1, 3 ) );
387 gsl_matrix_set( metric1_k->g_ij, 2, 3, gDf + gFD * dt );
388 gsl_matrix_set( metric1_k->g_ij, 3, 2, gsl_matrix_get( metric1_k->g_ij, 2, 3 ) );
389 gsl_matrix_set( metric1_k->g_ij, 3, 3, gff + 2 * gFf * dt + gFF * dt * dt );
390
391 XLAL_CHECK( XLALAddOldDopplerMetric( &metric1, metric1_k ) == XLAL_SUCCESS, XLAL_EFUNC );
392 XLALDestroyOldDopplerMetric( metric1_k );
393 }
394 XLAL_CHECK( XLALScaleOldDopplerMetric( metric1, 1.0 / Nseg ) == XLAL_SUCCESS, XLAL_EFUNC );
395
396 // 2) compute metric using modern UniversalDopplerMetric module: (used in lalpulsar_FstatMetric_v2)
397 XLAL_CHECK( ( metric2P = XLALComputeDopplerPhaseMetric( &pars2, edat ) ) != NULL, XLAL_EFUNC );
398
399 GPMAT( metric1->g_ij, "%0.4e" );
400 GPMAT( metric2P->g_ij, "%0.4e" );
401
402 // compare both metrics against each other:
403 XLAL_CHECK( ( diff_2_1 = XLALCompareMetrics( metric2P->g_ij, metric1->g_ij ) ) < tolPh, XLAL_ETOL, "Error(g2,g1)= %g exceeds tolerance of %g\n", diff_2_1, tolPh );
404 XLALPrintWarning( "diff_2_1 = %e\n", diff_2_1 );
405
408
409 XLALSegListClear( &NsegList );
410 }
411
412
413 XLALPrintWarning( "\n---------- ROUND 6: directed binary orbital metric ----------\n" );
414 {
415 REAL8 Period = 68023.70496;
416 REAL8 Omega = LAL_TWOPI / Period;
417 REAL8 asini = 1.44;
418 REAL8 tAsc = 897753994;
419 REAL8 argp = 0;
420 LIGOTimeGPS tP;
421 XLALGPSSetREAL8( &tP, tAsc + argp / Omega );
422
423 const PulsarDopplerParams dopScoX1 = {
424 .refTime = startTimeGPS,
425 .Alpha = Alpha,
426 .Delta = Delta,
427 .fkdot = { Freq },
428 .asini = asini,
429 .period = Period,
430 .tp = tP
431 };
432 REAL8 TspanScoX1 = 20 * 19 * 3600; // 20xPorb for long-segment regime
433 LALSegList XLAL_INIT_DECL( segListScoX1 );
434 XLAL_CHECK( XLALSegListInitSimpleSegments( &segListScoX1, startTimeGPS, 1, TspanScoX1 ) == XLAL_SUCCESS, XLAL_EFUNC );
435 REAL8 tMid = XLALGPSGetREAL8( &startTimeGPS ) + 0.5 * TspanScoX1;
436 REAL8 DeltaMidAsc = tMid - tAsc;
438 DopplerMetricParams pars_ScoX1 = {
439 .coordSys = coordSysScoX1,
440 .detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT,
441 .segmentList = segListScoX1,
442 .multiIFO = multiIFO,
443 .multiNoiseFloor = multiNoiseFloor,
444 .signalParams = { .Amp = Amp, .Doppler = dopScoX1 },
445 .projectCoord = - 1, // -1==no projection
446 .approxPhase = 1,
447 };
448 pars_ScoX1.multiIFO.length = 1; // truncate to first detector
449 pars_ScoX1.multiNoiseFloor.length = 1; // truncate to first detector
450
451 // compute metric using modern UniversalDopplerMetric module: (used in lalpulsar_FstatMetric_v2)
452 DopplerPhaseMetric *metric_ScoX1;
453 XLAL_CHECK( ( metric_ScoX1 = XLALComputeDopplerPhaseMetric( &pars_ScoX1, edat ) ) != NULL, XLAL_EFUNC );
454
455 // compute analytic metric computed from Eq.(47) in Leaci,Prix PRD91, 102003 (2015):
456 gsl_matrix *g0_ij;
457 XLAL_CHECK( ( g0_ij = gsl_matrix_calloc( 6, 6 ) ) != NULL, XLAL_ENOMEM, "Failed to gsl_calloc a 6x6 matrix\n" );
458 gsl_matrix_set( g0_ij, 0, 0, pow( LAL_PI * TspanScoX1, 2 ) / 3.0 );
459 gsl_matrix_set( g0_ij, 1, 1, 2.0 * pow( LAL_PI * Freq, 2 ) );
460 gsl_matrix_set( g0_ij, 2, 2, 2.0 * pow( LAL_PI * Freq * asini * Omega, 2 ) );
461 gsl_matrix_set( g0_ij, 3, 3, 0.5 * pow( Omega, 4 ) * pow( Freq * asini, 2 ) * ( pow( TspanScoX1, 2 ) / 12.0 + pow( DeltaMidAsc, 2 ) ) );
462 REAL8 gPAsc = LAL_PI * pow( Freq * asini, 2 ) * pow( Omega, 3 ) * DeltaMidAsc;
463 gsl_matrix_set( g0_ij, 2, 3, gPAsc );
464 gsl_matrix_set( g0_ij, 3, 2, gPAsc );
465 gsl_matrix_set( g0_ij, 4, 4, 0.5 * pow( LAL_PI * Freq * asini, 2 ) );
466 gsl_matrix_set( g0_ij, 5, 5, 0.5 * pow( LAL_PI * Freq * asini, 2 ) );
467
468 GPMAT( metric_ScoX1->g_ij, "%0.4e" );
469 GPMAT( g0_ij, "%0.4e" );
470
471 // compare metrics against each other
472 REAL8 diff, tolScoX1 = 0.05;
473 XLAL_CHECK( ( diff = XLALCompareMetrics( metric_ScoX1->g_ij, g0_ij ) ) < tolScoX1, XLAL_ETOL, "Error(gNum,gAn)= %g exceeds tolerance of %g\n", diff, tolScoX1 );
474 XLALPrintWarning( "diff_Num_An = %e\n", diff );
475
476
477 XLALPrintWarning( "\n---------- ROUND 7: directed binary orbital metric -- comparison between 'old' and 'new' coords ----------\n" );
478 // ----- 2nd part of the test: compare ScoX1 metric in new coordinates against old one
479 DopplerMetricParams pars_ScoX1_newCoords = pars_ScoX1;
481 pars_ScoX1_newCoords.coordSys = coordSysScoX1_newCoords;
482
483 DopplerPhaseMetric *metric_ScoX1_newCoords;
484 XLAL_CHECK( ( metric_ScoX1_newCoords = XLALComputeDopplerPhaseMetric( &pars_ScoX1_newCoords, edat ) ) != NULL, XLAL_EFUNC );
485
486 // apply coordinate transformation
487 gsl_matrix *Trnf_ij; /* This is the matrix for co-ordinate transformation from old to new */
488 XLAL_CHECK( ( Trnf_ij = gsl_matrix_calloc( 6, 6 ) ) != NULL, XLAL_ENOMEM, "Failed to gsl_calloc a 6x6 matrix\n" );
489 gsl_matrix_set( Trnf_ij, 0, 0, 1.0 );
490 gsl_matrix_set( Trnf_ij, 1, 1, 1.0 );
491 gsl_matrix_set( Trnf_ij, 2, 2, asini * Omega );
492 gsl_matrix_set( Trnf_ij, 3, 3, -1.0 * asini * pow( Omega, 2 ) / ( 2 * LAL_PI ) );
493 gsl_matrix_set( Trnf_ij, 4, 4, asini );
494 gsl_matrix_set( Trnf_ij, 5, 5, asini );
495
496 XLAL_CHECK( XLALInverseTransformMetric( &metric_ScoX1->g_ij, Trnf_ij, metric_ScoX1->g_ij ) == XLAL_SUCCESS, XLAL_EFUNC );
497
498 // output metrics
499 GPMAT( metric_ScoX1->g_ij, "%0.4e" );
500 GPMAT( metric_ScoX1_newCoords->g_ij, "%0.4e" );
501
502 // compare metrics
503 REAL8 Coord_diff, tolCoordScoX1 = 1e-10; // should be purely numerical differences
504 XLAL_CHECK( ( Coord_diff = XLALCompareMetrics( metric_ScoX1_newCoords->g_ij, metric_ScoX1->g_ij ) ) < tolCoordScoX1, XLAL_ETOL, "Error(gNum,gAn)= %g exceeds tolerance of %g\n", Coord_diff, tolCoordScoX1 );
505 XLALPrintWarning( "rel diff old vs new coords = %e\n", Coord_diff );
506
507 // free memory
508 gsl_matrix_free( g0_ij );
509 XLALDestroyDopplerPhaseMetric( metric_ScoX1 );
510 XLALDestroyDopplerPhaseMetric( metric_ScoX1_newCoords );
511 XLALSegListClear( &segListScoX1 );
512 } // end: Round 6 + 7 (binary orbital metrics)
513
514
515 // ----- clean up memory
518
519 return XLAL_SUCCESS;
520
521} /* test_XLALComputeDopplerMetrics() */
522
523
524/**
525 * Unit test function for XLALComputeOrbitalDerivatives()
526 */
527static int
529{
530 // ----- load an example ephemeris, describing a pure cicular 2D
531 // orbit w period of one year
532 CHAR earthEphem[] = TEST_DATA_DIR "circularEphem.dat";
533 CHAR sunEphem[] = TEST_PKG_DATA_DIR "sun00-40-DE405.dat";
534
535 EphemerisData *edat = XLALInitBarycenter( earthEphem, sunEphem );
536 XLAL_CHECK( edat != NULL, XLAL_EFUNC, "XLALInitBarycenter('%s','%s') failed with xlalErrno = %d\n", earthEphem, sunEphem, xlalErrno );
537
538 /* Unit test for XLALComputeOrbitalDerivatives() */
539 // ----------------------------------------
540 // the tests consists in using a purely 2D circular orbit to
541 // compute the derivatives, so we can analytically check them!
542
543 // one line from the middle of cicularEphem.dat:
544 // 700244800 498.41220200278 24.31154155846971 0 -4.84039532365306e-06 9.923320107134072e-05 0 -1.975719726623028e-11 -9.63716218195963e-13 0
545
546 // we can use this to check derivatives '0-'2'
547 vect3Dlist_t *rOrb_n = NULL;
548 LIGOTimeGPS t0 = { 700244800, 0 };
549 vect3D_t r_0 = {498.41220200278, 24.31154155846971, 0 };
550 vect3D_t r_1 = {-4.84039532365306e-06, 9.923320107134072e-05, 0 };
551 vect3D_t r_2 = { -1.975719726623028e-11, -9.63716218195963e-13, 0 };
552 UINT4 maxorder = 4;
553
554 rOrb_n = XLALComputeOrbitalDerivatives( maxorder, &t0, edat );
555 XLAL_CHECK( rOrb_n != NULL, XLAL_EFUNC, "XLALComputeOrbitalDerivatives() failed with xlalErrno = %d!.\n", xlalErrno );
556
557 // ----- first check differences to known first derivatives 0 - 2:
558 vect3D_t diff;
559 REAL8 reldiff;
560 REAL8 reltol = 1e-6;
561 UINT4 i;
562
563 /* order = 0 */
564 for ( i = 0; i < 3; i++ ) {
565 diff[i] = r_0[i] - rOrb_n->data[0][i];
566 }
567 reldiff = sqrt( NORM( diff ) / NORM( r_0 ) );
568 XLAL_CHECK( reldiff <= reltol, XLAL_ETOL, "Relative error %g on 0th order r_0 exceeds tolerance of %g.\n", reldiff, reltol );
569
570 /* order = 1 */
571 for ( i = 0; i < 3; i++ ) {
572 diff[i] = r_1[i] - rOrb_n->data[1][i];
573 }
574 reldiff = sqrt( NORM( diff ) / NORM( r_0 ) );
575 XLAL_CHECK( reldiff <= reltol, XLAL_ETOL, "Relative error %g on 1st order r_1 exceeds tolerance of %g.\n", reldiff, reltol );
576
577 /* order = 1 */
578 for ( i = 0; i < 3; i++ ) {
579 diff[i] = r_2[i] - rOrb_n->data[2][i];
580 }
581 reldiff = sqrt( NORM( diff ) / NORM( r_0 ) );
582 XLAL_CHECK( reldiff <= reltol, XLAL_ETOL, "Relative error %g on 2n order r_2 exceeds tolerance of %g.\n", reldiff, reltol );
583
584 // ----- second check derivatives against known analytic results
585 REAL8 RorbC = LAL_AU_SI / LAL_C_SI;
587 vect3D_t nR, nV;
588 REAL8 norm;
589 vect3D_t rTest_n[maxorder + 1];
590
591 norm = NORM( r_0 );
592 DIV_VECT( nR, r_0, norm );
593 norm = NORM( r_1 );
594 DIV_VECT( nV, r_1, norm );
595
596 /* r_0 */
597 COPY_VECT( rTest_n[0], nR );
598 MULT_VECT( rTest_n[0], RorbC );
599 /* r_1 */
600 COPY_VECT( rTest_n[1], nV );
601 MULT_VECT( rTest_n[1], RorbC * Om );
602 /* r_2 */
603 COPY_VECT( rTest_n[2], nR );
604 MULT_VECT( rTest_n[2], -RorbC * Om * Om );
605 /* r_3 */
606 COPY_VECT( rTest_n[3], nV );
607 MULT_VECT( rTest_n[3], -RorbC * Om * Om * Om );
608 /* r_4 */
609 COPY_VECT( rTest_n[4], nR );
610 MULT_VECT( rTest_n[4], RorbC * Om * Om * Om * Om );
611
612
613 UINT4 n;
614 reltol = 1e-2; /* 1% error should be enough to enforce order 0-2 are ~1e-5 - 1e-8, order 3-4 are ~ 5e-3*/
615 XLALPrintInfo( "\nComparing Earth orbital derivatives:\n" );
616 for ( n = 0; n <= maxorder; n ++ ) {
617 for ( i = 0; i < 3; i++ ) {
618 diff[i] = rTest_n[n][i] - rOrb_n->data[n][i];
619 }
620 reldiff = sqrt( NORM( diff ) / NORM( rTest_n[n] ) );
621 XLALPrintInfo( "order %d: relative difference = %g\n", n, reldiff );
622 XLAL_CHECK( reldiff <= reltol, XLAL_ETOL,
623 "Relative error %g on r_%d exceeds tolerance of %g.\n"
624 "rd[%d] = {%g, %g, %g}, rTest[%d] = {%g, %g, %g}\n",
625 reldiff, n, reltol,
626 n, rOrb_n->data[n][0], rOrb_n->data[n][1], rOrb_n->data[n][2],
627 n, rTest_n[n][0], rTest_n[n][1], rTest_n[n][2] );
628 } /* for n <= maxorder */
629
630 /* free memory */
631 XLALDestroyVect3Dlist( rOrb_n );
633
634 return XLAL_SUCCESS;
635
636} /* test_XLALComputeOrbitalDerivatives() */
int k
void LALCheckMemoryLeaks(void)
const double scale
multiplicative scaling factor of the coordinate
#define DIV_VECT(dst, src, div)
#define COPY_VECT(dst, src)
OldDopplerMetric * XLALOldDopplerFstatMetric(const OldMetricType_t metricType, const DopplerMetricParams *metricParams, const EphemerisData *edat)
The only purpose of this function is to serve as a backwards-comparison check for XLALDopplerFstatMet...
int XLALScaleOldDopplerMetric(OldDopplerMetric *m, REAL8 scale)
Scale all (existing) matrices, error-estimates and 'rho2' by 'scale'.
static int test_XLALComputeDopplerMetrics(void)
Unit test for metric functions XLALComputeDopplerPhaseMetric() and XLALComputeDopplerFstatMetric()
static int test_XLALComputeOrbitalDerivatives(void)
Unit test function for XLALComputeOrbitalDerivatives()
int main(void)
MAIN function: calls a number of unit-tests.
int XLALAddOldDopplerMetric(OldDopplerMetric **metric1, const OldDopplerMetric *metric2)
Add 'metric2' to 'metric1', by adding the matrixes and 'rho2', and adding error-estimates in quadratu...
#define NORM(v)
void XLALDestroyOldDopplerMetric(OldDopplerMetric *metric)
Free a OldDopplerMetric structure.
#define MULT_VECT(v, lam)
@ OLDMETRIC_TYPE_PHASE
compute phase metric only
@ OLDMETRIC_TYPE_FSTAT
compute full F-metric only
@ OLDMETRIC_TYPE_ALL
compute both F-metric and phase-metric
double e
const double rho2
int XLALParseMultiLALDetector(MultiLALDetector *detInfo, const LALStringVector *detNames)
Parse string-vectors (typically input by user) of N detector-names for detectors ,...
int XLALParseMultiNoiseFloor(MultiNoiseFloor *multiNoiseFloor, const LALStringVector *sqrtSX, UINT4 numDetectors)
Parse string-vectors (typically input by user) of N detector noise-floors for detectors ,...
EphemerisData * XLALInitBarycenter(const CHAR *earthEphemerisFile, const CHAR *sunEphemerisFile)
XLAL interface to reading ephemeris files 'earth' and 'sun', and return ephemeris-data in old backwar...
void XLALDestroyEphemerisData(EphemerisData *edat)
Destructor for EphemerisData struct, NULL robust.
#define LAL_PI
#define LAL_YRSID_SI
#define LAL_TWOPI
double REAL8
#define XLAL_INIT_DECL(var,...)
char CHAR
uint32_t UINT4
int32_t INT4
REAL8 XLALCompareMetrics(const gsl_matrix *g1_ij, const gsl_matrix *g2_ij)
Flexible comparison function between two metrics and .
Definition: MetricUtils.c:52
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
int XLALNaturalizeMetric(gsl_matrix **p_gpr_ij, gsl_matrix **p_transform, const gsl_matrix *g_ij, const DopplerMetricParams *metricParams)
Return a metric in naturalized coordinates.
Definition: MetricUtils.c:456
static const INT4 m
int XLALSegListInit(LALSegList *seglist)
int XLALSegListClear(LALSegList *seglist)
int XLALSegListInitSimpleSegments(LALSegList *seglist, LIGOTimeGPS startTime, UINT4 Nseg, REAL8 Tseg)
void XLALDestroyStringVector(LALStringVector *vect)
LALStringVector * XLALCreateStringVector(const CHAR *str1,...)
REAL8 vect3D_t[3]
3D vector
void XLALDestroyDopplerFstatMetric(DopplerFstatMetric *metric)
Free a DopplerFstatMetric structure.
void XLALDestroyDopplerPhaseMetric(DopplerPhaseMetric *metric)
Free a DopplerPhaseMetric structure.
vect3Dlist_t * XLALComputeOrbitalDerivatives(UINT4 maxorder, const LIGOTimeGPS *tGPS, const EphemerisData *edat)
Compute time-derivatives up to 'maxorder' of the Earths' orbital position vector .
DopplerFstatMetric * XLALComputeDopplerFstatMetric(const DopplerMetricParams *metricParams, const EphemerisData *edat)
Calculate the general (single-segment coherent, or multi-segment semi-coherent) full (multi-IFO) Fsta...
void XLALDestroyVect3Dlist(vect3Dlist_t *list)
DopplerPhaseMetric * XLALComputeDopplerPhaseMetric(const DopplerMetricParams *metricParams, const EphemerisData *edat)
Calculate an approximate "phase-metric" with the specified parameters.
@ DOPPLERCOORD_ETA
Lagrange parameter 'eta = ecc * sin(argp) of binary orbit (ELL1 model) [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_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_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_DELTA
Declination [Units: radians].
@ DOPPLERCOORD_F1DOT
First spindown [Units: Hz/s].
@ DOPPLERCOORD_ALPHA
Right ascension [Units: radians].
@ DOPPLERCOORD_VP
Rescaled (by asini) differential-coordinate 'dvp = asini * dOMEGA', ('OMEGA' = 2 * pi/'porb') of bina...
@ DOPPLERCOORD_PORB
Period of binary orbit (ELL1 model) [Units: s].
@ DOPPLERCOORD_F3DOT
Third spindown [Units: Hz/s^3].
@ DOPPLERCOORD_FREQ
Frequency [Units: Hz].
@ DETMOTION_SPIN
Full spin motion.
@ DETMOTION_PTOLEORBIT
Ptolemaic (circular) orbital motion.
@ DETMOTION_ORBIT
Ephemeris-based orbital motion.
#define xlalErrno
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK(assertion,...)
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFUNC
XLAL_ETOL
LIGOTimeGPS * XLALGPSSetREAL8(LIGOTimeGPS *epoch, REAL8 t)
REAL8 XLALGPSGetREAL8(const LIGOTimeGPS *epoch)
REAL8 XLALGPSDiff(const LIGOTimeGPS *t1, const LIGOTimeGPS *t0)
def Omega(v, m1, m2, S1, S2, Ln)
n
OldMetricType_t
double t0
type describing a Doppler coordinate system: lists the number of dimensions and the symbolic names of...
Struct to hold the output of XLALComputeDopplerFstatMetric(), including meta-info on the number of di...
gsl_matrix * gFav_ij
'average' Fstat-metric
gsl_matrix * gF_ij
full F-statistic metric gF_ij, including antenna-pattern effects (see )
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)
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...
gsl_matrix * g_ij
symmetric matrix holding the phase-metric, averaged over segments
This structure contains all information about the center-of-mass positions of the Earth and Sun,...
LIGOTimeGPS start
LALSeg * segs
array of detectors definitions 'LALDetector'
UINT4 length
number of detectors
array of detector-specific 'noise floors' (ie PSD values), assumed constant over the frequency-band o...
UINT4 length
number of detectors
gsl_matrix * g_ij
symmetric matrix holding the phase-metric, averaged over segments
gsl_matrix * gFav_ij
'average' Fstat-metric
gsl_matrix * gF_ij
full F-statistic metric gF_ij, including antenna-pattern effects (see )
Type containing the JKS 'amplitude parameters' {h0, cosi, phi0, psi}.
Type containing the 'Doppler-parameters' affecting the time-evolution of the phase.
LIGOTimeGPS refTime
Reference time of pulsar parameters (in SSB!)
PulsarDopplerParams Doppler
'Phase-evolution parameters': {skypos, fkdot, orbital params }
variable-length list of 3D vectors
vect3D_t * data
array of 3D vectors