/// /// Calculate the projected metric onto the subspace orthogonal to coordinate-axis \c c, namely /// \f$ g^{\prime}_{ij} = g_{ij} - ( g_{ic} g_{jc} / g_{cc} ) \f$, where \f$c\f$ is the index of /// the projected coordinate. /// /// \note \c *p_gpr_ij will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij may point to the same /// matrix. /// int XLALProjectMetric( gsl_matrix **p_gpr_ij, ///< [in,out] Pointer to projected matrix \f$g^{\prime}_{ij}\f$ const gsl_matrix *g_ij, ///< [in] Matrix to project \f$g_{ij}\f$ const UINT4 c ///< [in] Index of projected coordinate ) { // Check input XLAL_CHECK( g_ij != NULL, XLAL_EFAULT ); XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE ); XLAL_CHECK( p_gpr_ij != NULL, XLAL_EFAULT ); if ( *p_gpr_ij != NULL ) { XLAL_CHECK( (*p_gpr_ij)->size1 == (*p_gpr_ij)->size2, XLAL_ESIZE ); XLAL_CHECK( (*p_gpr_ij)->size1 == g_ij->size1, XLAL_ESIZE ); } else { GAMAT( *p_gpr_ij, g_ij->size1, g_ij->size2 ); } XLAL_CHECK( c < g_ij->size1, XLAL_EINVAL ); // Allocate temporary matrix gsl_matrix *GAMAT( ret_ij, g_ij->size1, g_ij->size2 ); // Compute projected matrix for ( UINT4 i=0; i < g_ij->size1; i++) { for ( UINT4 j=0; j < g_ij->size2; j++ ) { if ( i==c || j==c ) { gsl_matrix_set ( ret_ij, i, j, 0.0 ); } else { 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)); gsl_matrix_set ( ret_ij, i, j, proj ); } } /* for j < dim2 */ } /* for i < dim1 */ gsl_matrix_memcpy( *p_gpr_ij, ret_ij ); // Cleanup GFMAT( ret_ij ); return XLAL_SUCCESS; } // XLALProjectMetric()
/// /// Diagonally-normalize a metric \f$ g_{ij} \f$. <i>Diagonally-normalize</i> means normalize /// metric by its diagonal, namely apply the transformation \f$ g_{ij} \rightarrow g^{\prime}_{ij} = /// g_{ij} / \sqrt{g_{ii} g_{jj}} \f$, resulting in a lower condition number and unit diagonal /// elements. /// /// If \c p_transform is non-NULL, return the diagonal-normalization transform in \c *p_transform. /// If \c p_gpr_ij is non-NULL, apply the transform to the metric \c *p_gpr_ij. /// /// \note \c *p_gpr_ij and \c *p_transform will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij /// may point to the same matrix. /// int XLALDiagNormalizeMetric( gsl_matrix **p_gpr_ij, ///< [in,out,optional] Pointer to transformed matrix \f$g^{\prime}_{ij}\f$ gsl_matrix **p_transform, ///< [in,out,optional] Pointer to diagonal-normalization transform const gsl_matrix *g_ij ///< [in] Matrix to transform \f$g_{ij}\f$ ) { // Check input XLAL_CHECK( g_ij != NULL, XLAL_EFAULT ); XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE ); if ( p_transform != NULL ) { if ( *p_transform != NULL ) { XLAL_CHECK( (*p_transform)->size1 == g_ij->size1, XLAL_ESIZE ); XLAL_CHECK( (*p_transform)->size2 == g_ij->size2, XLAL_ESIZE ); } else { GAMAT( *p_transform, g_ij->size1, g_ij->size2 ); } } // Create diagonal normalization transform gsl_matrix *GAMAT( transform, g_ij->size1, g_ij->size2 ); gsl_matrix_set_zero( transform ); for ( size_t i = 0; i < g_ij->size1; ++i ) { const double gii = gsl_matrix_get(g_ij, i, i); XLAL_CHECK( gii > 0, XLAL_EINVAL, "Diagonal normalization not defined for non-positive diagonal elements! g_ii(%zu,%zu) = %g\n", i, i, gii ); gsl_matrix_set( transform, i, i, 1.0 / sqrt( gii ) ); } // Apply transform if ( p_gpr_ij != NULL ) { XLAL_CHECK( XLALTransformMetric( p_gpr_ij, transform, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC ); } // Return transform if ( p_transform != NULL ) { gsl_matrix_memcpy( *p_transform, transform ); } // Cleanup GFMAT( transform ); return XLAL_SUCCESS; } // XLALDiagNormalizeMetric()
/// /// Apply the inverse of a transform \f$\mathbf{A}^{-1} = \mathbf{B} = (b_{ij})\f$ to a metric /// \f$\mathbf{G} = (g_{ij})\f$ such that \f$ \mathbf{G} \rightarrow \mathbf{G}^{\prime} = /// \mathbf{B}^{\mathrm{T}} \mathbf{G} \mathbf{B} \f$, or equivalently \f$ g_{ij} \rightarrow /// g^{\prime}_{kl} = g_{ij} b_{ik} b_{jl} \f$. /// /// \note \c *p_gpr_ij will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij may point to the same /// matrix. /// int XLALInverseTransformMetric( gsl_matrix **p_gpr_ij, ///< [in,out] Pointer to transformed matrix \f$\mathbf{G}^{\prime}\f$ const gsl_matrix *transform, ///< [in] Transform \f$\mathbf{A}\f$, the inverse of which to apply const gsl_matrix *g_ij ///< [in] Matrix to transform \f$\mathbf{G}\f$ ) { // Check input XLAL_CHECK( g_ij != NULL, XLAL_EFAULT ); XLAL_CHECK( transform != NULL, XLAL_EFAULT ); XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE ); XLAL_CHECK( g_ij->size2 == transform->size1, XLAL_ESIZE ); XLAL_CHECK( transform->size1 == transform->size2, XLAL_ESIZE ); XLAL_CHECK( p_gpr_ij != NULL, XLAL_EFAULT ); // Allocate memory gsl_matrix *GAMAT( LU_decomp, transform->size1, transform->size2 ); gsl_permutation *GAPERM( LU_perm, transform->size1 ); gsl_matrix *GAMAT( inverse, transform->size1, transform->size2 ); // Compute inverse of transform int LU_sign = 0; gsl_matrix_memcpy( LU_decomp, transform ); XLAL_CHECK( gsl_linalg_LU_decomp( LU_decomp, LU_perm, &LU_sign ) == 0, XLAL_EFAILED, "'transform' cannot be LU-decomposed" ); XLAL_CHECK( gsl_linalg_LU_invert( LU_decomp, LU_perm, inverse ) == 0, XLAL_EFAILED, "'transform' cannot be inverted" ); // Apply transform XLAL_CHECK( XLALTransformMetric( p_gpr_ij, inverse, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC ); // Cleanup GFMAT( LU_decomp, inverse ); GFPERM( LU_perm ); return XLAL_SUCCESS; } // XLALInverseTransformMetric()
/// /// Decompose a metric \f$\mathbf{G}\f$ as \f$ \mathbf{G} = \mathbf{L} \mathbf{D} /// \mathbf{L}^{\mathrm{T}} \f$, where \f$\mathbf{L}\f$ is a lower-triangular matrix /// with unit diagonal, and \f$\mathbf{D}\f$ is a diagonal matrix. This decomposition /// may be useful if the metric cannot yet be guaranteed to be positive definite. /// int XLALCholeskyLDLTDecompMetric( gsl_matrix **p_cholesky, ///< [in,out] Pointer to decomposition; stores \f$\mathbf{L}\f$ in lower triangular part \f$\mathbf{D}\f$ on diagonal const gsl_matrix *g_ij ///< [in] Matrix to decompose \f$\mathbf{G}\f$ ) { // Check input XLAL_CHECK( g_ij != NULL, XLAL_EFAULT ); XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE ); XLAL_CHECK( p_cholesky != NULL, XLAL_EFAULT ); if ( *p_cholesky != NULL ) { XLAL_CHECK( (*p_cholesky)->size1 == g_ij->size1, XLAL_ESIZE ); XLAL_CHECK( (*p_cholesky)->size2 == g_ij->size2, XLAL_ESIZE ); } else { GAMAT( *p_cholesky, g_ij->size1, g_ij->size2 ); } // Straightforward implementation of Cholesky–Banachiewicz algorithm gsl_matrix_set_zero( *p_cholesky ); #define A(i,j) *gsl_matrix_const_ptr( g_ij, i, j ) #define D(j) *gsl_matrix_ptr( *p_cholesky, j, j ) #define L(i,j) *gsl_matrix_ptr( *p_cholesky, i, j ) for ( size_t i = 0; i < g_ij->size1; ++i ) { for ( size_t j = 0; j <= i; ++j ) { if ( i == j ) { D(j) = A(j, j); for ( size_t k = 0; k < j; ++k ) { D(j) -= L(j, k) * L(j, k) * D(k); } } else { L(i, j) = A(i, j); for ( size_t k = 0; k < j; ++k ) { L(i, j) -= L(i, k) * L(j, k) * D(k); } L(i, j) /= D(j); } } } #undef A #undef D #undef L return XLAL_SUCCESS; }
/// /// Apply a transform \f$\mathbf{A} = (a_{ij})\f$ to a metric \f$\mathbf{G} = (g_{ij})\f$ such that /// \f$ \mathbf{G} \rightarrow \mathbf{G}^{\prime} = \mathbf{A}^{\mathrm{T}} \mathbf{G} \mathbf{A} /// \f$, or equivalently \f$ g_{ij} \rightarrow g^{\prime}_{kl} = g_{ij} a_{ik} a_{jl} \f$. /// /// \note \c *p_gpr_ij will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij may point to the same /// matrix. /// int XLALTransformMetric( gsl_matrix **p_gpr_ij, ///< [in,out] Pointer to transformed matrix \f$\mathbf{G}^{\prime}\f$ const gsl_matrix *transform, ///< [in] Transform to apply \f$\mathbf{A}\f$ const gsl_matrix *g_ij ///< [in] Matrix to transform \f$\mathbf{G}\f$ ) { // Check input XLAL_CHECK( g_ij != NULL, XLAL_EFAULT ); XLAL_CHECK( transform != NULL, XLAL_EFAULT ); XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE ); XLAL_CHECK( g_ij->size2 == transform->size1, XLAL_ESIZE ); XLAL_CHECK( p_gpr_ij != NULL, XLAL_EFAULT ); if ( *p_gpr_ij != NULL ) { XLAL_CHECK( (*p_gpr_ij)->size1 == transform->size2, XLAL_ESIZE ); XLAL_CHECK( (*p_gpr_ij)->size2 == transform->size2, XLAL_ESIZE ); } else { GAMAT( *p_gpr_ij, transform->size2, transform->size2 ); } // Allocate temporary matrix gsl_matrix *tmp = gsl_matrix_alloc( g_ij->size1, transform->size2 ); XLAL_CHECK( tmp != NULL, XLAL_ENOMEM ); // Perform transform gsl_blas_dgemm( CblasNoTrans, CblasNoTrans, 1.0, g_ij, transform, 0.0, tmp ); gsl_blas_dgemm( CblasTrans, CblasNoTrans, 1.0, transform, tmp, 0.0, *p_gpr_ij ); // Ensure transformed g_ij is exactly symmetric for( size_t i = 0; i < (*p_gpr_ij)->size1; ++i ) { for( size_t j = i + 1; j < (*p_gpr_ij)->size2; ++j ) { const double gij = gsl_matrix_get( *p_gpr_ij, i, j ); const double gji = gsl_matrix_get( *p_gpr_ij, j, i ); const double g = 0.5 * ( gij + gji ); gsl_matrix_set( *p_gpr_ij, i, j, g ); gsl_matrix_set( *p_gpr_ij, j, i, g ); } } // Cleanup gsl_matrix_free( tmp ); return XLAL_SUCCESS; } // XLALTransformMetric()
static int MismatchSquareTest( const char *lattice_name, const double freqband, const double f1dotband, const double f2dotband, const UINT8 total_ref, const double mism_hist_ref[MISM_HIST_BINS] ) { // Create lattice tiling LatticeTiling *tiling = XLALCreateLatticeTiling(3); XLAL_CHECK(tiling != NULL, XLAL_EFUNC); // Add bounds const double fndot[3] = {100, 0, 0}; const double fndotband[3] = {freqband, f1dotband, f2dotband}; for (size_t i = 0; i < 3; ++i) { printf("Bounds: f%zudot=%0.3g, f%zudotband=%0.3g\n", i, fndot[i], i, fndotband[i]); XLAL_CHECK(XLALSetLatticeTilingConstantBound(tiling, i, fndot[i], fndot[i] + fndotband[i]) == XLAL_SUCCESS, XLAL_EFUNC); } // Set metric to the spindown metric const double max_mismatch = 0.3; gsl_matrix *GAMAT(metric, 3, 3); for (size_t i = 0; i < metric->size1; ++i) { for (size_t j = i; j < metric->size2; ++j) { const double Tspan = 432000; const double metric_i_j_num = 4.0 * LAL_PI * LAL_PI * pow(Tspan, i + j + 2) * (i + 1) * (j + 1); const double metric_i_j_denom = LAL_FACT[i + 1] * LAL_FACT[j + 1] * (i + 2) * (j + 2) * (i + j + 3); gsl_matrix_set(metric, i, j, metric_i_j_num / metric_i_j_denom); gsl_matrix_set(metric, j, i, gsl_matrix_get(metric, i, j)); } } printf("Lattice type: %s\n", lattice_name); XLAL_CHECK(XLALSetTilingLatticeAndMetric(tiling, lattice_name, metric, max_mismatch) == XLAL_SUCCESS, XLAL_EFUNC); // Perform mismatch test XLAL_CHECK(MismatchTest(tiling, metric, max_mismatch, total_ref, mism_hist_ref) == XLAL_SUCCESS, XLAL_EFUNC); return XLAL_SUCCESS; }
static int MismatchAgeBrakeTest( const char *lattice_name, const double freq, const double freqband, const UINT8 total_ref, const double mism_hist_ref[MISM_HIST_BINS] ) { // Create lattice tiling LatticeTiling *tiling = XLALCreateLatticeTiling(3); XLAL_CHECK(tiling != NULL, XLAL_EFUNC); // Add bounds printf("Bounds: freq=%0.3g, freqband=%0.3g\n", freq, freqband); XLAL_CHECK(XLALSetLatticeTilingConstantBound(tiling, 0, freq, freq + freqband) == XLAL_SUCCESS, XLAL_EFUNC); XLAL_CHECK(XLALSetLatticeTilingF1DotAgeBrakingBound(tiling, 0, 1, 1e11, 2, 5) == XLAL_SUCCESS, XLAL_EFUNC); XLAL_CHECK(XLALSetLatticeTilingF2DotBrakingBound(tiling, 0, 1, 2, 2, 5) == XLAL_SUCCESS, XLAL_EFUNC); // Set metric to the spindown metric const double max_mismatch = 0.3; gsl_matrix *GAMAT(metric, 3, 3); for (size_t i = 0; i < metric->size1; ++i) { for (size_t j = i; j < metric->size2; ++j) { const double Tspan = 1036800; const double metric_i_j_num = 4.0 * LAL_PI * LAL_PI * pow(Tspan, i + j + 2) * (i + 1) * (j + 1); const double metric_i_j_denom = LAL_FACT[i + 1] * LAL_FACT[j + 1] * (i + 2) * (j + 2) * (i + j + 3); gsl_matrix_set(metric, i, j, metric_i_j_num / metric_i_j_denom); gsl_matrix_set(metric, j, i, gsl_matrix_get(metric, i, j)); } } printf("Lattice type: %s\n", lattice_name); XLAL_CHECK(XLALSetTilingLatticeAndMetric(tiling, lattice_name, metric, max_mismatch) == XLAL_SUCCESS, XLAL_EFUNC); // Perform mismatch test XLAL_CHECK(MismatchTest(tiling, metric, max_mismatch, total_ref, mism_hist_ref) == XLAL_SUCCESS, XLAL_EFUNC); return XLAL_SUCCESS; }
static int BasicTest( size_t n, const int bound_on_0, const int bound_on_1, const int bound_on_2, const int bound_on_3, const char *lattice_name, const UINT8 total_ref_0, const UINT8 total_ref_1, const UINT8 total_ref_2, const UINT8 total_ref_3 ) { const int bound_on[4] = {bound_on_0, bound_on_1, bound_on_2, bound_on_3}; const UINT8 total_ref[4] = {total_ref_0, total_ref_1, total_ref_2, total_ref_3}; // Create lattice tiling LatticeTiling *tiling = XLALCreateLatticeTiling(n); XLAL_CHECK(tiling != NULL, XLAL_EFUNC); // Add bounds for (size_t i = 0; i < n; ++i) { XLAL_CHECK(bound_on[i] == 0 || bound_on[i] == 1, XLAL_EFAILED); XLAL_CHECK(XLALSetLatticeTilingConstantBound(tiling, i, 0.0, bound_on[i] * pow(100.0, 1.0/n)) == XLAL_SUCCESS, XLAL_EFUNC); } // Set metric to the Lehmer matrix const double max_mismatch = 0.3; { gsl_matrix *GAMAT(metric, n, n); for (size_t i = 0; i < n; ++i) { for (size_t j = 0; j < n; ++j) { const double ii = i+1, jj = j+1; gsl_matrix_set(metric, i, j, jj >= ii ? ii/jj : jj/ii); } } XLAL_CHECK(XLALSetTilingLatticeAndMetric(tiling, lattice_name, metric, max_mismatch) == XLAL_SUCCESS, XLAL_EFUNC); GFMAT(metric); printf("Number of (tiled) dimensions: %zu (%zu)\n", XLALTotalLatticeTilingDimensions(tiling), XLALTiledLatticeTilingDimensions(tiling)); printf(" Bounds: %i %i %i %i\n", bound_on_0, bound_on_1, bound_on_2, bound_on_3); printf(" Lattice type: %s\n", lattice_name); } // Create lattice tiling locator LatticeTilingLocator *loc = XLALCreateLatticeTilingLocator(tiling); XLAL_CHECK(loc != NULL, XLAL_EFUNC); if (lalDebugLevel & LALINFOBIT) { printf(" Index trie:\n"); XLAL_CHECK(XLALPrintLatticeTilingIndexTrie(loc, stdout) == XLAL_SUCCESS, XLAL_EFUNC); } for (size_t i = 0; i < n; ++i) { // Create lattice tiling iterator and locator over 'i+1' dimensions LatticeTilingIterator *itr = XLALCreateLatticeTilingIterator(tiling, i+1); XLAL_CHECK(itr != NULL, XLAL_EFUNC); // Count number of points const UINT8 total = XLALTotalLatticeTilingPoints(itr); printf("Number of lattice points in %zu dimensions: %" LAL_UINT8_FORMAT "\n", i+1, total); XLAL_CHECK(imaxabs(total - total_ref[i]) <= 1, XLAL_EFUNC, "ERROR: |total - total_ref[%zu]| = |%" LAL_UINT8_FORMAT " - %" LAL_UINT8_FORMAT "| > 1", i, total, total_ref[i]); for (UINT8 k = 0; XLALNextLatticeTilingPoint(itr, NULL) > 0; ++k) { const UINT8 itr_index = XLALCurrentLatticeTilingIndex(itr); XLAL_CHECK(k == itr_index, XLAL_EFUNC, "ERROR: k = %" LAL_UINT8_FORMAT " != %" LAL_UINT8_FORMAT " = itr_index", k, itr_index); } XLAL_CHECK(XLALResetLatticeTilingIterator(itr) == XLAL_SUCCESS, XLAL_EFUNC); // Check tiling statistics printf(" Check tiling statistics ..."); for (size_t j = 0; j < n; ++j) { const LatticeTilingStats *stats = XLALLatticeTilingStatistics(tiling, j); XLAL_CHECK(stats != NULL, XLAL_EFUNC); XLAL_CHECK(imaxabs(stats->total_points - total_ref[j]) <= 1, XLAL_EFAILED, "\n " "ERROR: |total - total_ref[%zu]| = |%" LAL_UINT8_FORMAT " - %" LAL_UINT8_FORMAT "| > 1", j, stats->total_points, total_ref[j]); XLAL_CHECK(stats->min_points <= stats->avg_points, XLAL_EFAILED, "\n " "ERROR: min_points = %" LAL_INT4_FORMAT " > %g = avg_points", stats->min_points, stats->avg_points); XLAL_CHECK(stats->max_points >= stats->avg_points, XLAL_EFAILED, "\n " "ERROR: max_points = %" LAL_INT4_FORMAT " < %g = avg_points", stats->max_points, stats->avg_points); } printf(" done\n"); // Get all points gsl_matrix *GAMAT(points, n, total); XLAL_CHECK(XLALNextLatticeTilingPoints(itr, &points) == (int)total, XLAL_EFUNC); XLAL_CHECK(XLALNextLatticeTilingPoint(itr, NULL) == 0, XLAL_EFUNC); // Get nearest points to each template, check for consistency printf(" Testing XLALNearestLatticeTiling{Point|Block}() ..."); gsl_vector *GAVEC(nearest, n); UINT8Vector *nearest_indexes = XLALCreateUINT8Vector(n); XLAL_CHECK(nearest_indexes != NULL, XLAL_ENOMEM); for (UINT8 k = 0; k < total; ++k) { gsl_vector_const_view point_view = gsl_matrix_const_column(points, k); const gsl_vector *point = &point_view.vector; XLAL_CHECK(XLALNearestLatticeTilingPoint(loc, point, nearest, nearest_indexes) == XLAL_SUCCESS, XLAL_EFUNC); gsl_vector_sub(nearest, point); double err = gsl_blas_dasum(nearest) / n; XLAL_CHECK(err < 1e-6, XLAL_EFAILED, "\n " "ERROR: err = %e < 1e-6", err); XLAL_CHECK(nearest_indexes->data[i] == k, XLAL_EFAILED, "\n " "ERROR: nearest_indexes[%zu] = %" LAL_UINT8_FORMAT " != %" LAL_UINT8_FORMAT "\n", i, nearest_indexes->data[i], k); if (0 < i) { const LatticeTilingStats *stats = XLALLatticeTilingStatistics(tiling, i); UINT8 nearest_index = 0; UINT4 nearest_left = 0, nearest_right = 0; XLAL_CHECK(XLALNearestLatticeTilingBlock(loc, point, i, nearest, &nearest_index, &nearest_left, &nearest_right) == XLAL_SUCCESS, XLAL_EFUNC); XLAL_CHECK(nearest_index == nearest_indexes->data[i-1], XLAL_EFAILED, "\n " "ERROR: nearest_index = %" LAL_UINT8_FORMAT " != %" LAL_UINT8_FORMAT "\n", nearest_index, nearest_indexes->data[i-1]); UINT4 nearest_len = 1 + nearest_left + nearest_right; XLAL_CHECK(nearest_len <= stats->max_points, XLAL_EFAILED, "\n " "ERROR: nearest_len = %i > %i = stats[%zu]->max_points\n", nearest_len, stats->max_points, i); } if (i+1 < n) { const LatticeTilingStats *stats = XLALLatticeTilingStatistics(tiling, i+1); UINT8 nearest_index = 0; UINT4 nearest_left = 0, nearest_right = 0; XLAL_CHECK(XLALNearestLatticeTilingBlock(loc, point, i+1, nearest, &nearest_index, &nearest_left, &nearest_right) == XLAL_SUCCESS, XLAL_EFUNC); XLAL_CHECK(nearest_index == nearest_indexes->data[i], XLAL_EFAILED, "\n " "ERROR: nearest_index = %" LAL_UINT8_FORMAT " != %" LAL_UINT8_FORMAT "\n", nearest_index, nearest_indexes->data[i]); UINT4 nearest_len = 1 + nearest_left + nearest_right; XLAL_CHECK(nearest_len <= stats->max_points, XLAL_EFAILED, "\n " "ERROR: nearest_len = %i > %i = stats[%zu]->max_points\n", nearest_len, stats->max_points, i+1); } } printf(" done\n"); // Cleanup XLALDestroyLatticeTilingIterator(itr); GFMAT(points); GFVEC(nearest); XLALDestroyUINT8Vector(nearest_indexes); } for (size_t i = 0; i < n; ++i) { // Create alternating lattice tiling iterator over 'i+1' dimensions LatticeTilingIterator *itr_alt = XLALCreateLatticeTilingIterator(tiling, i+1); XLAL_CHECK(itr_alt != NULL, XLAL_EFUNC); XLAL_CHECK(XLALSetLatticeTilingAlternatingIterator(itr_alt, true) == XLAL_SUCCESS, XLAL_EFUNC); // Count number of points, check for consistency with non-alternating count UINT8 total = 0; while (XLALNextLatticeTilingPoint(itr_alt, NULL) > 0) ++total; XLAL_CHECK(imaxabs(total - total_ref[i]) <= 1, XLAL_EFUNC, "ERROR: alternating |total - total_ref[%zu]| = |%" LAL_UINT8_FORMAT " - %" LAL_UINT8_FORMAT "| > 1", i, total, total_ref[i]); // Cleanup XLALDestroyLatticeTilingIterator(itr_alt); } // Cleanup XLALDestroyLatticeTiling(tiling); XLALDestroyLatticeTilingLocator(loc); LALCheckMemoryLeaks(); printf("\n"); fflush(stdout); return XLAL_SUCCESS; }
static int MismatchTest( LatticeTiling *tiling, gsl_matrix *metric, const double max_mismatch, const UINT8 total_ref, const double mism_hist_ref[MISM_HIST_BINS] ) { const size_t n = XLALTotalLatticeTilingDimensions(tiling); // Create lattice tiling iterator and locator LatticeTilingIterator *itr = XLALCreateLatticeTilingIterator(tiling, n); XLAL_CHECK(itr != NULL, XLAL_EFUNC); LatticeTilingLocator *loc = XLALCreateLatticeTilingLocator(tiling); XLAL_CHECK(loc != NULL, XLAL_EFUNC); // Count number of points const UINT8 total = XLALTotalLatticeTilingPoints(itr); printf("Number of lattice points: %" LAL_UINT8_FORMAT "\n", total); XLAL_CHECK(imaxabs(total - total_ref) <= 1, XLAL_EFUNC, "ERROR: |total - total_ref| = |%" LAL_UINT8_FORMAT " - %" LAL_UINT8_FORMAT "| > 1", total, total_ref); // Get all points gsl_matrix *GAMAT(points, n, total); XLAL_CHECK(XLALNextLatticeTilingPoints(itr, &points) == (int)total, XLAL_EFUNC); XLAL_CHECK(XLALNextLatticeTilingPoint(itr, NULL) == 0, XLAL_EFUNC); // Initialise mismatch histogram counts double mism_hist[MISM_HIST_BINS] = {0}; double mism_hist_total = 0, mism_hist_out_of_range = 0; // Perform 10 injections for every template { gsl_matrix *GAMAT(injections, 3, total); gsl_matrix *GAMAT(nearest, 3, total); gsl_matrix *GAMAT(temp, 3, total); RandomParams *rng = XLALCreateRandomParams(total); XLAL_CHECK(rng != NULL, XLAL_EFUNC); for (size_t i = 0; i < 10; ++i) { // Generate random injection points XLAL_CHECK(XLALRandomLatticeTilingPoints(tiling, 0.0, rng, injections) == XLAL_SUCCESS, XLAL_EFUNC); // Find nearest lattice template points XLAL_CHECK(XLALNearestLatticeTilingPoints(loc, injections, &nearest, NULL) == XLAL_SUCCESS, XLAL_EFUNC); // Compute mismatch between injections gsl_matrix_sub(nearest, injections); gsl_blas_dsymm(CblasLeft, CblasUpper, 1.0, metric, nearest, 0.0, temp); for (size_t j = 0; j < temp->size2; ++j) { gsl_vector_view temp_j = gsl_matrix_column(temp, j); gsl_vector_view nearest_j = gsl_matrix_column(nearest, j); double mismatch = 0.0; gsl_blas_ddot(&nearest_j.vector, &temp_j.vector, &mismatch); mismatch /= max_mismatch; // Increment mismatch histogram counts ++mism_hist_total; if (mismatch < 0.0 || mismatch > 1.0) { ++mism_hist_out_of_range; } else { ++mism_hist[lround(floor(mismatch * MISM_HIST_BINS))]; } } } // Cleanup GFMAT(injections, nearest, temp); XLALDestroyRandomParams(rng); } // Normalise histogram for (size_t i = 0; i < MISM_HIST_BINS; ++i) { mism_hist[i] *= MISM_HIST_BINS / mism_hist_total; } // Print mismatch histogram and its reference printf("Mismatch histogram: "); for (size_t i = 0; i < MISM_HIST_BINS; ++i) { printf(" %0.3f", mism_hist[i]); } printf("\n"); printf("Reference histogram:"); for (size_t i = 0; i < MISM_HIST_BINS; ++i) { printf(" %0.3f", mism_hist_ref[i]); } printf("\n"); // Determine error between mismatch histogram and its reference double mism_hist_error = 0.0; for (size_t i = 0; i < MISM_HIST_BINS; ++i) { mism_hist_error += fabs(mism_hist[i] - mism_hist_ref[i]); } mism_hist_error /= MISM_HIST_BINS; printf("Mismatch histogram error: %0.3e\n", mism_hist_error); const double mism_hist_error_tol = 5e-2; if (mism_hist_error >= mism_hist_error_tol) { XLAL_ERROR(XLAL_EFAILED, "ERROR: mismatch histogram error exceeds %0.3e\n", mism_hist_error_tol); } // Check fraction of injections out of histogram range const double mism_out_of_range = mism_hist_out_of_range / mism_hist_total; printf("Fraction of points out of histogram range: %0.3e\n", mism_out_of_range); const double mism_out_of_range_tol = 2e-3; if (mism_out_of_range > mism_out_of_range_tol) { XLAL_ERROR(XLAL_EFAILED, "ERROR: fraction of points out of histogram range exceeds %0.3e\n", mism_out_of_range_tol); } // Perform 10 injections outside parameter space { gsl_matrix *GAMAT(injections, 3, 10); gsl_matrix *GAMAT(nearest, n, total); RandomParams *rng = XLALCreateRandomParams(total); XLAL_CHECK(rng != NULL, XLAL_EFUNC); // Generate random injection points outside parameter space XLAL_CHECK(XLALRandomLatticeTilingPoints(tiling, 5.0, rng, injections) == XLAL_SUCCESS, XLAL_EFUNC); // Find nearest lattice template points XLAL_CHECK(XLALNearestLatticeTilingPoints(loc, injections, &nearest, NULL) == XLAL_SUCCESS, XLAL_EFUNC); // Cleanup GFMAT(injections, nearest); XLALDestroyRandomParams(rng); } // Cleanup XLALDestroyLatticeTiling(tiling); XLALDestroyLatticeTilingIterator(itr); XLALDestroyLatticeTilingLocator(loc); GFMAT(metric, points); LALCheckMemoryLeaks(); printf("\n"); fflush(stdout); return XLAL_SUCCESS; }
/// /// Compute the transform which changes the metric reference time \f$ \tau_0 \rightarrow \tau_1 = /// \tau_0 + \Delta\tau \f$. /// /// If \c p_transform is non-NULL, return the reference-time transform in \c *p_transform. /// If \c p_gpr_ij is non-NULL, apply the transform to the metric \c *p_gpr_ij. /// /// \note \c *p_gpr_ij and \c *p_transform will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij /// may point to the same matrix. /// int XLALChangeMetricReferenceTime( gsl_matrix **p_gpr_ij, ///< [in,out,optional] Pointer to transformed matrix \f$g^{\prime}_{ij}\f$ gsl_matrix **p_transform, ///< [in,out,optional] Pointer to reference time transform const gsl_matrix *g_ij, ///< [in] Matrix to transform \f$g_{ij}\f$ const DopplerCoordinateSystem *coordSys, ///< [in] Coordinate system of metric const double Dtau ///< [in] Difference between new and old reference times \f$\Delta\tau\f$ ) { // Check input XLAL_CHECK( g_ij != NULL, XLAL_EFAULT ); XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE ); if ( p_transform != NULL ) { if ( *p_transform != NULL ) { XLAL_CHECK( (*p_transform)->size1 == g_ij->size1, XLAL_ESIZE ); XLAL_CHECK( (*p_transform)->size2 == g_ij->size2, XLAL_ESIZE ); } else { GAMAT( *p_transform, g_ij->size1, g_ij->size2 ); } } XLAL_CHECK( coordSys != NULL, XLAL_EFAULT ); XLAL_CHECK( coordSys->dim == g_ij->size1, XLAL_ESIZE ); for( size_t i = 0; i < coordSys->dim; ++i ) { switch( coordSys->coordIDs[i] ) { case DOPPLERCOORD_GC_NU0: case DOPPLERCOORD_GC_NU1: case DOPPLERCOORD_GC_NU2: case DOPPLERCOORD_GC_NU3: XLAL_ERROR( XLAL_EINVAL, "GCT coordinates are not supported" ); default: break; } } // Compute transformation matrix for frequency-spindown coordinates // from Prix: "Frequency metric for CW searches" (2014-08-17), p. 4 gsl_matrix *GAMAT( transform, g_ij->size1, g_ij->size2 ); gsl_matrix_set_identity( transform ); if( Dtau != 0.0 ) { for( size_t i = 0; i < coordSys->dim; ++i ) { const DopplerCoordinateID icoord = coordSys->coordIDs[i]; if (DOPPLERCOORD_FREQ <= icoord && icoord <= DOPPLERCOORD_LASTFDOT) { const size_t ispinorder = icoord - DOPPLERCOORD_FREQ; for( size_t j = i + 1; j < coordSys->dim; ++j ) { const DopplerCoordinateID jcoord = coordSys->coordIDs[j]; if (DOPPLERCOORD_FREQ <= jcoord && jcoord <= DOPPLERCOORD_LASTFDOT) { const size_t jspinorder = jcoord - DOPPLERCOORD_FREQ; if( jspinorder > ispinorder ) { const double tij = LAL_FACT_INV[jspinorder - ispinorder] * pow( -1 * Dtau, jspinorder - ispinorder ); gsl_matrix_set( transform, i, j, tij ); } } } } } } // Apply transform if ( p_gpr_ij != NULL ) { XLAL_CHECK( XLALTransformMetric( p_gpr_ij, transform, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC ); } // Return transform if ( p_transform != NULL ) { gsl_matrix_memcpy( *p_transform, transform ); } // Cleanup GFMAT( transform ); return XLAL_SUCCESS; } // XLALPhaseMetricRefTimeTransform()
/// /// Return a metric in <i>naturalized</i> coordinates. /// Frequency coordinates of spindown order \f$s\f$ are scaled by /// \f[ \frac{2\pi}{(s+1)!} \left(\frac{\overline{\Delta T}}{2}\right)^{s+1} \f] /// where \f$\overline{\Delta T}\equiv\sum_{k}^{N} \Delta T_k\f$ is the average segment-length /// over all \f$N\f$ segments. /// /// Sky coordinates are scaled by Holgers' units, see Eq.(44) in PRD82,042002(2010), /// without the equatorial rotation in alpha: /// \f[ \frac{2\pi f R_{E} \cos(\delta_{D})}{c} \f] /// where \f$f\f$ is the frequency and /// \f$R_{E}\f$ the Earth radius, and \f$\delta_{D}\f$ is the detectors latitude. /// /// If \c p_transform is non-NULL, return the naturalization transform in \c *p_transform. /// If \c p_gpr_ij is non-NULL, apply the transform to the metric \c *p_gpr_ij. /// /// \note \c *p_gpr_ij and \c *p_transform will be allocated if \c NULL. \c *p_gpr_ij and \c g_ij /// may point to the same matrix. /// int XLALNaturalizeMetric( gsl_matrix **p_gpr_ij, ///< [in,out,optional] Pointer to transformed matrix \f$g^{\prime}_{ij}\f$ gsl_matrix **p_transform, ///< [in,out,optional] Pointer to naturalization transform const gsl_matrix *g_ij, ///< [in] Matrix to transform \f$g_{ij}\f$ const DopplerMetricParams *metricParams ///< [in] Input parameters used to calculate naturalization transform ) { // Check input XLAL_CHECK( g_ij != NULL, XLAL_EFAULT ); XLAL_CHECK( g_ij->size1 == g_ij->size2, XLAL_ESIZE ); if ( p_transform != NULL ) { if ( *p_transform != NULL ) { XLAL_CHECK( (*p_transform)->size1 == g_ij->size1, XLAL_ESIZE ); XLAL_CHECK( (*p_transform)->size2 == g_ij->size2, XLAL_ESIZE ); } else { GAMAT( *p_transform, g_ij->size1, g_ij->size2 ); } } XLAL_CHECK( metricParams != NULL, XLAL_EFAULT ); // Compute average segment length XLAL_CHECK ( XLALSegListIsInitialized ( &(metricParams->segmentList) ), XLAL_EINVAL, "Passed un-initialzied segment list 'metricParams->segmentList'\n"); UINT4 Nseg = metricParams->segmentList.length; REAL8 sumTseg = 0; for ( UINT4 k=0; k < Nseg; k ++ ) { LIGOTimeGPS *startTime_k = &(metricParams->segmentList.segs[k].start); LIGOTimeGPS *endTime_k = &(metricParams->segmentList.segs[k].end); sumTseg += XLALGPSDiff( endTime_k, startTime_k ); } REAL8 avgTseg = sumTseg / Nseg; // Compute naturalization transform gsl_matrix *GAMAT( transform, g_ij->size1, g_ij->size2 ); gsl_matrix_set_zero( transform ); for (size_t i = 0; i < g_ij->size1; ++i) { const DopplerCoordinateID coordID = metricParams->coordSys.coordIDs[i]; const double Freq = metricParams->signalParams.Doppler.fkdot[0]; const double T = avgTseg; double scale = 0; switch (coordID) { case DOPPLERCOORD_NONE: scale = 1; break; case DOPPLERCOORD_FREQ: case DOPPLERCOORD_GC_NU0: scale = LAL_TWOPI * LAL_FACT_INV[1] * (0.5 * T); break; case DOPPLERCOORD_F1DOT: case DOPPLERCOORD_GC_NU1: scale = LAL_TWOPI * LAL_FACT_INV[2] * POW2(0.5 * T); break; case DOPPLERCOORD_F2DOT: case DOPPLERCOORD_GC_NU2: scale = LAL_TWOPI * LAL_FACT_INV[3] * POW3(0.5 * T); break; case DOPPLERCOORD_F3DOT: case DOPPLERCOORD_GC_NU3: scale = LAL_TWOPI * LAL_FACT_INV[4] * POW4(0.5 * T); break; case DOPPLERCOORD_ALPHA: case DOPPLERCOORD_DELTA: case DOPPLERCOORD_N2X_EQU: case DOPPLERCOORD_N2Y_EQU: case DOPPLERCOORD_N2X_ECL: case DOPPLERCOORD_N2Y_ECL: case DOPPLERCOORD_N3X_EQU: case DOPPLERCOORD_N3Y_EQU: case DOPPLERCOORD_N3Z_EQU: case DOPPLERCOORD_N3X_ECL: case DOPPLERCOORD_N3Y_ECL: case DOPPLERCOORD_N3Z_ECL: case DOPPLERCOORD_N3SX_EQU: case DOPPLERCOORD_N3SY_EQU: case DOPPLERCOORD_N3OX_ECL: case DOPPLERCOORD_N3OY_ECL: { const REAL8 rEarth_c = (LAL_REARTH_SI / LAL_C_SI); REAL8 cosdD = cos ( metricParams->multiIFO.sites[0].frDetector.vertexLatitudeRadians ); scale = LAL_TWOPI * Freq * rEarth_c * cosdD; } break; default: scale = 1; break; } // switch(coordID) gsl_matrix_set( transform, i, i, 1.0 / scale ); } // Apply transform if ( p_gpr_ij != NULL ) { XLAL_CHECK( XLALTransformMetric( p_gpr_ij, transform, g_ij ) == XLAL_SUCCESS, XLAL_EFUNC ); } // Return transform if ( p_transform != NULL ) { gsl_matrix_memcpy( *p_transform, transform ); } // Cleanup GFMAT( transform ); return XLAL_SUCCESS; } // XLALNaturalizeMetric()
static int CheckSuperskyMetrics( const gsl_matrix *rssky_metric, const double rssky_metric_ref[4][4], const gsl_matrix *rssky_transf, const double rssky_transf_ref[6][3], const double phys_mismatch[NUM_POINTS][NUM_POINTS], const double phys_mismatch_tol ) { // Check supersky metrics { gsl_matrix_const_view rssky_metric_ref_view = gsl_matrix_const_view_array( ( const double * )rssky_metric_ref, 4, 4 ); const double err = XLALCompareMetrics( rssky_metric, &rssky_metric_ref_view.matrix ), err_tol = 1e-6; XLAL_CHECK( err <= err_tol, XLAL_ETOL, "'rssky_metric' check failed: err = %0.3e > %0.3e = err_tol", err, err_tol ); } { XLAL_CHECK( rssky_transf->size1 == 6 && rssky_transf->size2 == 3, XLAL_ESIZE ); const double err_tol = 1e-5; for ( size_t i = 0; i < rssky_transf->size1; ++i ) { for ( size_t j = 0; j < rssky_transf->size2; ++j ) { const double rssky_transf_ij = gsl_matrix_get( rssky_transf, i, j ); const double rssky_transf_ref_ij = rssky_transf_ref[i][j]; CHECK_RELERR( rssky_transf_ij, rssky_transf_ref_ij, err_tol ); } } } // Check round-trip conversions of each test point { gsl_matrix *GAMAT( rssky_points, 4, NUM_POINTS ); for ( size_t j = 0; j < NUM_POINTS; ++j ) { gsl_vector_view rssky_point = gsl_matrix_column( rssky_points, j ); PulsarDopplerParams XLAL_INIT_DECL( new_phys_point ); XLAL_CHECK( XLALConvertPhysicalToSuperskyPoint( &rssky_point.vector, &phys_points[j], rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK( XLALConvertSuperskyToPhysicalPoint( &new_phys_point, &rssky_point.vector, rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK( CompareDoppler( &phys_points[j], &new_phys_point ) == EXIT_SUCCESS, XLAL_EFUNC ); } gsl_matrix *intm_phys_points = NULL; gsl_matrix *new_rssky_points = NULL; XLAL_CHECK( XLALConvertSuperskyToPhysicalPoints( &intm_phys_points, rssky_points, rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK( XLALConvertPhysicalToSuperskyPoints( &new_rssky_points, intm_phys_points, rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC ); const double err_tol = 1e-6; for ( size_t i = 0; i < 4; ++i ) { for ( size_t j = 0; j < NUM_POINTS; ++j ) { const double rssky_points_ij = gsl_matrix_get( rssky_points, i, j ); const double new_rssky_points_ij = gsl_matrix_get( new_rssky_points, i, j ); CHECK_RELERR( rssky_points_ij, new_rssky_points_ij, err_tol ); } } GFMAT( rssky_points, intm_phys_points, new_rssky_points ); } // Check mismatches between pairs of points { gsl_vector *GAVEC( rssky_point_i, 4 ); gsl_vector *GAVEC( rssky_point_j, 4 ); gsl_vector *GAVEC( temp, 4 ); for ( size_t i = 0; i < NUM_POINTS; ++i ) { XLAL_CHECK( XLALConvertPhysicalToSuperskyPoint( rssky_point_i, &phys_points[i], rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC ); for ( size_t j = 0; j < NUM_POINTS; ++j ) { XLAL_CHECK( XLALConvertPhysicalToSuperskyPoint( rssky_point_j, &phys_points[j], rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC ); gsl_vector_sub( rssky_point_j, rssky_point_i ); gsl_blas_dgemv( CblasNoTrans, 1.0, rssky_metric, rssky_point_j, 0.0, temp ); double mismatch = 0.0; gsl_blas_ddot( rssky_point_j, temp, &mismatch ); CHECK_RELERR( mismatch, phys_mismatch[i][j], phys_mismatch_tol ); } } GFVEC( rssky_point_i, rssky_point_j, temp ); } return XLAL_SUCCESS; }