// test string-vector parsing function XLALParseStringValueAsStringVector() int test_ParseStringVector(void) { #define STR1 "Hello, world!" #define STR2 "xyda 3!#4134" #define STR3 "&\\//.. :: some junk" #define STR4 "H1" #define STR5 "H2" #define STR6 "L1" LALStringVector *strVect1; XLAL_CHECK ( (strVect1 = XLALCreateStringVector ( STR1, STR2, STR3, STR4, STR5, NULL )) != NULL, XLAL_EFUNC ); XLAL_CHECK ( (strVect1 = XLALAppendString2Vector ( strVect1, STR6 )) != NULL, XLAL_EFUNC ); // now 'print' this string-vector as a 'string-value', then re-parse back into a vector: CHAR *strValue1 = NULL; LALStringVector *strVect2 = NULL; XLAL_CHECK ( (strValue1 = XLALPrintStringValueOfSTRINGVector ( &strVect1 )) != NULL, XLAL_EFUNC ); XLALPrintInfo ("String value of initial string-vector: %s\n", strValue1 ); XLAL_CHECK ( XLALParseStringValueAsSTRINGVector ( &strVect2, strValue1 ) == XLAL_SUCCESS, XLAL_EFUNC ); CHAR *strValue2 = NULL; XLAL_CHECK ( (strValue2 = XLALPrintStringValueOfSTRINGVector ( &strVect2 )) != NULL, XLAL_EFUNC ); XLALPrintInfo ("String value of re-parsed string-vector: %s\n", strValue2 ); // ----- compare results // 1) compare string values XLAL_CHECK ( strcmp ( strValue1, strValue2 ) == 0, XLAL_EFAILED, "String values differ:\nstrValue1 = %s\nstrValue2 = %s\n", strValue1, strValue2 ); // 2) compare string vectors UINT4 len1 = strVect1->length; UINT4 len2 = strVect2->length; XLAL_CHECK ( len1 == len2, XLAL_EFAILED, "String vectors vect1 and vect2 have different lengths (%d != %d )\n", len1, len2 ); for ( UINT4 i = 0; i < len1; i++ ) { if ( strcmp ( strVect1->data[i], strVect2->data[i] ) != 0 ) { for ( UINT4 j=0; j < len1; j ++ ) { XLALPrintError ("j = %d: s1[j] = %6s, s2[j] = %6s\n", j, strVect1->data[j], strVect2->data[j] ); } XLAL_ERROR ( XLAL_EFAILED, "Printed and re-parsed string-vector differ!\n" ); } // if s1[i] != s2[i] } // for i < len // clean up memory XLALFree ( strValue1 ); XLALFree ( strValue2 ); XLALDestroyStringVector ( strVect1 ); XLALDestroyStringVector ( strVect2 ); return XLAL_SUCCESS; } // test_ParseStringVector()
/** * Test various StringVector functions */ int XLALStringVector_TEST ( void ) { LALStringVector *strVect1 = NULL, *strVectCmp = NULL; #define STR1 "Hello" #define STR2 "World" #define STR3 "foo" #define STR4 "H1" #define STR5 "H2" #define STR6 "L1" if ( (strVect1 = XLALCreateStringVector ( STR1, STR2, STR3, STR4, STR5, NULL )) == NULL ) XLAL_ERROR ( XLAL_EFUNC ); if ( ( strVect1 = XLALAppendString2Vector ( strVect1, STR6 )) == NULL ) XLAL_ERROR ( XLAL_EFUNC ); // now sort string-vector according to strcmp() if ( XLALSortStringVector ( strVect1 ) != XLAL_SUCCESS ) { XLALDestroyStringVector ( strVect1 ); XLAL_ERROR ( XLAL_EFUNC ); } // generate 'manually' sorted string-vector, using CSV function instead // sort-order according to "LC_ALL=C sort" if ( ( strVectCmp = XLALParseCSV2StringVector ( STR4 "," STR5 "," STR1 "," STR6 "," STR2 "," STR3 )) == NULL ) { XLALDestroyStringVector ( strVect1 ); XLAL_ERROR ( XLAL_EFUNC ); } /* compare results */ UINT4 len1 = strVect1->length; UINT4 len2 = strVectCmp->length; if ( len1 != len2 ) { XLALDestroyStringVector ( strVect1 ); XLALDestroyStringVector ( strVectCmp ); XLAL_ERROR ( XLAL_EFAILED, "String vectors have different lengths (%d != %d )\n", len1, len2 ); } for ( UINT4 i = 0; i < len1; i++ ) { if ( 0 != strcmp ( strVect1->data[i], strVectCmp->data[i] ) ) { XLALPrintError ( "%s: Sorted string-vector differs from expectation!\n", __func__ ); for ( UINT4 j=0; j < len1; j ++ ) XLALPrintError ("j = %d: s1[j] = %6s, s2[j] = %6s\n", j, strVect1->data[j], strVectCmp->data[j] ); /* clean up memory, and return with error */ XLALDestroyStringVector ( strVect1 ); XLALDestroyStringVector ( strVectCmp ); XLAL_ERROR ( XLAL_EFAILED, "String sorting failed.\n"); } /* if s1[i] != s2[i] */ } /* for i < len */ /* clean up memory */ XLALDestroyStringVector ( strVect1 ); XLALDestroyStringVector ( strVectCmp ); return XLAL_SUCCESS; } /* XLALStringVector_TEST() */
/** * Function to determine the PulsarParamsVector input from a user-input defining CW sources. * * This option supports a dual-type feature: if any string in the list is of the form '{...}', then * it determines the *contents* of a config-file, otherwise the name-pattern of config-files to be parsed by XLALFindFiles(), * NOTE: when specifying file-contents, options can be separated by ';' and/or newlines) */ PulsarParamsVector * XLALPulsarParamsFromUserInput ( const LALStringVector *UserInput ///< [in] user-input CSV list defining 'CW sources' ) { XLAL_CHECK_NULL ( UserInput, XLAL_EINVAL ); XLAL_CHECK_NULL ( UserInput->length > 0, XLAL_EINVAL ); PulsarParamsVector *allSources = NULL; for ( UINT4 l = 0; l < UserInput->length; l ++ ) { const char *thisInput = UserInput->data[l]; if ( thisInput[0] != '{' ) // if it's an actual file-specification { LALStringVector *file_list; XLAL_CHECK_NULL ( ( file_list = XLALFindFiles ( &thisInput[0] )) != NULL, XLAL_EFUNC ); UINT4 numFiles = file_list->length; for ( UINT4 i = 0; i < numFiles; i ++ ) { PulsarParamsVector *sources_i; XLAL_CHECK_NULL ( (sources_i = XLALPulsarParamsFromFile ( file_list->data[i] )) != NULL, XLAL_EFUNC ); XLAL_CHECK_NULL ( (allSources = XLALPulsarParamsVectorAppend ( allSources, sources_i )) != NULL, XLAL_EFUNC ); XLALDestroyPulsarParamsVector ( sources_i ); } // for i < numFiles XLALDestroyStringVector ( file_list ); } // if file-pattern given else { UINT4 len = strlen(thisInput); XLAL_CHECK_NULL ( (thisInput[0] == '{') && (thisInput[len-1] == '}'), XLAL_EINVAL, "Invalid file-content input:\n%s\n", thisInput ); char *buf; XLAL_CHECK_NULL ( (buf = XLALStringDuplicate ( &thisInput[1] )) != NULL, XLAL_EFUNC ); len = strlen(buf); buf[len-1] = 0; // remove trailing '}' LALParsedDataFile *cfgdata = NULL; XLAL_CHECK_NULL ( XLALParseDataFileContent ( &cfgdata, buf ) == XLAL_SUCCESS, XLAL_EFUNC ); XLALFree ( buf ); PulsarParamsVector *addSource; XLAL_CHECK_NULL ( (addSource = XLALCreatePulsarParamsVector ( 1 )) != NULL, XLAL_EFUNC ); XLAL_CHECK_NULL ( XLALReadPulsarParams ( &addSource->data[0], cfgdata, NULL ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK_NULL ( (addSource->data[0].name = XLALStringDuplicate ( "direct-string-input" )) != NULL, XLAL_EFUNC ); XLALDestroyParsedDataFile ( cfgdata ); XLAL_CHECK_NULL ( (allSources = XLALPulsarParamsVectorAppend ( allSources, addSource )) != NULL, XLAL_EFUNC ); XLALDestroyPulsarParamsVector ( addSource ); } // if direct config-string given } // for l < len(UserInput) return allSources; } // XLALPulsarParamsFromUserInput()
/// /// Free contents of setup data /// void XLALWeaveSetupDataClear( WeaveSetupData *setup ) { if ( setup != NULL ) { XLALDestroyStringVector( setup->detectors ); XLALSegListFree( setup->segments ); XLALDestroySuperskyMetrics( setup->metrics ); XLALDestroyEphemerisData( setup->ephemerides ); } }
/** * Parse a given 'CWsources' config file for PulsarParams, return vector * of all pulsar definitions found [using sections] */ PulsarParamsVector * XLALPulsarParamsFromFile ( const char *fname ///< [in] 'CWsources' config file name ) { XLAL_CHECK_NULL ( fname != NULL, XLAL_EINVAL ); LALParsedDataFile *cfgdata = NULL; XLAL_CHECK_NULL ( XLALParseDataFile ( &cfgdata, fname ) == XLAL_SUCCESS, XLAL_EFUNC ); LALStringVector *sections; XLAL_CHECK_NULL ( (sections = XLALListConfigFileSections ( cfgdata )) != NULL, XLAL_EFUNC ); UINT4 numPulsars = sections->length; // currently only single-section defs supported! FIXME PulsarParamsVector *sources; XLAL_CHECK_NULL ( (sources = XLALCreatePulsarParamsVector ( numPulsars )) != NULL, XLAL_EFUNC ); for ( UINT4 i = 0; i < numPulsars; i ++ ) { const char *sec_i = sections->data[i]; if ( strcmp ( sec_i, "default" ) == 0 ) { // special handling of 'default' section sec_i = NULL; } XLAL_CHECK_NULL ( XLALReadPulsarParams ( &sources->data[i], cfgdata, sec_i ) == XLAL_SUCCESS, XLAL_EFUNC ); // ----- source naming convention: 'filename:section' char *name; size_t len = strlen(fname) + strlen(sections->data[i]) + 2; XLAL_CHECK_NULL ( (name = XLALCalloc(1, len)) != NULL, XLAL_ENOMEM ); sprintf ( name, "%s:%s", fname, sections->data[i] ); sources->data[i].name = name; } // for i < numPulsars XLALDestroyStringVector ( sections ); XLALDestroyParsedDataFile ( cfgdata ); return sources; } // XLALPulsarParamsFromFile()
/// /// Create coherent input data /// WeaveCohInput *XLALWeaveCohInputCreate( const LALStringVector *setup_detectors, const WeaveSimulationLevel simulation_level, const SFTCatalog *sft_catalog, const UINT4 segment_index, const LALSeg *segment, const PulsarDopplerParams *min_phys, const PulsarDopplerParams *max_phys, const double dfreq, const EphemerisData *ephemerides, const LALStringVector *sft_noise_sqrtSX, const LALStringVector *Fstat_assume_sqrtSX, FstatOptionalArgs *Fstat_opt_args, const WeaveStatisticsParams *statistics_params, BOOLEAN recalc_stage ) { // Check input XLAL_CHECK_NULL( setup_detectors != NULL, XLAL_EFAULT ); XLAL_CHECK_NULL( ( simulation_level & WEAVE_SIMULATE_MIN_MEM ) || ( sft_catalog != NULL ), XLAL_EFAULT ); XLAL_CHECK_NULL( segment != NULL, XLAL_EFAULT ); XLAL_CHECK_NULL( min_phys != NULL, XLAL_EFAULT ); XLAL_CHECK_NULL( max_phys != NULL, XLAL_EFAULT ); XLAL_CHECK_NULL( dfreq >= 0, XLAL_EINVAL ); XLAL_CHECK_NULL( ephemerides != NULL, XLAL_EFAULT ); XLAL_CHECK_NULL( Fstat_opt_args != NULL, XLAL_EFAULT ); XLAL_CHECK_NULL( statistics_params != NULL, XLAL_EFAULT ); // Allocate memory WeaveCohInput *coh_input = XLALCalloc( 1, sizeof( *coh_input ) ); XLAL_CHECK_NULL( coh_input != NULL, XLAL_ENOMEM ); // Set fields coh_input->setup_detectors = setup_detectors; coh_input->simulation_level = simulation_level; coh_input->seg_info_have_sft_info = ( sft_catalog != NULL ); coh_input->Fstat_collect_timing = Fstat_opt_args->collectTiming; // Record information from segment coh_input->seg_info.segment_start = segment->start; coh_input->seg_info.segment_end = segment->end; // Decide what F-statistic quantities to compute WeaveStatisticType requested_stats = ( recalc_stage ) ? statistics_params->completionloop_statistics[1] : statistics_params->mainloop_statistics; if ( requested_stats & WEAVE_STATISTIC_COH2F ) { coh_input->Fstat_what_to_compute |= FSTATQ_2F; } if ( requested_stats & WEAVE_STATISTIC_COH2F_DET ) { coh_input->Fstat_what_to_compute |= FSTATQ_2F_PER_DET; } // Return now if simulating search with minimal memory allocation if ( coh_input->simulation_level & WEAVE_SIMULATE_MIN_MEM ) { return coh_input; } // Get a timeslice of SFT catalog restricted to the given segment SFTCatalog XLAL_INIT_DECL( sft_catalog_seg ); XLAL_CHECK_NULL( XLALSFTCatalogTimeslice( &sft_catalog_seg, sft_catalog, &segment->start, &segment->end ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK_NULL( sft_catalog_seg.length > 0, XLAL_EINVAL, "No SFTs found in segment %u", segment_index ); // Check that the number of SFTs in each segment matches the number provided by the segment list in the setup file, if nonzero const UINT4 sft_count = ( UINT4 ) segment->id; XLAL_CHECK_NULL( sft_count == 0 || sft_catalog_seg.length == sft_count, XLAL_EFAILED, "Number of SFTs found for segment %u (%u) is inconsistent with expected number of SFTs given by segment list (%u)", segment_index, sft_catalog_seg.length, sft_count ); // Get list of detectors of SFT catalog in this segment LALStringVector *sft_catalog_seg_detectors = XLALListIFOsInCatalog( &sft_catalog_seg ); XLAL_CHECK_NULL( sft_catalog_seg_detectors != NULL, XLAL_EFUNC ); // Compute frequency range covered by spindown range over in the given segment LIGOTimeGPS sft_start = sft_catalog_seg.data[0].header.epoch; LIGOTimeGPS sft_end = sft_catalog_seg.data[sft_catalog_seg.length - 1].header.epoch; const double sft_end_timebase = 1.0 / sft_catalog_seg.data[sft_catalog_seg.length - 1].header.deltaF; XLALGPSAdd( &sft_end, sft_end_timebase ); PulsarSpinRange XLAL_INIT_DECL( spin_range ); XLAL_CHECK_NULL( XLALInitPulsarSpinRangeFromSpins( &spin_range, &min_phys->refTime, min_phys->fkdot, max_phys->fkdot ) == XLAL_SUCCESS, XLAL_EFUNC ); double sft_min_cover_freq = 0, sft_max_cover_freq = 0; XLAL_CHECK_NULL( XLALCWSignalCoveringBand( &sft_min_cover_freq, &sft_max_cover_freq, &sft_start, &sft_end, &spin_range, 0, 0, 0 ) == XLAL_SUCCESS, XLAL_EFUNC ); // Parse SFT noise sqrt(Sh) string vector for detectors in this segment // - This is important when segments contain data from a subset of detectors MultiNoiseFloor Fstat_injectSqrtSX; if ( sft_noise_sqrtSX != NULL ) { XLAL_CHECK_NULL( XLALParseMultiNoiseFloorMapped( &Fstat_injectSqrtSX, sft_catalog_seg_detectors, sft_noise_sqrtSX, setup_detectors ) == XLAL_SUCCESS, XLAL_EFUNC ); Fstat_opt_args->injectSqrtSX = &Fstat_injectSqrtSX; } // Parse F-statistic assumed sqrt(Sh) string vector for detectors in this segment // - This is important when segments contain data from a subset of detectors MultiNoiseFloor Fstat_assumeSqrtSX; if ( Fstat_assume_sqrtSX != NULL ) { XLAL_CHECK_NULL( XLALParseMultiNoiseFloorMapped( &Fstat_assumeSqrtSX, sft_catalog_seg_detectors, Fstat_assume_sqrtSX, setup_detectors ) == XLAL_SUCCESS, XLAL_EFUNC ); Fstat_opt_args->assumeSqrtSX = &Fstat_assumeSqrtSX; } // Load F-statistic input data coh_input->Fstat_input = XLALCreateFstatInput( &sft_catalog_seg, sft_min_cover_freq, sft_max_cover_freq, dfreq, ephemerides, Fstat_opt_args ); XLAL_CHECK_NULL( coh_input->Fstat_input != NULL, XLAL_EFUNC ); Fstat_opt_args->prevInput = coh_input->Fstat_input; // Map detectors in F-statistic data in the given segment to their index in the coherent results // - This is important when segments contain data from a subset of detectors // - Map entry 'i' in 'Fstat_detector_info' (F-statistic data) to entry 'idx' in 'detectors' (coherent results) if ( coh_input->Fstat_what_to_compute & FSTATQ_2F_PER_DET ) { const MultiLALDetector *Fstat_detector_info = XLALGetFstatInputDetectors( coh_input->Fstat_input ); coh_input->Fstat_ndetectors = Fstat_detector_info->length; char *statistics_detectors_string = XLALConcatStringVector( statistics_params->detectors, "," ); for ( size_t i = 0; i < coh_input->Fstat_ndetectors; ++i ) { const char *prefix = Fstat_detector_info->sites[i].frDetector.prefix; const int idx = XLALFindStringInVector( prefix, statistics_params->detectors ); XLAL_CHECK_NULL( idx >= 0, XLAL_EFAILED, "Detector '%s' from F-statistic data not found in list of detectors '%s'", prefix, statistics_detectors_string ); coh_input->Fstat_res_idx[i] = idx; } XLALFree( statistics_detectors_string ); } // Record information from SFTs in the given segment { MultiSFTCatalogView *sft_catalog_seg_view = XLALGetMultiSFTCatalogView( &sft_catalog_seg ); XLAL_CHECK_NULL( sft_catalog_seg_view != NULL, XLAL_EINVAL ); for ( size_t j = 0; j < sft_catalog_seg_view->length; ++j ) { XLAL_CHECK_NULL( sft_catalog_seg_view->data[j].length > 0, XLAL_EINVAL ); char *detector_name = XLALGetChannelPrefix( sft_catalog_seg_view->data[j].data[0].header.name ); XLAL_CHECK_NULL( detector_name != NULL, XLAL_EFUNC ); const int k = XLALFindStringInVector( detector_name, sft_catalog_seg_detectors ); if ( k >= 0 ) { const UINT4 length = sft_catalog_seg_view->data[j].length; coh_input->seg_info.sft_first[k] = sft_catalog_seg_view->data[j].data[0].header.epoch; coh_input->seg_info.sft_last[k] = sft_catalog_seg_view->data[j].data[length - 1].header.epoch; coh_input->seg_info.sft_count[k] = length; } XLALFree( detector_name ); } XLALDestroyMultiSFTCatalogView( sft_catalog_seg_view ); } XLAL_CHECK_NULL( XLALGetFstatInputSFTBand( coh_input->Fstat_input, &coh_input->seg_info.sft_min_freq, &coh_input->seg_info.sft_max_freq ) == XLAL_SUCCESS, XLAL_EFUNC ); // Cleanup XLALDestroyStringVector( sft_catalog_seg_detectors ); return coh_input; }
// ---------- main ---------- int main ( int argc, char *argv[] ) { XLAL_CHECK ( argc == 1, XLAL_EINVAL, "No input arguments allowed.\n" ); XLAL_CHECK ( argv != NULL, XLAL_EINVAL ); // ----- load ephemeris EphemerisData *ephem; XLAL_CHECK ( (ephem = XLALInitBarycenter ( TEST_DATA_DIR "earth00-19-DE405.dat.gz", TEST_DATA_DIR "sun00-19-DE405.dat.gz" )) != NULL, XLAL_EFUNC ); // ----- setup injection and data parameters LALStringVector *detNames = NULL; XLAL_CHECK ( (detNames = XLALCreateStringVector ( "H1", "L1", NULL )) != NULL, XLAL_EFUNC ); UINT4 numDetectors = detNames->length; // generate and assume some gaussian noise floors MultiNoiseFloor XLAL_INIT_DECL(injectSqrtSX); MultiNoiseFloor XLAL_INIT_DECL(assumeSqrtSX); injectSqrtSX.length = numDetectors; assumeSqrtSX.length = numDetectors; for ( UINT4 X = 0; X < numDetectors; X ++ ) { injectSqrtSX.sqrtSn[X] = 0; // don't inject random noise to keep errors deterministic and informative (resampling differs much more on noise) assumeSqrtSX.sqrtSn[X] = 1.0 + 2.0*X; } LIGOTimeGPS startTime = {711595934, 0}; REAL8 Tspan = 20 * 3600; LIGOTimeGPS endTime = startTime; XLALGPSAdd( &endTime, Tspan ); REAL8 Tsft = 1800; LIGOTimeGPS refTime = { startTime.gpsSeconds - 2.3 * Tspan, 0 }; MultiLIGOTimeGPSVector *multiTimestamps; XLAL_CHECK ( ( multiTimestamps = XLALCalloc ( 1, sizeof(*multiTimestamps))) != NULL, XLAL_ENOMEM ); XLAL_CHECK ( ( multiTimestamps->data = XLALCalloc ( numDetectors, sizeof(multiTimestamps->data[0]) )) != NULL, XLAL_ENOMEM ); multiTimestamps->length = numDetectors; LIGOTimeGPS startTimeX = startTime; for ( UINT4 X=0; X < numDetectors; X ++ ) { XLAL_CHECK ( (multiTimestamps->data[X] = XLALMakeTimestamps ( startTimeX, Tspan, Tsft, 0 ) ) != NULL, XLAL_EFUNC ); XLALGPSAdd ( &startTimeX, 0.5 * Tspan ); // shift start-times by 1/2 Tspan for each detector Tspan *= 2.0; } // for X < numDetectors // shift a few timestamps around to create gaps UINT4 numSFTsPerDet = multiTimestamps->data[0]->length; multiTimestamps->data[0]->data[numSFTsPerDet-1].gpsSeconds += 10000; multiTimestamps->data[0]->data[numSFTsPerDet-2].gpsSeconds += 5000; multiTimestamps->data[1]->data[0].gpsSeconds -= 10000; multiTimestamps->data[1]->data[1].gpsSeconds -= 5000; SFTCatalog *catalog; XLAL_CHECK ( (catalog = XLALMultiAddToFakeSFTCatalog ( NULL, detNames, multiTimestamps )) != NULL, XLAL_EFUNC ); // ----- CW sources to injet ---------- REAL8 Freq = 100.0; PulsarParamsVector *injectSources; XLAL_CHECK ( (injectSources = XLALCreatePulsarParamsVector(1)) != NULL, XLAL_EFUNC ); injectSources->data[0].Amp.h0 = 1; injectSources->data[0].Amp.cosi = 0.5; injectSources->data[0].Amp.psi = 0.1; injectSources->data[0].Amp.phi0 = 1.2; REAL8 asini = 0; // 1.4; // sco-X1 like REAL8 Period = 0; // 19 * 3600;// sco-X1 like REAL8 ecc = 0; // 0.1; // much larger than ScoX1 PulsarDopplerParams XLAL_INIT_DECL(Doppler); Doppler.Alpha = 0.5; Doppler.Delta = -0.5; Doppler.fkdot[0] = Freq; Doppler.fkdot[1] = -1e-9; Doppler.refTime = refTime; Doppler.asini = asini; Doppler.ecc = ecc; Doppler.tp = startTime; Doppler.period = Period; Doppler.argp = 0.5; injectSources->data[0].Doppler = Doppler; REAL8 dFreq = 0.1 / Tspan; // 10x finer than native FFT resolution REAL8 mis = 0.5; REAL8 df1dot = sqrt( 720.0 * mis ) / (LAL_PI * Tspan * Tspan); // metric (f-projected) stepsize for given mismatch mis REAL8 dSky = 1e4 / (Freq * Tspan); // rough estimate of a 'metric' sky step, eg. Eq.(118) in \cite Prix07 REAL8 dPeriod = 3600; UINT4 numFreqBins = 1000; UINT4 numf1dotPoints = 2; UINT4 numSkyPoints = 2; UINT4 numPeriodPoints = 2; PulsarSpinRange XLAL_INIT_DECL(spinRange); spinRange.refTime = refTime; memcpy ( &spinRange.fkdot, &injectSources->data[0].Doppler.fkdot, sizeof(spinRange.fkdot) ); spinRange.fkdotBand[0] = (numFreqBins - 1)*dFreq - 10*LAL_REAL8_EPS; spinRange.fkdotBand[1] = (numf1dotPoints - 1)*df1dot - 10*LAL_REAL8_EPS; Doppler.fkdot[0] -= 0.4 * spinRange.fkdotBand[0]; REAL8 minCoverFreq, maxCoverFreq; XLAL_CHECK ( XLALCWSignalCoveringBand ( &minCoverFreq, &maxCoverFreq, &startTime, &endTime, &spinRange, asini, Period, ecc ) == XLAL_SUCCESS, XLAL_EFUNC ); // ----- setup optional Fstat arguments FstatOptionalArgs optionalArgs = FstatOptionalArgsDefaults; optionalArgs.injectSources = injectSources; optionalArgs.injectSqrtSX = &injectSqrtSX; optionalArgs.assumeSqrtSX = &assumeSqrtSX; // ----- prepare input data with injection for all available methods FstatInput *input[FMETHOD_END]; FstatResults *results[FMETHOD_END]; for ( UINT4 iMethod = FMETHOD_START; iMethod < FMETHOD_END; iMethod ++ ) { results[iMethod] = NULL; if ( !XLALFstatMethodIsAvailable(iMethod) ) { continue; } optionalArgs.FstatMethod = iMethod; XLAL_CHECK ( (input[iMethod] = XLALCreateFstatInput ( catalog, minCoverFreq, maxCoverFreq, dFreq, ephem, &optionalArgs )) != NULL, XLAL_EFUNC ); } FstatQuantities whatToCompute = (FSTATQ_2F | FSTATQ_FAFB); // ----- loop over all templates {sky, f1dot, period} for ( UINT4 iSky = 0; iSky < numSkyPoints; iSky ++ ) { for ( UINT4 if1dot = 0; if1dot < numf1dotPoints; if1dot ++ ) { for ( UINT4 iPeriod = 0; iPeriod < numPeriodPoints; iPeriod ++ ) { // ----- loop over all available methods and compare Fstat results FstatMethodType firstMethod = FMETHOD_START; for ( UINT4 iMethod = FMETHOD_START; iMethod < FMETHOD_END; iMethod ++ ) { if ( !XLALFstatMethodIsAvailable(iMethod) ) { continue; } if ( firstMethod == FMETHOD_START ) { // keep track of first available method found firstMethod = iMethod; } XLAL_CHECK ( XLALComputeFstat ( &results[iMethod], input[iMethod], &Doppler, numFreqBins, whatToCompute ) == XLAL_SUCCESS, XLAL_EFUNC ); if ( lalDebugLevel & LALINFOBIT ) { FILE *fp; char fname[1024]; XLAL_INIT_MEM ( fname ); snprintf ( fname, sizeof(fname)-1, "twoF%s-iSky%02d-if1dot%02d-iPeriod%02d.dat", XLALGetFstatMethodName(iMethod), iSky, if1dot, iPeriod ); XLAL_CHECK ( (fp = fopen ( fname, "wb" )) != NULL, XLAL_EFUNC ); for ( UINT4 k = 0; k < results[iMethod]->numFreqBins; k ++ ) { REAL8 Freq0 = results[iMethod]->doppler.fkdot[0]; REAL8 Freq_k = Freq0 + k * results[iMethod]->dFreq; if ( whatToCompute & FSTATQ_FAFB ) { fprintf ( fp, "%20.16g %10.4g %10.4g %10.4g %10.4g %10.4g\n", Freq_k, results[iMethod]->twoF[k], crealf(results[iMethod]->Fa[k]), cimagf(results[iMethod]->Fa[k]), crealf(results[iMethod]->Fb[k]), cimagf(results[iMethod]->Fb[k]) ); } else { fprintf ( fp, "%20.16g %10.4g\n", Freq_k, results[iMethod]->twoF[k] ); } } // for k < numFreqBins fclose(fp); } // if info // compare to first result if ( iMethod != firstMethod ) { XLALPrintInfo ("Comparing results between method '%s' and '%s'\n", XLALGetFstatMethodName(firstMethod), XLALGetFstatMethodName(iMethod) ); if ( compareFstatResults ( results[firstMethod], results[iMethod] ) != XLAL_SUCCESS ) { XLALPrintError ("Comparison between method '%s' and '%s' failed\n", XLALGetFstatMethodName(firstMethod), XLALGetFstatMethodName(iMethod) ); XLAL_ERROR ( XLAL_EFUNC ); } } } // for i < FMETHOD_END Doppler.period += dPeriod; } // for iPeriod < numPeriodPoints Doppler.fkdot[1] += df1dot; } // for if1dot < numf1dotPoints Doppler.Alpha += dSky; } // for iSky < numSkyPoints // free remaining memory for ( UINT4 iMethod=FMETHOD_START; iMethod < FMETHOD_END; iMethod ++ ) { if ( !XLALFstatMethodIsAvailable(iMethod) ) { continue; } XLALDestroyFstatInput ( input[iMethod] ); XLALDestroyFstatResults ( results[iMethod] ); } // for i < FMETHOD_END XLALDestroyPulsarParamsVector ( injectSources ); XLALDestroySFTCatalog ( catalog ); XLALDestroyMultiTimestamps ( multiTimestamps ); XLALDestroyStringVector ( detNames ); XLALDestroyEphemerisData ( ephem ); LALCheckMemoryLeaks(); return XLAL_SUCCESS; } // main()
/** * Unit test for metric functions XLALComputeDopplerPhaseMetric() * and XLALComputeDopplerFstatMetric() * * Initially modelled afer testMetricCodes.py script: * Check metric codes 'getMetric' 'FstatMetric' and 'FstatMetric_v2' by * comparing them against each other. * Given that they represent 3 very different implementations of * metric calculations, this provides a very powerful consistency test * */ static int test_XLALComputeDopplerMetrics ( void ) { int ret; const REAL8 tolPh = 0.01; // 1% tolerance on phase metrics [taken from testMetricCodes.py] // ----- load ephemeris const char earthEphem[] = TEST_DATA_DIR "earth00-19-DE200.dat.gz"; const char sunEphem[] = TEST_DATA_DIR "sun00-19-DE200.dat.gz"; EphemerisData *edat = XLALInitBarycenter ( earthEphem, sunEphem ); XLAL_CHECK ( edat != NULL, XLAL_EFUNC, "XLALInitBarycenter('%s','%s') failed with xlalErrno = %d\n", earthEphem, sunEphem, xlalErrno ); // ----- set test-parameters ---------- const LIGOTimeGPS startTimeGPS = { 792576013, 0 }; const REAL8 Tseg = 60000; const REAL8 Alpha = 1.0; const REAL8 Delta = 0.5; const REAL8 Freq = 100; const REAL8 f1dot = 0;// -1e-8; LALStringVector *detNames = XLALCreateStringVector ( "H1", "L1", "V1", NULL ); LALStringVector *sqrtSX = XLALCreateStringVector ( "1.0", "0.5", "1.5", NULL ); MultiLALDetector multiIFO; XLAL_CHECK ( XLALParseMultiLALDetector ( &multiIFO, detNames ) == XLAL_SUCCESS, XLAL_EFUNC ); XLALDestroyStringVector ( detNames ); MultiNoiseFloor multiNoiseFloor; XLAL_CHECK ( XLALParseMultiNoiseFloor ( &multiNoiseFloor, sqrtSX, multiIFO.length ) == XLAL_SUCCESS, XLAL_EFUNC ); XLALDestroyStringVector ( sqrtSX ); // prepare metric parameters for modern XLALComputeDopplerFstatMetric() and mid-old XLALOldDopplerFstatMetric() const DopplerCoordinateSystem coordSys = { 4, { DOPPLERCOORD_FREQ, DOPPLERCOORD_ALPHA, DOPPLERCOORD_DELTA, DOPPLERCOORD_F1DOT } }; const PulsarAmplitudeParams Amp = { 0.03, -0.3, 0.5, 0.0 }; // h0, cosi, psi, phi0 const PulsarDopplerParams dop = { .refTime = startTimeGPS, .Alpha = Alpha, .Delta = Delta, .fkdot = { Freq, f1dot }, }; LALSegList XLAL_INIT_DECL(segList); ret = XLALSegListInitSimpleSegments ( &segList, startTimeGPS, 1, Tseg ); XLAL_CHECK ( ret == XLAL_SUCCESS, XLAL_EFUNC, "XLALSegListInitSimpleSegments() failed with xlalErrno = %d\n", xlalErrno ); const DopplerMetricParams master_pars2 = { .coordSys = coordSys, .detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT, .segmentList = segList, .multiIFO = multiIFO, .multiNoiseFloor = multiNoiseFloor, .signalParams = { .Amp = Amp, .Doppler = dop }, .projectCoord = - 1, // -1==no projection .approxPhase = 0, }; // ========== BEGINNING OF TEST CALLS ========== XLALPrintWarning("\n---------- ROUND 1: ephemeris-based, single-IFO phase metrics ----------\n"); { OldDopplerMetric *metric1; DopplerPhaseMetric *metric2P; REAL8 diff_2_1; DopplerMetricParams pars2 = master_pars2; pars2.multiIFO.length = 1; // truncate to first detector pars2.multiNoiseFloor.length = 1; // truncate to first detector // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric() XLAL_CHECK ( (metric1 = XLALOldDopplerFstatMetric ( OLDMETRIC_TYPE_PHASE, &pars2, edat )) != NULL, XLAL_EFUNC ); // 2) compute metric using modern UniversalDopplerMetric module: (used in lalapps_FstatMetric_v2) XLAL_CHECK ( (metric2P = XLALComputeDopplerPhaseMetric ( &pars2, edat )) != NULL, XLAL_EFUNC ); // compare metrics against each other: 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 ); XLALPrintWarning ("diff_2_1 = %e\n", diff_2_1 ); XLALDestroyOldDopplerMetric ( metric1 ); XLALDestroyDopplerPhaseMetric ( metric2P ); } XLALPrintWarning("\n---------- ROUND 2: Ptolemaic-based, single-IFO phase metrics ----------\n"); { OldDopplerMetric *metric1; DopplerPhaseMetric *metric2P; REAL8 diff_2_1; DopplerMetricParams pars2 = master_pars2; pars2.multiIFO.length = 1; // truncate to first detector pars2.multiNoiseFloor.length = 1; // truncate to first detector pars2.detMotionType = DETMOTION_SPIN | DETMOTION_PTOLEORBIT; // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric() XLAL_CHECK ( (metric1 = XLALOldDopplerFstatMetric ( OLDMETRIC_TYPE_PHASE, &pars2, edat )) != NULL, XLAL_EFUNC ); // 2) compute metric using modern UniversalDopplerMetric module: (used in lalapps_FstatMetric_v2) XLAL_CHECK ( (metric2P = XLALComputeDopplerPhaseMetric ( &pars2, edat )) != NULL, XLAL_EFUNC ); // compare all 3 metrics against each other: 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 ); XLALPrintWarning ("diff_2_1 = %e\n", diff_2_1 ); XLALDestroyOldDopplerMetric ( metric1 ); XLALDestroyDopplerPhaseMetric ( metric2P ); } XLALPrintWarning("\n---------- ROUND 3: ephemeris-based, multi-IFO F-stat metrics ----------\n"); { OldDopplerMetric *metric1; DopplerFstatMetric *metric2F; REAL8 diff_2_1; DopplerMetricParams pars2 = master_pars2; pars2.detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT; pars2.multiIFO = multiIFO; // 3 IFOs pars2.multiNoiseFloor = multiNoiseFloor;// 3 IFOs // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric() XLAL_CHECK ( (metric1 = XLALOldDopplerFstatMetric ( OLDMETRIC_TYPE_FSTAT, &pars2, edat )) != NULL, XLAL_EFUNC ); // 2) compute metric using modern UniversalDopplerMetric module: (used in lalapps_FstatMetric_v2) XLAL_CHECK ( (metric2F = XLALComputeDopplerFstatMetric ( &pars2, edat )) != NULL, XLAL_EFUNC ); // compare both metrics against each other: 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 ); XLALPrintWarning ("gF: diff_2_1 = %e\n", diff_2_1 ); 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 ); XLALPrintWarning ("gFav: diff_2_1 = %e\n", diff_2_1 ); XLALDestroyOldDopplerMetric ( metric1 ); XLALDestroyDopplerFstatMetric ( metric2F ); } XLALPrintWarning("\n---------- ROUND 4: compare analytic {f,f1dot,f2dot,f3dot} phase metric vs XLALComputeDopplerPhaseMetric() ----------\n"); { DopplerPhaseMetric *metric2P; REAL8 diff_2_1; DopplerMetricParams pars2 = master_pars2; pars2.multiIFO.length = 1; // truncate to 1st detector pars2.multiNoiseFloor.length = 1; // truncate to 1st detector pars2.detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT; pars2.approxPhase = 1; // use same phase-approximation as in analytic solution to improve comparison DopplerCoordinateSystem coordSys2 = { 4, { DOPPLERCOORD_FREQ, DOPPLERCOORD_F1DOT, DOPPLERCOORD_F2DOT, DOPPLERCOORD_F3DOT } }; pars2.coordSys = coordSys2; gsl_matrix* gN_ij; // a) compute metric at refTime = startTime pars2.signalParams.Doppler.refTime = startTimeGPS; XLAL_CHECK ( (metric2P = XLALComputeDopplerPhaseMetric ( &pars2, edat )) != NULL, XLAL_EFUNC ); gN_ij = NULL; XLAL_CHECK ( XLALNaturalizeMetric ( &gN_ij, NULL, metric2P->g_ij, &pars2 ) == XLAL_SUCCESS, XLAL_EFUNC ); REAL8 gStart_ij[] = { 1.0/3, 2.0/3, 6.0/5, 32.0/15, \ 2.0/3, 64.0/45, 8.0/3, 512.0/105, \ 6.0/5, 8.0/3, 36.0/7, 48.0/5, \ 32.0/15, 512.0/105, 48.0/5, 4096.0/225 }; const gsl_matrix_view gStart = gsl_matrix_view_array ( gStart_ij, 4, 4 ); // compare natural-units metric against analytic solution XLAL_CHECK ( (diff_2_1 = XLALCompareMetrics ( gN_ij, &(gStart.matrix) )) < tolPh, XLAL_ETOL, "RefTime=StartTime: Error(g_ij,g_analytic)= %e exceeds tolerance of %e\n", diff_2_1, tolPh ); XLALPrintWarning ("Analytic (refTime=startTime): diff_2_1 = %e\n", diff_2_1 ); XLALDestroyDopplerPhaseMetric ( metric2P ); gsl_matrix_free ( gN_ij ); // b) compute metric at refTime = midTime pars2.signalParams.Doppler.refTime = startTimeGPS; pars2.signalParams.Doppler.refTime.gpsSeconds += Tseg / 2; XLAL_CHECK ( (metric2P = XLALComputeDopplerPhaseMetric ( &pars2, edat )) != NULL, XLAL_EFUNC ); gN_ij = NULL; XLAL_CHECK ( XLALNaturalizeMetric ( &gN_ij, NULL, metric2P->g_ij, &pars2 ) == XLAL_SUCCESS, XLAL_EFUNC ); REAL8 gMid_ij[] = { 1.0/3, 0, 1.0/5, 0, \ 0, 4.0/45, 0, 8.0/105, \ 1.0/5, 0, 1.0/7, 0, \ 0, 8.0/105, 0, 16.0/225 }; const gsl_matrix_view gMid = gsl_matrix_view_array ( gMid_ij, 4, 4 ); // compare natural-units metric against analytic solution XLAL_CHECK ( (diff_2_1 = XLALCompareMetrics ( gN_ij, &(gMid.matrix) )) < tolPh, XLAL_ETOL, "RefTime=MidTime: Error(g_ij,g_analytic)= %e exceeds tolerance of %e\n", diff_2_1, tolPh ); XLALPrintWarning ("Analytic (refTime=midTime): diff_2_1 = %e\n\n", diff_2_1 ); XLALDestroyDopplerPhaseMetric ( metric2P ); gsl_matrix_free ( gN_ij ); } XLALPrintWarning("\n---------- ROUND 5: ephemeris-based, single-IFO, segment-averaged phase metrics ----------\n"); { OldDopplerMetric *metric1; DopplerPhaseMetric *metric2P; REAL8 diff_2_1; DopplerMetricParams pars2 = master_pars2; pars2.detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT; pars2.multiIFO.length = 1; // truncate to first detector pars2.multiNoiseFloor.length = 1; // truncate to first detector pars2.approxPhase = 1; const UINT4 Nseg = 10; LALSegList XLAL_INIT_DECL(NsegList); ret = XLALSegListInitSimpleSegments ( &NsegList, startTimeGPS, Nseg, Tseg ); XLAL_CHECK ( ret == XLAL_SUCCESS, XLAL_EFUNC, "XLALSegListInitSimpleSegments() failed with xlalErrno = %d\n", xlalErrno ); pars2.segmentList = NsegList; LALSegList XLAL_INIT_DECL(segList_k); LALSeg segment_k; XLALSegListInit( &segList_k ); // prepare single-segment list containing segment k segList_k.arraySize = 1; segList_k.length = 1; segList_k.segs = &segment_k; // 1) compute metric using old FstatMetric code, now wrapped into XLALOldDopplerFstatMetric() metric1 = NULL; for (UINT4 k = 0; k < Nseg; ++k) { // setup 1-segment segment-list pointing k-th segment DopplerMetricParams pars2_k = pars2; pars2_k.segmentList = segList_k; pars2_k.segmentList.segs[0] = pars2.segmentList.segs[k]; // XLALOldDopplerFstatMetric() does not agree numerically with UniversalDopplerMetric when using refTime != startTime pars2_k.signalParams.Doppler.refTime = pars2_k.segmentList.segs[0].start; OldDopplerMetric *metric1_k; // per-segment coherent metric XLAL_CHECK ( (metric1_k = XLALOldDopplerFstatMetric ( OLDMETRIC_TYPE_PHASE, &pars2_k, edat )) != NULL, XLAL_EFUNC ); // manually correct reference time of metric1_k->g_ij; see Prix, "Frequency metric for CW searches" (2014-08-17), p. 4 const double dt = XLALGPSDiff( &(pars2_k.signalParams.Doppler.refTime), &(pars2.signalParams.Doppler.refTime) ); const double gFF = gsl_matrix_get( metric1_k->g_ij, 0, 0 ); const double gFA = gsl_matrix_get( metric1_k->g_ij, 0, 1 ); const double gFD = gsl_matrix_get( metric1_k->g_ij, 0, 2 ); const double gFf = gsl_matrix_get( metric1_k->g_ij, 0, 3 ); const double gAf = gsl_matrix_get( metric1_k->g_ij, 1, 3 ); const double gDf = gsl_matrix_get( metric1_k->g_ij, 2, 3 ); const double gff = gsl_matrix_get( metric1_k->g_ij, 3, 3 ); gsl_matrix_set( metric1_k->g_ij, 0, 3, gFf + gFF*dt ); gsl_matrix_set( metric1_k->g_ij, 3, 0, gsl_matrix_get( metric1_k->g_ij, 0, 3 ) ); gsl_matrix_set( metric1_k->g_ij, 1, 3, gAf + gFA*dt ); gsl_matrix_set( metric1_k->g_ij, 3, 1, gsl_matrix_get( metric1_k->g_ij, 1, 3 ) ); gsl_matrix_set( metric1_k->g_ij, 2, 3, gDf + gFD*dt ); gsl_matrix_set( metric1_k->g_ij, 3, 2, gsl_matrix_get( metric1_k->g_ij, 2, 3 ) ); gsl_matrix_set( metric1_k->g_ij, 3, 3, gff + 2*gFf*dt + gFF*dt*dt ); XLAL_CHECK ( XLALAddOldDopplerMetric ( &metric1, metric1_k ) == XLAL_SUCCESS, XLAL_EFUNC ); XLALDestroyOldDopplerMetric ( metric1_k ); } XLAL_CHECK ( XLALScaleOldDopplerMetric ( metric1, 1.0 / Nseg ) == XLAL_SUCCESS, XLAL_EFUNC ); // 2) compute metric using modern UniversalDopplerMetric module: (used in lalapps_FstatMetric_v2) XLAL_CHECK ( (metric2P = XLALComputeDopplerPhaseMetric ( &pars2, edat )) != NULL, XLAL_EFUNC ); GPMAT( metric1->g_ij, "%0.4e" ); GPMAT( metric2P->g_ij, "%0.4e" ); // compare both metrics against each other: 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 ); XLALPrintWarning ("diff_2_1 = %e\n", diff_2_1 ); XLALDestroyOldDopplerMetric ( metric1 ); XLALDestroyDopplerPhaseMetric ( metric2P ); XLALSegListClear ( &NsegList ); } XLALPrintWarning("\n---------- ROUND 6: directed binary orbital metric ----------\n"); { REAL8 Period = 68023.70496; REAL8 Omega = LAL_TWOPI / Period; REAL8 asini = 1.44; REAL8 tAsc = 897753994; REAL8 argp = 0; LIGOTimeGPS tP; XLALGPSSetREAL8 ( &tP, tAsc + argp / Omega ); const PulsarDopplerParams dopScoX1 = { .refTime = startTimeGPS, .Alpha = Alpha, .Delta = Delta, .fkdot = { Freq }, .asini = asini, .period = Period, .tp = tP }; REAL8 TspanScoX1 = 20 * 19 * 3600; // 20xPorb for long-segment regime LALSegList XLAL_INIT_DECL(segListScoX1); XLAL_CHECK ( XLALSegListInitSimpleSegments ( &segListScoX1, startTimeGPS, 1, TspanScoX1 ) == XLAL_SUCCESS, XLAL_EFUNC ); REAL8 tMid = XLALGPSGetREAL8(&startTimeGPS) + 0.5 * TspanScoX1; REAL8 DeltaMidAsc = tMid - tAsc; const DopplerCoordinateSystem coordSysScoX1 = { 6, { DOPPLERCOORD_FREQ, DOPPLERCOORD_ASINI, DOPPLERCOORD_TASC, DOPPLERCOORD_PORB, DOPPLERCOORD_KAPPA, DOPPLERCOORD_ETA } }; DopplerMetricParams pars_ScoX1 = { .coordSys = coordSysScoX1, .detMotionType = DETMOTION_SPIN | DETMOTION_ORBIT, .segmentList = segListScoX1, .multiIFO = multiIFO, .multiNoiseFloor = multiNoiseFloor, .signalParams = { .Amp = Amp, .Doppler = dopScoX1 }, .projectCoord = - 1, // -1==no projection .approxPhase = 1, }; pars_ScoX1.multiIFO.length = 1; // truncate to first detector pars_ScoX1.multiNoiseFloor.length = 1; // truncate to first detector // compute metric using modern UniversalDopplerMetric module: (used in lalapps_FstatMetric_v2) DopplerPhaseMetric *metric_ScoX1; XLAL_CHECK ( (metric_ScoX1 = XLALComputeDopplerPhaseMetric ( &pars_ScoX1, edat )) != NULL, XLAL_EFUNC ); // compute analytic metric computed from Eq.(47) in Leaci,Prix PRD91, 102003 (2015): gsl_matrix *g0_ij; XLAL_CHECK ( (g0_ij = gsl_matrix_calloc ( 6, 6 )) != NULL, XLAL_ENOMEM, "Failed to gsl_calloc a 6x6 matrix\n"); gsl_matrix_set ( g0_ij, 0, 0, pow ( LAL_PI * TspanScoX1, 2 ) / 3.0 ); gsl_matrix_set ( g0_ij, 1, 1, 2.0 * pow ( LAL_PI * Freq, 2 ) ); gsl_matrix_set ( g0_ij, 2, 2, 2.0 * pow ( LAL_PI * Freq * asini * Omega, 2 ) ); gsl_matrix_set ( g0_ij, 3, 3, 0.5 * pow ( Omega, 4 ) * pow ( Freq * asini, 2 ) * ( pow ( TspanScoX1, 2 ) / 12.0 + pow ( DeltaMidAsc, 2 ) ) ); REAL8 gPAsc = LAL_PI * pow ( Freq * asini, 2 ) * pow ( Omega, 3 ) * DeltaMidAsc; gsl_matrix_set ( g0_ij, 2, 3, gPAsc ); gsl_matrix_set ( g0_ij, 3, 2, gPAsc ); gsl_matrix_set ( g0_ij, 4, 4, 0.5 * pow ( LAL_PI * Freq * asini, 2 ) ); gsl_matrix_set ( g0_ij, 5, 5, 0.5 * pow ( LAL_PI * Freq * asini, 2 ) ); GPMAT ( metric_ScoX1->g_ij, "%0.4e" ); GPMAT ( g0_ij, "%0.4e" ); // compare metrics against each other REAL8 diff, tolScoX1 = 0.05; XLAL_CHECK ( (diff = XLALCompareMetrics ( metric_ScoX1->g_ij, g0_ij )) < tolScoX1, XLAL_ETOL, "Error(gNum,gAn)= %g exceeds tolerance of %g\n", diff, tolScoX1 ); XLALPrintWarning ("diff_Num_An = %e\n", diff ); gsl_matrix_free ( g0_ij ); XLALDestroyDopplerPhaseMetric ( metric_ScoX1 ); XLALSegListClear ( &segListScoX1 ); }