35#include <lal/LALStdlib.h>
36#include <lal/LALStdio.h>
37#include <lal/UserInput.h>
38#include <lal/LogPrintf.h>
40#include <lal/TimeSeries.h>
41#include <lal/BandPassTimeSeries.h>
42#include <lal/Window.h>
43#include <lal/RealFFT.h>
44#include <lal/SFTfileIO.h>
45#include <lal/LALFrStream.h>
46#include <lal/LALVCSInfo.h>
47#include <lal/LALPulsarVCSInfo.h>
51int main(
int argc,
char *argv[] )
72 REAL8 overlap_fraction;
81 UINT4 observing_revision;
86 .overlap_fraction = 0,
91 .sft_write_path = default_sft_write_path,
92 .allow_skipping =
false,
102 frame_cache,
STRING,
'C', REQUIRED,
103 "Path to frame cache file to read frames from. "
106 frame_checksums,
BOOLEAN,
'k', OPTIONAL,
107 "Validate frame checksums. Default is to only validate checksums for " UVAR_STR( observing_kind )
"=RUN SFTs. "
110 channel_name, STRINGVector,
'N', REQUIRED,
111 "Name(s) of channel(s) to read within a frame. "
114 gps_start_time,
INT4,
's', REQUIRED,
115 "GPS time to start generating SFTs. "
118 gps_end_time,
INT4,
'e', REQUIRED,
119 "GPS time to end generating SFTs. "
122 allow_skipping,
BOOLEAN,
'x', OPTIONAL,
123 "Channel is allowed to be skipped if it is not in frames or has too low sampling frequency. "
130 sft_duration,
INT4,
't', OPTIONAL,
131 "SFT duration in seconds. "
134 overlap_fraction,
REAL8,
'P', OPTIONAL,
135 "Fraction of SFT duration to overlap SFTs by. "
139 high_pass_freq,
REAL8,
'f', REQUIRED,
140 "High pass filtering frequency in Hertz. "
144 "Window to apply to SFTs. See https://dcc.ligo.org/T040164/public for supported options.\n\n"
145 "The standard window applied to LVK production SFTs is documented in `lalpulsar_MakeSFTDAG`. "
148 window_param,
REAL8,
'r', OPTIONAL,
149 "Parameter (if required) of window to apply to SFTs. "
152 start_freq,
REAL8,
'F', OPTIONAL,
153 "Start frequency of the SFTs, in Hertz. "
156 band,
REAL8,
'B', OPTIONAL,
157 "Frequency band of the SFTs, in Hertz. "
164 sft_write_path, STRINGVector,
'p', OPTIONAL,
165 "Path(s) to write SFTs to, same order as channel name(s). "
168 observing_run,
UINT4,
'O', REQUIRED,
169 "For >=1, SFTs will be named following the 'public' scheme from T040164-v2, and this number should correspond to the observing run the data comes from (without the leading 'O').\n\n"
170 "If set to 0, 'private' SFTs will be generated. "
173 observing_kind,
STRING,
'K', OPTIONAL,
174 "For public SFTs (" UVAR_STR( observing_run )
">=1) only, the kind of SFTs being generated: 'RUN', 'AUX', 'SIM', or 'DEV'. "
177 observing_revision,
UINT4,
'R', OPTIONAL,
178 "For public SFTs (" UVAR_STR( observing_run )
">=1) only, the revision number of the SFT production. "
181 misc_desc,
STRING,
'X', OPTIONAL,
182 "For private SFTs only, a miscellaneous description field that will be included in the filenames. "
185 comment_field,
STRING,
'c', OPTIONAL,
186 "Comment for SFT header. "
192 NULL,
"frame_struct_type",
STRING,
'u', DEFUNCT,
193 "No longer required; the frame channel type is determined automatically. "
196 NULL,
"ht_data",
BOOLEAN,
'H', DEFUNCT,
197 "No longer required; the frame channel type is determined automatically. "
200 NULL,
"ifo",
STRING,
'i', DEFUNCT,
201 "No longer required; the detector prefix is deduced from the channel name. "
204 NULL,
"make_gps_dirs",
BOOLEAN,
'D', DEFUNCT,
205 "No longer supported. "
208 NULL,
"make_tmp_file",
BOOLEAN,
'Z', DEFUNCT,
209 "Default behaviour. "
212 NULL,
"sft_version",
INT4,
'V', DEFUNCT,
213 "No longer supported. "
216 NULL,
"use_single",
BOOLEAN,
'S', DEFUNCT,
217 "No longer supported. "
220 NULL,
"window_radius",
REAL8, 0, DEFUNCT,
221 "Use " UVAR_STR( window_param )
" instead. "
237 uvar->gps_start_time > 0,
238 UVAR_STR( gps_start_time )
" must be strictly positive" );
240 uvar->gps_end_time > 0,
241 UVAR_STR( gps_end_time )
" must be strictly positive" );
246 uvar->sft_duration > 0,
247 UVAR_STR( sft_duration )
" must be strictly positive" );
249 uvar->gps_end_time - uvar->gps_start_time >= uvar->sft_duration,
250 "Cannot fit an SFT of duration %d between GPS times %d and %d\n",
251 uvar->sft_duration, uvar->gps_start_time, uvar->gps_end_time );
253 0 <= uvar->overlap_fraction && uvar->overlap_fraction < 1,
254 UVAR_STR( overlap_fraction )
" must be within range [0.0, 1.0)" );
256 uvar->high_pass_freq >= 0,
257 UVAR_STR( high_pass_freq )
" must be positive" );
258 if ( strcmp( uvar->window_type,
"0" ) == 0 ) {
261 }
else if ( strcmp( uvar->window_type,
"1" ) == 0 ) {
265 "the same window; see https://dcc.ligo.org/LIGO-T040164/public for details" );
266 }
else if ( strcmp( uvar->window_type,
"2" ) == 0 ) {
270 "although this will NOT give you exactly the same window" );
271 }
else if ( strcmp( uvar->window_type,
"3" ) == 0 ) {
280 uvar->window_param >= 0,
281 UVAR_STR( window_param )
" must be positive" );
283 uvar->start_freq >= 0,
284 UVAR_STR( start_freq )
" must be positive" );
287 UVAR_STR( band )
" must be strictly positive" );
292 uvar->observing_run == 0
295 "Must set " UVAR_STR( observing_kind )
" and " UVAR_STR( observing_revision )
" when using " UVAR_STR( observing_run )
">0" );
297 uvar->observing_run == 0
299 && ( strcmp( uvar->observing_kind,
"RUN" ) == 0
300 || strcmp( uvar->observing_kind,
"AUX" ) == 0
301 || strcmp( uvar->observing_kind,
"SIM" ) == 0
302 || strcmp( uvar->observing_kind,
"DEV" ) == 0 ) ),
303 UVAR_STR( observing_kind )
" must be one of 'RUN', 'AUX', 'SIM', or 'DEV'" );
305 uvar->observing_run == 0 || uvar->observing_revision > 0,
306 UVAR_STR( observing_revision )
" must be strictly positive" );
309 UVAR_STR( observing_run )
"=0 is mutually exclusive with " UVAR_STR( misc_desc ) );
311 uvar->observing_run > 0
314 "Setting " UVAR_STR( observing_kind )
" or " UVAR_STR( observing_revision )
" is not allowed with " UVAR_STR( observing_run )
"=0" );
316 uvar->channel_name->length == uvar->sft_write_path->length
317 || uvar->sft_write_path->length == 1,
318 "Number of channels in " UVAR_STR( channel_name )
" must be the same as the number of output paths in " UVAR_STR( sft_write_path )
"or a single path" );
320 uvar->observing_run > 0
321 || uvar->channel_name->length == 1,
322 "For private SFTs (" UVAR_STR( observing_run )
"=0), can only provide one channel at a time" );
331 bool frame_checksums =
false;
333 if ( uvar->frame_checksums ) {
334 frame_checksums =
true;
337 frame_checksums =
false;
341 if ( strcmp( uvar->observing_kind,
"RUN" ) == 0 ) {
342 frame_checksums =
true;
345 frame_checksums =
false;
349 frame_checksums =
false;
357 char *SFT_comment = NULL;
363 SFT_comment =
XLALStringAppendFmt( SFT_comment,
"Generated by %s\nVersion:\n%s\nOptions:\n%s\n", argv[0], vcs_info_str, cmd_line_str );
372 "Failed to open frame cache '%s'", uvar->frame_cache );
377 "Failed to open frame stream from cache '%s'", uvar->frame_cache );
384 if ( frame_checksums ) {
388 "Failed to set frame stream mode to %i",
mode );
392 const UINT4 SFT_first_bin = lrint( uvar->start_freq * uvar->sft_duration );
393 const UINT4 SFT_bins = lrint( uvar->band * uvar->sft_duration );
396 "Failed to allocate SFT of %u bins", SFT_bins );
405 REAL8FFTPlan *SFT_fft_plan = NULL;
408 INT4 SFT_epoch_sec = uvar->gps_start_time;
409 INT4 num_SFTs_made = 0;
415 for (
UINT4 n = 0;
n < uvar->channel_name->length;
n++ ) {
429 if ( errnum != 0 && uvar->allow_skipping ) {
430 LogPrintf(
LOG_CRITICAL,
"--require-channel=FALSE and %s is not in frames\n", uvar->channel_name->data[
n] );
433 }
else if ( errnum != 0 ) {
442 if ( errnum != 0 && uvar->allow_skipping ) {
443 LogPrintf(
LOG_CRITICAL,
"--require-channel=FALSE and %s is not in frames\n", uvar->channel_name->data[
n] );
446 }
else if ( errnum != 0 ) {
459 "XLALFrStreamInputREAL8TimeSeries() failed at GPS time %" LAL_INT4_FORMAT, SFT_epoch_sec );
467 if ( SFT_window == NULL ) {
470 "Failed to allocate SFT time series window of %u elements at GPS time %" LAL_INT4_FORMAT, SFT_time_series->
data->
length, SFT_epoch_sec );
474 if ( SFT_fft_data != NULL && SFT_fft_data->
length != SFT_time_series->
data->
length / 2 + 1 ) {
480 if ( SFT_fft_data == NULL ) {
483 "Failed to allocate SFT FFT data vector of %u elements at GPS time %" LAL_INT4_FORMAT, SFT_time_series->
data->
length / 2 + 1, SFT_epoch_sec );
486 "Failed to allocate SFT FFT plan at GPS time %" LAL_INT4_FORMAT, SFT_epoch_sec );
489 if ( SFT_fft_data->
length < SFT_bins && uvar->allow_skipping ) {
490 LogPrintf(
LOG_CRITICAL,
"Sampling rate is too low for band requested, skipping %s\n", uvar->channel_name->data[
n] );
506 if ( uvar->high_pass_freq > 0.0 ) {
507 char filtername[] =
"Butterworth High Pass";
511 .f2 = uvar->high_pass_freq,
517 "Failed to apply %s filter to SFT time series data at GPS time %" LAL_INT4_FORMAT, filterpar.
name, SFT_epoch_sec );
522 "Failed to apply window to SFT time series data at GPS time %" LAL_INT4_FORMAT, SFT_epoch_sec );
526 "Failed to Fourier transform SFT time series data at GPS time %" LAL_INT4_FORMAT, SFT_epoch_sec );
529 SFT->
name[0] = uvar->channel_name->data[
n][0];
530 SFT->
name[1] = uvar->channel_name->data[
n][1] ==
'0' ?
'1' : uvar->channel_name->data[
n][1];
533 SFT->
f0 = uvar->start_freq;
534 SFT->
deltaF = 1.0 / ( (
REAL8 ) uvar->sft_duration );
537 const REAL8 SFT_normalisation = SFT_time_series->
deltaT;
538 for (
UINT4 k = 0;
k < SFT_bins; ++
k ) {
539 const REAL8 SFT_fft_re = creal( SFT_fft_data->
data[
k + SFT_first_bin] );
540 const REAL8 SFT_fft_im = cimag( SFT_fft_data->
data[
k + SFT_first_bin] );
541 SFT->
data->
data[
k] =
crectf( SFT_normalisation * SFT_fft_re, SFT_normalisation * SFT_fft_im );
546 if ( uvar->sft_write_path->length > 1 ) {
551 spec.window_param = uvar->window_param;
552 spec.pubObsRun = uvar->observing_run;
553 spec.pubRevision = uvar->observing_revision;
556 char *temp_SFT_filename = NULL;
561 "Failed to write SFT '%s' at GPS time %" LAL_INT4_FORMAT, temp_SFT_filename ? temp_SFT_filename :
"<unknown>", SFT_epoch_sec );
567 "Failed to validate SFT '%s' at GPS time %" LAL_INT4_FORMAT, temp_SFT_filename, SFT_epoch_sec );
571 char *
const extn = strrchr( final_SFT_filename,
'.' );
574 strcpy( extn,
".sft" );
576 "Failed to rename '%s' to '%s': %s", temp_SFT_filename, final_SFT_filename, strerror( errno ) );
580 if ( ++num_SFTs_made == 1 ) {
590 if ( n < uvar->channel_name->length - 1 ) {
598 const INT4 last_SFT_epoch_sec = SFT_epoch_sec;
599 SFT_epoch_sec += ( 1.0 - uvar->overlap_fraction ) * ( (
REAL8 ) uvar->sft_duration );
600 if ( SFT_epoch_sec + uvar->sft_duration > uvar->gps_end_time ) {
int XLALButterworthREAL8TimeSeries(REAL8TimeSeries *series, PassBandParamStruc *params)
void LALCheckMemoryLeaks(void)
const LALVCSInfoList lalPulsarVCSInfoList
NULL-terminated list of VCS and build information for LALPulsar and its dependencies
int main(int argc, char *argv[])
void XLALDestroyCache(LALCache *cache)
LALCache * XLALCacheImport(const char *fname)
#define XLAL_INIT_DECL(var,...)
int XLALFrStreamSeek(LALFrStream *stream, const LIGOTimeGPS *epoch)
int XLALFrStreamSeekO(LALFrStream *stream, double dt, int whence)
int XLALFrStreamClose(LALFrStream *stream)
LALFrStream * XLALFrStreamCacheOpen(LALCache *cache)
int XLALFrStreamSetMode(LALFrStream *stream, int mode)
LAL_FR_STREAM_CHECKSUM_MODE
LAL_FR_STREAM_VERBOSE_MODE
LALTYPECODE XLALFrStreamGetTimeSeriesType(const char *chname, LALFrStream *stream)
REAL8TimeSeries * XLALFrStreamInputREAL8TimeSeries(LALFrStream *stream, const char *chname, const LIGOTimeGPS *start, double duration, size_t lengthlimit)
char char * XLALStringDuplicate(const char *s)
char * XLALStringAppendFmt(char *s, const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(2
char * XLALVCSInfoString(const LALVCSInfoList vcs_list, const int verbose, const char *prefix)
void LogPrintf(LogLevel_t, const char *format,...) _LAL_GCC_PRINTF_FORMAT_(2
int XLALREAL8ForwardFFT(COMPLEX16Vector *output, const REAL8Vector *input, const REAL8FFTPlan *plan)
void XLALDestroyREAL8FFTPlan(REAL8FFTPlan *plan)
REAL8FFTPlan * XLALCreateForwardREAL8FFTPlan(UINT4 size, int measurelvl)
SFTtype * XLALCreateSFT(UINT4 numBins)
XLAL function to create one SFT-struct.
char * XLALBuildSFTFilenameFromSpec(const SFTFilenameSpec *spec)
Build an SFT file name from the given specification.
void XLALDestroySFT(SFTtype *sft)
Destructor for one SFT.
int XLALWriteSFT2StandardFile(const SFTtype *sft, SFTFilenameSpec *SFTfnspec, const CHAR *SFTcomment)
Write the given SFTtype to a SFT file with a standard () filename.
int XLALFillSFTFilenameSpecStrings(SFTFilenameSpec *spec, const CHAR *path, const CHAR *extn, const CHAR *detector, const CHAR *window_type, const CHAR *privMisc, const CHAR *pubObsKind, const CHAR *pubChannel)
Convenience function for filling out the string fields in a SFTFilenameSpec.
int XLALCheckSFTFileIsValid(const char *fname)
Verify that the contents of a SFT file are valid.
LALStringVector * XLALCreateStringVector(const CHAR *str1,...)
void XLALDestroyREAL8TimeSeries(REAL8TimeSeries *series)
COMPLEX16Vector * XLALCreateCOMPLEX16Vector(UINT4 length)
void XLALDestroyCOMPLEX16Vector(COMPLEX16Vector *vector)
REAL8Window * XLALCreateNamedREAL8Window(const char *windowName, REAL8 beta, UINT4 length)
REAL8Sequence * XLALUnitaryWindowREAL8Sequence(REAL8Sequence *sequence, const REAL8Window *window)
void XLALDestroyREAL8Window(REAL8Window *window)
int XLALCheckNamedWindow(const char *windowName, const BOOLEAN haveBeta)
#define XLAL_CHECK_MAIN(assertion,...)
#define XLAL_ERROR_MAIN(...)
#define XLAL_TRY(statement, errnum)
Structure specifying an SFT file name, following the convention in .