Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-3a66518
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
MetricUtils.c
Go to the documentation of this file.
1//
2// Copyright (C) 2011--2015 Reinhard Prix, Karl Wette
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with with program; see the file COPYING. If not, write to the
16// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17// MA 02110-1301 USA
18//
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <math.h>
23
24#include <gsl/gsl_math.h>
25#include <gsl/gsl_blas.h>
26#include <gsl/gsl_linalg.h>
27
28#include <lal/MetricUtils.h>
29#include <lal/XLALError.h>
30#include <lal/LogPrintf.h>
31#include <lal/Factorial.h>
32
33#include <lal/GSLHelpers.h>
34
35// Shortcuts for integer powers
36#define POW2(a) ( (a) * (a) )
37#define POW3(a) ( (a) * (a) * (a) )
38#define POW4(a) ( (a) * (a) * (a) * (a) )
39#define POW5(a) ( (a) * (a) * (a) * (a) * (a) )
40
41/// \addtogroup MetricUtils_h
42/// @{
43
44///
45/// Flexible comparison function between two metrics \f$ g^1_{ij} \f$ and \f$ g^2_{ij} \f$ .
46///
47/// Returns maximal relative deviation \f$ \max_{i,j} \delta g_{ij} \f$ , measured in terms of
48/// diagonal entries, i.e. \f$ \delta g_{ij} = ( g^1_{ij} - g^2_{ij} ) / \sqrt{ g^1_{ii} g^1_{jj} } \f$ .
49/// This should always be well-defined, as we deal with positive-definite square matrices.
50///
53 const gsl_matrix *g1_ij, ///< [in] Metric to compare \f$ g^1_{ij} \f$ .
54 const gsl_matrix *g2_ij ///< [in] Metric to compare \f$ g^2_{ij} \f$ .
55)
56{
57
58 // Check input
59 XLAL_CHECK_REAL8( g1_ij != NULL, XLAL_EFAULT );
60 XLAL_CHECK_REAL8( g2_ij != NULL, XLAL_EFAULT );
61 XLAL_CHECK_REAL8( g1_ij->size1 == g1_ij->size2, XLAL_ESIZE );
62 XLAL_CHECK_REAL8( g2_ij->size1 == g2_ij->size2, XLAL_ESIZE );
63 XLAL_CHECK_REAL8( g1_ij->size1 == g2_ij->size1, XLAL_ESIZE );
64
65 if ( lalDebugLevel & LALINFOBIT ) {
66 fprintf( stderr, "%s(): comparing this metric:", __func__ );
67 XLALfprintfGSLmatrix( stderr, "%.15e", g1_ij );
68 fprintf( stderr, "%s(): to this metric:", __func__ );
69 XLALfprintfGSLmatrix( stderr, "%.15e", g2_ij );
70 }
71
72 REAL8 errmax = 0;
73 UINT4 dim = g1_ij->size1;
74 for ( UINT4 i = 0; i < dim; i ++ ) {
75 for ( UINT4 j = 0; j < dim; j ++ ) {
76 REAL8 norm = sqrt( gsl_matrix_get( g1_ij, i, i ) * gsl_matrix_get( g1_ij, j, j ) );
77 REAL8 e1 = gsl_matrix_get( g1_ij, i, j ) / norm;
78 REAL8 e2 = gsl_matrix_get( g2_ij, i, j ) / norm;
79 REAL8 base;
80 if ( e2 == 0 ) {
81 base = 1;
82 } else {
83 base = e2;
84 }
85 REAL8 reldiff = fabs( e1 - e2 ) / base;
86
87 errmax = fmax( errmax, reldiff );
88 } // for j < dim
89 } // for i < dim
90
91 return errmax;
92
93} // XLALCompareMetrics()
94
95///
96/// Compute the determinant of a metric \f$ g_{ij} \f$ .
97///
99 const gsl_matrix *g_ij ///< [in] Parameter-space metric \f$ g_{ij} \f$
100)
101{
102
103 // Check input
104 XLAL_CHECK_REAL8( g_ij != NULL, XLAL_EFAULT );
105
106 const size_t n = g_ij->size1;
107
108 // Allocate memory
109 gsl_matrix *GAMAT_REAL8( LU_decomp, n, n );
110 gsl_permutation *GAPERM_REAL8( LU_perm, n );
111
112 // Compute LU decomposition
113 gsl_matrix_memcpy( LU_decomp, g_ij );
114 int LU_sign = 0;
115 XLAL_CHECK_REAL8( gsl_linalg_LU_decomp( LU_decomp, LU_perm, &LU_sign ) == 0, XLAL_EFAILED, "'g_ij' cannot be LU-decomposed" );
116
117 // Compute determinant
118 const double determinant = gsl_linalg_LU_det( LU_decomp, LU_sign );
119
120 // Cleanup
121 GFMAT( LU_decomp );
122 GFPERM( LU_perm );
123
124 return determinant;
125
126}
127
128///
129/// Compute the extent of the bounding box of the mismatch ellipse of a metric \f$ g_{ij} \f$ .
130///
132 const gsl_matrix *g_ij, ///< [in] Parameter-space metric \f$ g_{ij} \f$
133 const double max_mismatch ///< [in] Maximum prescribed mismatch
134)
135{
136
137 // Check input
138 XLAL_CHECK_NULL( g_ij != NULL, XLAL_EFAULT );
139 XLAL_CHECK_NULL( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
140
141 const size_t n = g_ij->size1;
142
143 // Allocate memory
144 gsl_matrix *GAMAT_NULL( LU_decomp, n, n );
145 gsl_permutation *GAPERM_NULL( LU_perm, n );
146 gsl_matrix *GAMAT_NULL( diag_norm, n, n );
147 gsl_matrix *GAMAT_NULL( inverse, n, n );
148 gsl_vector *GAVEC_NULL( bounding_box, n );
149
150 // Diagonally normalize metric
151 XLAL_CHECK_NULL( XLALDiagNormalizeMetric( &LU_decomp, &diag_norm, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC );
152
153 // Compute metric inverse
154 int LU_sign = 0;
155 XLAL_CHECK_NULL( gsl_linalg_LU_decomp( LU_decomp, LU_perm, &LU_sign ) == 0, XLAL_EFAILED, "'g_ij' cannot be LU-decomposed" );
156 XLAL_CHECK_NULL( gsl_linalg_LU_invert( LU_decomp, LU_perm, inverse ) == 0, XLAL_EFAILED, "'g_ij' cannot be inverted" );
157
158 // Compute bounding box, and invert diagonal normalization
159 for ( size_t i = 0; i < n; ++i ) {
160 const double diag_norm_i = gsl_matrix_get( diag_norm, i, i );
161 const double bounding_box_i = 2.0 * sqrt( max_mismatch * gsl_matrix_get( inverse, i, i ) ) * diag_norm_i;
162 gsl_vector_set( bounding_box, i, bounding_box_i );
163 }
164
165 // Cleanup
166 GFMAT( LU_decomp, diag_norm, inverse );
167 GFPERM( LU_perm );
168
169 return bounding_box;
170
171} // XLALMetricEllipseBoundingBox()
172
173///
174/// Calculate the projected metric onto the subspace orthogonal to coordinate-axis \c c, namely
175/// \f$ g^{\prime}_{ij} = g_{ij} - ( g_{ic} g_{jc} / g_{cc} ) \f$ , where \f$ c \f$ is the index of
176/// the projected coordinate.
177///
178/// \note \c *p_gpr_ij will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij may point to the same
179/// matrix.
180///
181int
183 gsl_matrix **p_gpr_ij, ///< [in,out] Pointer to projected matrix \f$ g^{\prime}_{ij} \f$
184 const gsl_matrix *g_ij, ///< [in] Matrix to project \f$ g_{ij} \f$
185 const UINT4 c ///< [in] Index of projected coordinate
186)
187{
188
189 // Check input
190 XLAL_CHECK( g_ij != NULL, XLAL_EFAULT );
191 XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
192 XLAL_CHECK( p_gpr_ij != NULL, XLAL_EFAULT );
193 if ( *p_gpr_ij != NULL ) {
194 XLAL_CHECK( ( *p_gpr_ij )->size1 == ( *p_gpr_ij )->size2, XLAL_ESIZE );
195 XLAL_CHECK( ( *p_gpr_ij )->size1 == g_ij->size1, XLAL_ESIZE );
196 } else {
197 GAMAT( *p_gpr_ij, g_ij->size1, g_ij->size2 );
198 }
199 XLAL_CHECK( c < g_ij->size1, XLAL_EINVAL );
200
201 // Allocate temporary matrix
202 gsl_matrix *GAMAT( ret_ij, g_ij->size1, g_ij->size2 );
203
204 // Compute projected matrix
205 for ( UINT4 i = 0; i < g_ij->size1; i++ ) {
206 for ( UINT4 j = 0; j < g_ij->size2; j++ ) {
207 if ( i == c || j == c ) {
208 gsl_matrix_set( ret_ij, i, j, 0.0 );
209 } else {
210 double proj = gsl_matrix_get( g_ij, i, j ) - ( gsl_matrix_get( g_ij, i, c ) * gsl_matrix_get( g_ij, j, c ) / gsl_matrix_get( g_ij, c, c ) );
211 gsl_matrix_set( ret_ij, i, j, proj );
212 }
213 } /* for j < dim2 */
214
215 } /* for i < dim1 */
216 gsl_matrix_memcpy( *p_gpr_ij, ret_ij );
217
218 // Cleanup
219 GFMAT( ret_ij );
220
221 return XLAL_SUCCESS;
222
223} // XLALProjectMetric()
224
225///
226/// Decompose a metric \f$ \mathbf{G} \f$ as \f$ \mathbf{G} = \mathbf{L} \mathbf{D}
227/// \mathbf{L}^{\mathrm{T}} \f$ , where \f$ \mathbf{L} \f$ is a lower-triangular matrix
228/// with unit diagonal, and \f$ \mathbf{D} \f$ is a diagonal matrix. This decomposition
229/// may be useful if the metric cannot yet be guaranteed to be positive definite.
230///
232 gsl_matrix **p_cholesky, ///< [in,out] Pointer to decomposition; stores \f$ \mathbf{L} \f$ in lower triangular part \f$ \mathbf{D} \f$ on diagonal
233 const gsl_matrix *g_ij ///< [in] Matrix to decompose \f$ \mathbf{G} \f$
234)
235{
236
237
238 // Check input
239 XLAL_CHECK( g_ij != NULL, XLAL_EFAULT );
240 XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
241 XLAL_CHECK( p_cholesky != NULL, XLAL_EFAULT );
242 if ( *p_cholesky != NULL ) {
243 XLAL_CHECK( ( *p_cholesky )->size1 == g_ij->size1, XLAL_ESIZE );
244 XLAL_CHECK( ( *p_cholesky )->size2 == g_ij->size2, XLAL_ESIZE );
245 } else {
246 GAMAT( *p_cholesky, g_ij->size1, g_ij->size2 );
247 }
248
249 // Straightforward implementation of Cholesky–Banachiewicz algorithm
250 gsl_matrix_set_zero( *p_cholesky );
251#define A(i,j) *gsl_matrix_const_ptr( g_ij, i, j )
252#define D(j) *gsl_matrix_ptr( *p_cholesky, j, j )
253#define L(i,j) *gsl_matrix_ptr( *p_cholesky, i, j )
254 for ( size_t i = 0; i < g_ij->size1; ++i ) {
255 for ( size_t j = 0; j <= i; ++j ) {
256 if ( i == j ) {
257 D( j ) = A( j, j );
258 for ( size_t k = 0; k < j; ++k ) {
259 D( j ) -= L( j, k ) * L( j, k ) * D( k );
260 }
261 } else {
262 L( i, j ) = A( i, j );
263 for ( size_t k = 0; k < j; ++k ) {
264 L( i, j ) -= L( i, k ) * L( j, k ) * D( k );
265 }
266 L( i, j ) /= D( j );
267 }
268 }
269 }
270#undef A
271#undef D
272#undef L
273
274 return XLAL_SUCCESS;
275
276}
277
278///
279/// Apply a transform \f$ \mathbf{A} = (a_{ij}) \f$ to a metric \f$ \mathbf{G} = (g_{ij}) \f$ such that
280/// \f$ \mathbf{G} \rightarrow \mathbf{G}^{\prime} = \mathbf{A}^{\mathrm{T}} \mathbf{G} \mathbf{A}
281/// \f$ , or equivalently \f$ g_{ij} \rightarrow g^{\prime}_{kl} = g_{ij} a_{ik} a_{jl} \f$ .
282///
283/// \note \c *p_gpr_ij will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij may point to the same
284/// matrix.
285///
287 gsl_matrix **p_gpr_ij, ///< [in,out] Pointer to transformed matrix \f$ \mathbf{G}^{\prime} \f$
288 const gsl_matrix *transform, ///< [in] Transform to apply \f$ \mathbf{A} \f$
289 const gsl_matrix *g_ij ///< [in] Matrix to transform \f$ \mathbf{G} \f$
290)
291{
292
293 // Check input
294 XLAL_CHECK( g_ij != NULL, XLAL_EFAULT );
295 XLAL_CHECK( transform != NULL, XLAL_EFAULT );
296 XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
297 XLAL_CHECK( g_ij->size2 == transform->size1, XLAL_ESIZE );
298 XLAL_CHECK( p_gpr_ij != NULL, XLAL_EFAULT );
299 if ( *p_gpr_ij != NULL ) {
300 XLAL_CHECK( ( *p_gpr_ij )->size1 == transform->size2, XLAL_ESIZE );
301 XLAL_CHECK( ( *p_gpr_ij )->size2 == transform->size2, XLAL_ESIZE );
302 } else {
303 GAMAT( *p_gpr_ij, transform->size2, transform->size2 );
304 }
305
306 // Allocate temporary matrix
307 gsl_matrix *tmp = gsl_matrix_alloc( g_ij->size1, transform->size2 );
308 XLAL_CHECK( tmp != NULL, XLAL_ENOMEM );
309
310 // Perform transform
311 gsl_blas_dgemm( CblasNoTrans, CblasNoTrans, 1.0, g_ij, transform, 0.0, tmp );
312 gsl_blas_dgemm( CblasTrans, CblasNoTrans, 1.0, transform, tmp, 0.0, *p_gpr_ij );
313
314 // Ensure transformed g_ij is exactly symmetric
315 for ( size_t i = 0; i < ( *p_gpr_ij )->size1; ++i ) {
316 for ( size_t j = i + 1; j < ( *p_gpr_ij )->size2; ++j ) {
317 const double gij = gsl_matrix_get( *p_gpr_ij, i, j );
318 const double gji = gsl_matrix_get( *p_gpr_ij, j, i );
319 const double g = 0.5 * ( gij + gji );
320 gsl_matrix_set( *p_gpr_ij, i, j, g );
321 gsl_matrix_set( *p_gpr_ij, j, i, g );
322 }
323 }
324
325 // Cleanup
326 gsl_matrix_free( tmp );
327
328 return XLAL_SUCCESS;
329
330} // XLALTransformMetric()
331
332///
333/// Apply the inverse of a transform \f$ \mathbf{A}^{-1} = \mathbf{B} = (b_{ij}) \f$ to a metric
334/// \f$ \mathbf{G} = (g_{ij}) \f$ such that \f$ \mathbf{G} \rightarrow \mathbf{G}^{\prime} =
335/// \mathbf{B}^{\mathrm{T}} \mathbf{G} \mathbf{B} \f$ , or equivalently \f$ g_{ij} \rightarrow
336/// g^{\prime}_{kl} = g_{ij} b_{ik} b_{jl} \f$ .
337///
338/// \note \c *p_gpr_ij will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij may point to the same
339/// matrix.
340///
342 gsl_matrix **p_gpr_ij, ///< [in,out] Pointer to transformed matrix \f$ \mathbf{G}^{\prime} \f$
343 const gsl_matrix *transform, ///< [in] Transform \f$ \mathbf{A} \f$ , the inverse of which to apply
344 const gsl_matrix *g_ij ///< [in] Matrix to transform \f$ \mathbf{G} \f$
345)
346{
347
348 // Check input
349 XLAL_CHECK( g_ij != NULL, XLAL_EFAULT );
350 XLAL_CHECK( transform != NULL, XLAL_EFAULT );
351 XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
352 XLAL_CHECK( g_ij->size2 == transform->size1, XLAL_ESIZE );
353 XLAL_CHECK( transform->size1 == transform->size2, XLAL_ESIZE );
354 XLAL_CHECK( p_gpr_ij != NULL, XLAL_EFAULT );
355
356 // Allocate memory
357 gsl_matrix *GAMAT( LU_decomp, transform->size1, transform->size2 );
358 gsl_permutation *GAPERM( LU_perm, transform->size1 );
359 gsl_matrix *GAMAT( inverse, transform->size1, transform->size2 );
360
361 // Compute inverse of transform
362 int LU_sign = 0;
363 gsl_matrix_memcpy( LU_decomp, transform );
364 XLAL_CHECK( gsl_linalg_LU_decomp( LU_decomp, LU_perm, &LU_sign ) == 0, XLAL_EFAILED, "'transform' cannot be LU-decomposed" );
365 XLAL_CHECK( gsl_linalg_LU_invert( LU_decomp, LU_perm, inverse ) == 0, XLAL_EFAILED, "'transform' cannot be inverted" );
366
367 // Apply transform
368 XLAL_CHECK( XLALTransformMetric( p_gpr_ij, inverse, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC );
369
370 // Cleanup
371 GFMAT( LU_decomp, inverse );
372 GFPERM( LU_perm );
373
374 return XLAL_SUCCESS;
375
376} // XLALInverseTransformMetric()
377
378///
379/// Diagonally-normalize a metric \f$ g_{ij} \f$ . <i>Diagonally-normalize</i> means normalize
380/// metric by its diagonal, namely apply the transformation \f$ g_{ij} \rightarrow g^{\prime}_{ij} =
381/// g_{ij} / \sqrt{g_{ii} g_{jj}} \f$ , resulting in a lower condition number and unit diagonal
382/// elements.
383///
384/// If \c p_transform is non-NULL, return the diagonal-normalization transform in \c *p_transform.
385/// If \c p_gpr_ij is non-NULL, apply the transform to the metric \c *p_gpr_ij.
386///
387/// \note \c *p_gpr_ij and \c *p_transform will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij
388/// may point to the same matrix.
389///
390int
392 gsl_matrix **p_gpr_ij, ///< [in,out,optional] Pointer to transformed matrix \f$ g^{\prime}_{ij} \f$
393 gsl_matrix **p_transform, ///< [in,out,optional] Pointer to diagonal-normalization transform
394 const gsl_matrix *g_ij ///< [in] Matrix to transform \f$ g_{ij} \f$
395)
396{
397
398 // Check input
399 XLAL_CHECK( g_ij != NULL, XLAL_EFAULT );
400 XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
401 if ( p_transform != NULL ) {
402 if ( *p_transform != NULL ) {
403 XLAL_CHECK( ( *p_transform )->size1 == g_ij->size1, XLAL_ESIZE );
404 XLAL_CHECK( ( *p_transform )->size2 == g_ij->size2, XLAL_ESIZE );
405 } else {
406 GAMAT( *p_transform, g_ij->size1, g_ij->size2 );
407 }
408 }
409
410 // Create diagonal normalization transform
411 gsl_matrix *GAMAT( transform, g_ij->size1, g_ij->size2 );
412 gsl_matrix_set_zero( transform );
413 for ( size_t i = 0; i < g_ij->size1; ++i ) {
414 const double gii = gsl_matrix_get( g_ij, i, i );
415 XLAL_CHECK( gii > 0, XLAL_EINVAL, "Diagonal normalization not defined for non-positive diagonal elements! g_ii(%zu,%zu) = %g\n", i, i, gii );
416 gsl_matrix_set( transform, i, i, 1.0 / sqrt( gii ) );
417 }
418
419 // Apply transform
420 if ( p_gpr_ij != NULL ) {
421 XLAL_CHECK( XLALTransformMetric( p_gpr_ij, transform, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC );
422 }
423
424 // Return transform
425 if ( p_transform != NULL ) {
426 gsl_matrix_memcpy( *p_transform, transform );
427 }
428
429 // Cleanup
430 GFMAT( transform );
431
432 return XLAL_SUCCESS;
433
434} // XLALDiagNormalizeMetric()
435
436///
437/// Return a metric in <i>naturalized</i> coordinates.
438/// Frequency coordinates of spindown order \f$ s \f$ are scaled by
439/// \f[ \frac{2\pi}{(s+1)!} \left(\frac{\overline{\Delta T}}{2}\right)^{s+1} \f]
440/// where \f$ \overline{\Delta T}\equiv\sum_{k}^{N} \Delta T_k \f$ is the average segment-length
441/// over all \f$ N \f$ segments.
442///
443/// Sky coordinates are scaled by Holgers' units, see Eq.(44) in PRD82,042002(2010),
444/// without the equatorial rotation in alpha:
445/// \f[ \frac{2\pi f R_{E} \cos(\delta_{D})}{c} \f]
446/// where \f$ f \f$ is the frequency and
447/// \f$ R_{E} \f$ the Earth radius, and \f$ \delta_{D} \f$ is the detectors latitude.
448///
449/// If \c p_transform is non-NULL, return the naturalization transform in \c *p_transform.
450/// If \c p_gpr_ij is non-NULL, apply the transform to the metric \c *p_gpr_ij.
451///
452/// \note \c *p_gpr_ij and \c *p_transform will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij
453/// may point to the same matrix.
454///
455int
457 gsl_matrix **p_gpr_ij, ///< [in,out,optional] Pointer to transformed matrix \f$ g^{\prime}_{ij} \f$
458 gsl_matrix **p_transform, ///< [in,out,optional] Pointer to naturalization transform
459 const gsl_matrix *g_ij, ///< [in] Matrix to transform \f$ g_{ij} \f$
460 const DopplerMetricParams *metricParams ///< [in] Input parameters used to calculate naturalization transform
461)
462{
463
464 // Check input
465 XLAL_CHECK( g_ij != NULL, XLAL_EFAULT );
466 XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
467 if ( p_transform != NULL ) {
468 if ( *p_transform != NULL ) {
469 XLAL_CHECK( ( *p_transform )->size1 == g_ij->size1, XLAL_ESIZE );
470 XLAL_CHECK( ( *p_transform )->size2 == g_ij->size2, XLAL_ESIZE );
471 } else {
472 GAMAT( *p_transform, g_ij->size1, g_ij->size2 );
473 }
474 }
475 XLAL_CHECK( metricParams != NULL, XLAL_EFAULT );
476
477 // Compute average segment length
478 XLAL_CHECK( XLALSegListIsInitialized( &( metricParams->segmentList ) ), XLAL_EINVAL, "Passed un-initialzied segment list 'metricParams->segmentList'\n" );
479 UINT4 Nseg = metricParams->segmentList.length;
480 REAL8 sumTseg = 0;
481 for ( UINT4 k = 0; k < Nseg; k ++ ) {
482 LIGOTimeGPS *startTime_k = &( metricParams->segmentList.segs[k].start );
483 LIGOTimeGPS *endTime_k = &( metricParams->segmentList.segs[k].end );
484 sumTseg += XLALGPSDiff( endTime_k, startTime_k );
485 }
486 REAL8 avgTseg = sumTseg / Nseg;
487
488 // Compute naturalization transform
489 gsl_matrix *GAMAT( transform, g_ij->size1, g_ij->size2 );
490 gsl_matrix_set_zero( transform );
491 for ( size_t i = 0; i < g_ij->size1; ++i ) {
492 const DopplerCoordinateID coordID = metricParams->coordSys.coordIDs[i];
493 const double Freq = metricParams->signalParams.Doppler.fkdot[0];
494 const double T = avgTseg;
495 double scale = 0;
496 switch ( coordID ) {
498 scale = 1;
499 break;
500
503 scale = LAL_TWOPI * LAL_FACT_INV[1] * ( 0.5 * T );
504 break;
505
508 scale = LAL_TWOPI * LAL_FACT_INV[2] * POW2( 0.5 * T );
509 break;
510
513 scale = LAL_TWOPI * LAL_FACT_INV[3] * POW3( 0.5 * T );
514 break;
515
518 scale = LAL_TWOPI * LAL_FACT_INV[4] * POW4( 0.5 * T );
519 break;
520
537 const REAL8 rEarth_c = ( LAL_REARTH_SI / LAL_C_SI );
538 REAL8 cosdD = cos( metricParams->multiIFO.sites[0].frDetector.vertexLatitudeRadians );
539 scale = LAL_TWOPI * Freq * rEarth_c * cosdD;
540 }
541 break;
542
543 default:
544 scale = 1;
545 break;
546 } // switch(coordID)
547 gsl_matrix_set( transform, i, i, 1.0 / scale );
548 }
549
550 // Apply transform
551 if ( p_gpr_ij != NULL ) {
552 XLAL_CHECK( XLALTransformMetric( p_gpr_ij, transform, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC );
553 }
554
555 // Return transform
556 if ( p_transform != NULL ) {
557 gsl_matrix_memcpy( *p_transform, transform );
558 }
559
560 // Cleanup
561 GFMAT( transform );
562
563 return XLAL_SUCCESS;
564
565} // XLALNaturalizeMetric()
566
567///
568/// Compute the transform which changes the metric reference time \f$ \tau_0 \rightarrow \tau_1 =
569/// \tau_0 + \Delta\tau \f$ .
570///
571/// If \c p_transform is non-NULL, return the reference-time transform in \c *p_transform.
572/// If \c p_gpr_ij is non-NULL, apply the transform to the metric \c *p_gpr_ij.
573///
574/// \note \c *p_gpr_ij and \c *p_transform will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij
575/// may point to the same matrix.
576///
577int
579 gsl_matrix **p_gpr_ij, ///< [in,out,optional] Pointer to transformed matrix \f$ g^{\prime}_{ij} \f$
580 gsl_matrix **p_transform, ///< [in,out,optional] Pointer to reference time transform
581 const gsl_matrix *g_ij, ///< [in] Matrix to transform \f$ g_{ij} \f$
582 const DopplerCoordinateSystem *coordSys, ///< [in] Coordinate system of metric
583 const double Dtau ///< [in] Difference between new and old reference times \f$ \Delta\tau \f$
584)
585{
586
587 // Check input
588 XLAL_CHECK( g_ij != NULL, XLAL_EFAULT );
589 XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE );
590 if ( p_transform != NULL ) {
591 if ( *p_transform != NULL ) {
592 XLAL_CHECK( ( *p_transform )->size1 == g_ij->size1, XLAL_ESIZE );
593 XLAL_CHECK( ( *p_transform )->size2 == g_ij->size2, XLAL_ESIZE );
594 } else {
595 GAMAT( *p_transform, g_ij->size1, g_ij->size2 );
596 }
597 }
598 XLAL_CHECK( coordSys != NULL, XLAL_EFAULT );
599 XLAL_CHECK( coordSys->dim == g_ij->size1, XLAL_ESIZE );
600 for ( size_t i = 0; i < coordSys->dim; ++i ) {
601 switch ( coordSys->coordIDs[i] ) {
606 XLAL_ERROR( XLAL_EINVAL, "GCT coordinates are not supported" );
607 default:
608 break;
609 }
610 }
611
612 // Compute transformation matrix for frequency-spindown coordinates
613 // from Prix: "Frequency metric for CW searches" (2014-08-17), p. 4
614 gsl_matrix *GAMAT( transform, g_ij->size1, g_ij->size2 );
615 gsl_matrix_set_identity( transform );
616 if ( Dtau != 0.0 ) {
617 for ( size_t i = 0; i < coordSys->dim; ++i ) {
618 const DopplerCoordinateID icoord = coordSys->coordIDs[i];
619 if ( DOPPLERCOORD_FREQ <= icoord && icoord <= DOPPLERCOORD_LASTFDOT ) {
620 const size_t ispinorder = icoord - DOPPLERCOORD_FREQ;
621
622 for ( size_t j = i + 1; j < coordSys->dim; ++j ) {
623 const DopplerCoordinateID jcoord = coordSys->coordIDs[j];
624 if ( DOPPLERCOORD_FREQ <= jcoord && jcoord <= DOPPLERCOORD_LASTFDOT ) {
625 const size_t jspinorder = jcoord - DOPPLERCOORD_FREQ;
626
627 if ( jspinorder > ispinorder ) {
628 const double tij = LAL_FACT_INV[jspinorder - ispinorder] * pow( -1 * Dtau, jspinorder - ispinorder );
629 gsl_matrix_set( transform, i, j, tij );
630 }
631
632 }
633 }
634
635 }
636 }
637 }
638
639 // Apply transform
640 if ( p_gpr_ij != NULL ) {
641 XLAL_CHECK( XLALTransformMetric( p_gpr_ij, transform, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC );
642 }
643
644 // Return transform
645 if ( p_transform != NULL ) {
646 gsl_matrix_memcpy( *p_transform, transform );
647 }
648
649 // Cleanup
650 GFMAT( transform );
651
652 return XLAL_SUCCESS;
653
654} // XLALPhaseMetricRefTimeTransform()
655
656/// @}
#define __func__
log an I/O error, i.e.
int j
int k
#define c
#define POW4(a)
Definition: MetricUtils.c:38
#define D(j)
#define L(i, j)
#define POW3(a)
Definition: MetricUtils.c:37
#define A(i, j)
#define POW2(a)
Definition: MetricUtils.c:36
#define fprintf
const double scale
multiplicative scaling factor of the coordinate
#define rEarth_c
static const REAL8 LAL_FACT_INV[]
#define LAL_TWOPI
double REAL8
uint32_t UINT4
#define lalDebugLevel
LALINFOBIT
void void int XLALfprintfGSLmatrix(FILE *fp, const char *fmt, const gsl_matrix *gij) _LAL_GCC_VPRINTF_FORMAT_(2)
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
REAL8 XLALCompareMetrics(const gsl_matrix *g1_ij, const gsl_matrix *g2_ij)
Flexible comparison function between two metrics and .
Definition: MetricUtils.c:52
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
int XLALDiagNormalizeMetric(gsl_matrix **p_gpr_ij, gsl_matrix **p_transform, const gsl_matrix *g_ij)
Diagonally-normalize a metric .
Definition: MetricUtils.c:391
double XLALMetricDeterminant(const gsl_matrix *g_ij)
Compute the determinant of a metric .
Definition: MetricUtils.c:98
int XLALTransformMetric(gsl_matrix **p_gpr_ij, const gsl_matrix *transform, const gsl_matrix *g_ij)
Apply a transform to a metric such that , or equivalently .
Definition: MetricUtils.c:286
gsl_vector * XLALMetricEllipseBoundingBox(const gsl_matrix *g_ij, const double max_mismatch)
Compute the extent of the bounding box of the mismatch ellipse of a metric .
Definition: MetricUtils.c:131
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
int XLALSegListIsInitialized(const LALSegList *seglist)
DopplerCoordinateID
enum listing symbolic 'names' for all Doppler Coordinates supported by the metric codes in FstatMetri...
@ 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_N3X_ECL
X component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ 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_N3Z_EQU
Z component of unconstrained super-sky position in equatorial coordinates [Units: none].
@ DOPPLERCOORD_LASTFDOT
@ DOPPLERCOORD_F2DOT
Second spindown [Units: Hz/s^2].
@ 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_GC_NU1
Global correlation first spindown [Units: Hz/s].
@ DOPPLERCOORD_GC_NU0
Global correlation frequency [Units: Hz].
@ 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_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_N3Y_ECL
Y component of unconstrained super-sky position in ecliptic coordinates [Units: none].
@ 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].
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_REAL8(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_ESIZE
XLAL_EINVAL
XLAL_EFAILED
REAL8 XLALGPSDiff(const LIGOTimeGPS *t1, const LIGOTimeGPS *t0)
T
n
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
meta-info specifying a Doppler-metric
MultiLALDetector multiIFO
detectors to compute metric for
PulsarParams signalParams
parameter-space point to compute metric for (doppler + amplitudes)
LALSegList segmentList
segment list: Nseg segments of the form (startGPS endGPS numSFTs)
DopplerCoordinateSystem coordSys
number of dimensions and coordinate-IDs of Doppler-metric
LALFrDetector frDetector
REAL8 vertexLatitudeRadians
LIGOTimeGPS end
LIGOTimeGPS start
UINT4 length
LALSeg * segs
LALDetector sites[PULSAR_MAX_DETECTORS]
array of site information
PulsarSpins fkdot
Intrinsic spins: [Freq, f1dot, f2dot, ... ] where fkdot = d^kFreq/dt^k.
PulsarDopplerParams Doppler
'Phase-evolution parameters': {skypos, fkdot, orbital params }