56#include <lal/LALStdlib.h>
57#include <lal/LALHashTbl.h>
59#include <lal/SFTfileIO.h>
60#include <lal/SFTReferenceLibrary.h>
61#include <lal/LALPulsarVCSInfo.h>
71#define COMPARE_BY_NUM( x, y ) do { if ( (x) < (y) ) return -1; if ( (x) > (y) ) return +1; } while(0)
72#define COMPARE_BY_STR( x, y ) do { int c = strcmp( (x), (y) ); if ( c != 0 ) return c; } while(0)
105 if ( seconds > 10 ) {
108 if ( seconds == 0 ) {
119 struct stat stat_buf;
121 if (
stat( fname, &stat_buf ) ) {
125 if ( ! S_ISDIR( stat_buf.st_mode ) ) {
179 fseek( fpin, move, SEEK_CUR );
184int main(
int argc,
char **argv )
192 char *cmdline = NULL;
196 char outdir0[] =
".";
197 char *
outdir = (
char * )outdir0;
199 int firstfile =
TRUE;
200 int allcomments =
FALSE;
202 unsigned int startBin = 0, endBin = 0;
203 unsigned int width = 0, overlap = 0;
204 double fMin = -1.0, fMax = -1.0;
205 double fWidth = -1.0, fOverlap = -1;
206 unsigned int nactivesamples;
212 int assumeSorted = 0;
214 LALHashTbl *nbsfts = NULL;
223 if ( ( argv[1] == NULL ) ||
224 ( strcmp( argv[1],
"-h" ) == 0 ) ||
225 ( strcmp( argv[1],
"--help" ) == 0 ) ) {
229 " Write this help message\n"
232 " [-a|--all-comments]\n"
233 " [-c|--add-comment 0|1|2]\n"
234 " [-v|--no-validation]\n"
235 " [-s|--start-bin <startbin>]\n"
236 " [-e|--end-bin <endbin (exclusively)>]\n"
237 " [-b|--width <sftbins>]\n"
238 " [-x|--overlap <overlap>]\n"
239 " [-fs|--start-frequency <startfrequency>]\n"
240 " [-fe|--end-frequency <endfrequency (exclusively)>]\n"
241 " [-fb|--frequency-bandwidth <frequencywidth>]\n"
242 " [-fx|--frequency-overlap <frequencyoverlap>]\n"
243 " [-ts|--minStartTime <minStartTime>]\n"
244 " [-te|--maxStartTime <maxStartTime (exclusively)>]\n"
245 " [-as|--assumeSorted 1|0]\n"
246 " [-m|--factor <factor>]\n"
247 " [-n|--output-directory <outputdirectory>]\n"
248 " [--] <inputfile> ...\n"
250 " This program reads in binary SFTs and writes out narrow-banded\n"
253 " The frequency bands of the ouput SFTs (first frequency bin of first output SFT,\n"
254 " last frequency bin of last output SFT, number of bins in each output SFT)\n"
255 " and a possible overlap of the output files can be specified\n"
256 " either in bins ('-s', '-e', '-b', -'x') or Hz ('-fs', '-fe', '-fb', '-fx')\n"
257 " (or mixed - if both are given, frequency values take precedence).\n"
259 " A 'mystery factor' can be specified with '-m' option.\n"
261 " '-v' skips validation of the CRC checksum of the input files\n"
263 " The name of the output SFT follows the standard SFT filename convention, with\n"
264 " information specific to narrow-band SFTs included in the description:\n"
265 " <outdir>/<obs>-<nSFT>_<det>_<timebase>SFT_NBF<firstbin>W<binwidth>[_<misc>]-<start>-<span>.sft\n"
267 " <outdir> = output directory given by the '-n' option, default is '.'\n"
268 " <nSFT> = number of SFTs in the file\n"
269 " <obs> = 1-character observatory prefix, e.g. 'H', 'L', 'V'\n"
270 " <det> = 2-character detector prefix, e.g. 'H1', 'L1', 'V1'\n"
271 " <timebase> = time base of the SFTs, rounded to the nearest second\n"
272 " <firstbin> = first bin of the SFTs, expressed in the form\n"
273 " <firstbin> = <freq>Hz<remainder>, where\n"
274 " <freq> = <firstbin> / <timebase>, rounded down to nearest Hz\n"
275 " <remainder> = <firstbin> - <freq> * <timebase>, number of remaining bins\n"
276 " <binwidth> = bin width of the SFTs, expressed in the form\n"
277 " <binwidth> = <freq>Hz<remainder>, where\n"
278 " <freq> = <binwidth> / <timebase>, rounded down to nearest Hz\n"
279 " <remainder> = <binwidth> - <freq> * <timebase>, number of remaining bins\n"
280 " <misc> = misc description field, if any, from the input files\n"
281 " <start> = start time of the first SFT as a GPS timestamp\n"
282 " <span> = time spanned by the SFT in seconds\n"
283 " If an output file already exists, the program will append the new SFTs to them, making\n"
284 " it possible to construct the final narrow-band SFTs by running the program multiple\n"
285 " times with different input SFTs. The GPS timestamps of the input SFTs need to be in\n"
286 " ascending order to get valid merged SFT files.\n"
288 " The '-c' options specifies how to deal with comments - 0 means no comment is written\n"
289 " at all, 1 means that the comment is taken unmodified from the input SFTs, 2 (default)\n"
290 " means that the program appends its RCS id and command-line to the comment.\n"
291 " By default a comment is written only to the first SFT of a merged SFT output 'block'\n"
292 " (i.e. call to this program). Adding the option '-a' to the command line specifies that\n"
293 " instead the comment is written into every SFT in the resulting file.\n"
295 " The options 'minStartTime' and 'maxStartTime' constrain input SFTs to be read\n"
296 " according to their time stamps. Following the XLALCWGPSinRange() convention,\n"
297 " these are interpreted as half-open intervals:\n"
298 " \tminStartTime <= time stamp < maxStartTime.\n"
299 " After encountering a time stamp outside of the given range, the program jumps to\n"
300 " the next input file as specified in the input argument; i.e. time stamp constraints\n"
301 " are imposed file-wise. For a multi-SFT file, headers are checked to ensure proper\n"
302 " sorting. Mind that all timestamps refer to SFT **start** times.\n"
304 " If 'assumeSorted' is set to 1, SFT input files will be assumed to be chronologically\n"
305 " sorted, which means the program will stop as soon as an SFT located after the\n"
306 " specified range is encountered.\n"
308 " After all options (and an optional '--' separator), the input files are given, as many\n"
309 " as you wish (or the OS supports - using xargs should be simple with this command-line\n"
312 " The program adds its own VCS ID and command-line to the comment of the written SFTs,\n"
313 " a mystery factor should show up as 'xxx' there.\n",
322 strcat( cmdline,
"\n" );
323 for ( arg = 0; arg < argc; arg++ ) {
324 if ( strcmp( argv[arg],
"-m" ) == 0 ) {
327 strcat( cmdline,
"-m xxx " );
331 strcat( cmdline, argv[arg] );
332 if ( arg == argc - 1 ) {
333 strcat( cmdline,
"\n" );
335 strcat( cmdline,
" " );
341 for ( arg = 1; arg < argc; arg++ ) {
342 if ( ( strcmp( argv[arg],
"-c" ) == 0 ) ||
343 ( strcmp( argv[arg],
"--add-comment" ) == 0 ) ) {
344 add_comment = atoi( argv[++arg] );
345 }
else if ( ( strcmp( argv[arg],
"-a" ) == 0 ) ||
346 ( strcmp( argv[arg],
"--all-comments" ) == 0 ) ) {
348 }
else if ( ( strcmp( argv[arg],
"-s" ) == 0 ) ||
349 ( strcmp( argv[arg],
"--start-bin" ) == 0 ) ) {
350 startBin = atoi( argv[++arg] );
351 }
else if ( ( strcmp( argv[arg],
"-e" ) == 0 ) ||
352 ( strcmp( argv[arg],
"--end-bin" ) == 0 ) ) {
353 endBin = atoi( argv[++arg] );
354 }
else if ( ( strcmp( argv[arg],
"-b" ) == 0 ) ||
355 ( strcmp( argv[arg],
"--width" ) == 0 ) ) {
356 width = atoi( argv[++arg] );
357 }
else if ( ( strcmp( argv[arg],
"-x" ) == 0 ) ||
358 ( strcmp( argv[arg],
"--overlap" ) == 0 ) ) {
359 overlap = atoi( argv[++arg] );
360 }
else if ( ( strcmp( argv[arg],
"-fs" ) == 0 ) ||
361 ( strcmp( argv[arg],
"--start-frequency" ) == 0 ) ) {
362 fMin = atof( argv[++arg] );
363 }
else if ( ( strcmp( argv[arg],
"-fe" ) == 0 ) ||
364 ( strcmp( argv[arg],
"--end-frequency" ) == 0 ) ) {
365 fMax = atof( argv[++arg] );
366 }
else if ( ( strcmp( argv[arg],
"-fb" ) == 0 ) ||
367 ( strcmp( argv[arg],
"--frequency-bandwidth" ) == 0 ) ) {
368 fWidth = atof( argv[++arg] );
369 }
else if ( ( strcmp( argv[arg],
"-fx" ) == 0 ) ||
370 ( strcmp( argv[arg],
"--frequency-overlap" ) == 0 ) ) {
371 fOverlap = atof( argv[++arg] );
372 }
else if ( ( strcmp( argv[arg],
"-ts" ) == 0 ) ||
373 ( strcmp( argv[arg],
"--minStartTime" ) == 0 ) ) {
375 minStartTime = &userMinStartTime;
376 }
else if ( ( strcmp( argv[arg],
"-te" ) == 0 ) ||
377 ( strcmp( argv[arg],
"--maxStartTime" ) == 0 ) ) {
379 maxStartTime = &userMaxStartTime;
380 }
else if ( ( strcmp( argv[arg],
"-as" ) == 0 ) ||
381 ( strcmp( argv[arg],
"--assumeSorted" ) == 0 ) ) {
382 assumeSorted = atoi( argv[++arg] );
383 }
else if ( ( strcmp( argv[arg],
"-m" ) == 0 ) ||
384 ( strcmp( argv[arg],
"--factor" ) == 0 ) ) {
385 factor = atof( argv[++arg] );
386 }
else if ( ( strcmp( argv[arg],
"-v" ) == 0 ) ||
387 ( strcmp( argv[arg],
"--no-validation" ) == 0 ) ) {
389 }
else if ( ( strcmp( argv[arg],
"-n" ) == 0 ) ||
390 ( strcmp( argv[arg],
"--output-directory" ) == 0 ) ) {
392 }
else if ( ( strcmp( argv[arg],
"-rb" ) == 0 ) ||
393 ( strcmp( argv[arg],
"--read-bandwidth" ) == 0 ) ) {
395 }
else if ( ( strcmp( argv[arg],
"-ror" ) == 0 ) ||
396 ( strcmp( argv[arg],
"--read-open-rate" ) == 0 ) ) {
398 }
else if ( ( strcmp( argv[arg],
"-wb" ) == 0 ) ||
399 ( strcmp( argv[arg],
"--write-bandwidth" ) == 0 ) ) {
401 }
else if ( ( strcmp( argv[arg],
"-wor" ) == 0 ) ||
402 ( strcmp( argv[arg],
"--write-open-rate" ) == 0 ) ) {
404 }
else if ( strcmp( argv[arg],
"--" ) == 0 ) {
407 }
else if ( strncmp( argv[arg],
"-", 1 ) == 0 ) {
408 fprintf( stderr,
"unknown option '%s', try '-h' for help\n", argv[arg] );
416 char *constraint_str;
417 const size_t constraint_str_len = 32;
419 XLAL_ENOMEM,
"out of memory allocating constraint_str" );
420 if ( minStartTime ) {
421 XLAL_CHECK_MAIN( snprintf( constraint_str, constraint_str_len,
"%d,", minStartTime->
gpsSeconds ) < (
int )constraint_str_len,
422 XLAL_ESYS,
"output of snprintf() was truncated" );
424 XLAL_CHECK_MAIN( snprintf( constraint_str, constraint_str_len,
"," ) < (
int )constraint_str_len,
425 XLAL_ESYS,
"output of snprintf() was truncated" );
427 if ( maxStartTime ) {
428 XLAL_CHECK_MAIN( snprintf( constraint_str + strlen( constraint_str ), constraint_str_len - strlen( constraint_str ),
"%d", maxStartTime->
gpsSeconds ) < (
int )( constraint_str_len - strlen( constraint_str ) ),
429 XLAL_ESYS,
"output of snprintf() was truncated" );
445 glob( pattern, GLOB_MARK | GLOB_NOSORT, NULL, &globbuf );
446 for (
size_t i = 0;
i < globbuf.gl_pathc; ++
i ) {
463 XLALPrintInfo(
"Existing SFT: det=%s timebase=%u window=(%s,%g) priv=(%s) pub=(%i,%s,%i,%s) firstbin=(%u,%u) binwidth=(%u,%u) filename=%s\n",
467 globbuf.gl_pathv[
i] );
471 globfree( &globbuf );
475 int stopInputCauseSorted = 0;
477 for ( ; ( arg < argc ) && !stopInputCauseSorted; arg++ ) {
485 XLAL_CHECK_MAIN( ( fpin = fopen( argv[arg],
"r" ) ) != NULL,
XLAL_EIO,
"could not open SFT file for reading" );
488 int firstread =
TRUE;
489 int nSFT_this_file = 0;
495 sfterrno =
ReadSFTHeader( fpin, &hd, &oldcomment, &swap, validate );
512 XLAL_CHECK_MAIN( !( firstread && ( inRange == 1 ) ),
XLAL_EIO,
"First timestamp %d in file was after user constraint [%s)!", hd.
gps_sec, constraint_str );
514 if ( inRange == -1 ) {
518 if ( inRange == 1 ) {
519 stopInputCauseSorted = assumeSorted;
534 if ( fWidth >= 0.0 ) {
537 if ( fOverlap >= 0.0 ) {
548 "ERROR: start bin (%d) is smaller than first bin in input SFT (%d)\n",
554 if ( startBin + width > endBin + 1 ) {
556 "ERROR: end bin (%d) is larger than last bin in input SFT (%d)\n",
562 if ( overlap >= width ) {
564 "ERROR: overlap (%d) is not smaller than the width (%d)\n",
583 }
else if ( add_comment ==
CMT_OLD ) {
595 for ( nactivesamples = 0; nactivesamples < endBin - startBin; nactivesamples += width - overlap );
597 nactivesamples += overlap + 1;
605 sfterrno =
ReadSFTData( fpin,
data, startBin, nactivesamples, NULL, NULL );
609 for ( bin = 0; bin < 2 * nactivesamples; bin++ ) {
614 for ( bin = startBin; bin < endBin; bin += width - overlap ) {
620 int last_output_bin = bin + width - 1;
621 int max_input_width = last_output_bin <= last_input_bin ? width : width - ( last_output_bin - last_input_bin );
622 int max_output_width = endBin - bin + 1;
623 int this_width = max_input_width < max_output_width ? max_input_width : max_output_width;
625 int timebase = (
int ) round( hd.
tbase );
626 int outfreq = (
int )floor( bin / timebase );
627 int outfreqbin = bin - outfreq * timebase;
628 int outwidth = (
int )floor( this_width / timebase );
629 int outwidthbin = this_width - outwidth * timebase;
637 .nbFirstBinFreq = outfreq,
638 .nbFirstBinRem = outfreqbin,
639 .nbBinWidthFreq = outwidth,
640 .nbBinWidthRem = outwidthbin,
642 strncpy(
key.detector, inputSFTspec.
detector,
sizeof(
key.detector ) );
644 strncpy(
key.privMisc, inputSFTspec.
privMisc,
sizeof(
key.privMisc ) );
645 strncpy(
key.pubObsKind, inputSFTspec.
pubObsKind,
sizeof(
key.pubObsKind ) );
646 strncpy(
key.pubChannel, inputSFTspec.
pubChannel,
sizeof(
key.pubChannel ) );
647 XLALPrintInfo(
"Looking for SFT: det=%s timebase=%u window=(%s,%g) priv=(%s) pub=(%i,%s,%i,%s) firstbin=(%u,%u) binwidth=(%u,%u)\n",
648 key.detector,
key.SFTtimebase,
key.window_type,
key.window_param,
649 key.privMisc,
key.pubObsRun,
key.pubObsKind,
key.pubRevision,
key.pubChannel,
650 key.nbFirstBinFreq,
key.nbFirstBinRem,
key.nbBinWidthFreq,
key.nbBinWidthRem );
653 char *existingSFTfilename = NULL;
685 "New SFT timestamp %d is before startTime+span-timebase=%u+%u-%u=%u from existing file %s. Appending would yield an invalid merged SFT file.",
702 if ( existingSFTfilename != NULL && strcmp( existingSFTfilename, newSFTfilename ) != 0 ) {
703 XLALPrintInfo(
"Renaming SFT '%s' to '%s'\n", existingSFTfilename, newSFTfilename );
704 rename( existingSFTfilename, newSFTfilename );
708 XLALPrintInfo(
"New/updated SFT: det=%s timebase=%u window=(%s,%g) priv=(%s) pub=(%i,%s,%i,%s) firstbin=(%u,%u) binwidth=(%u,%u) filename=%s\n",
717 XLAL_CHECK_MAIN( ( fpout = fopen( newSFTfilename,
"a" ) ) != NULL,
XLAL_EIO,
"could not open SFT for writing" );
void LALCheckMemoryLeaks(void)
const LALVCSInfo lalPulsarVCSIdentInfo
Identable VCS and build information for LALPulsar.
#define XLAL_INIT_DECL(var,...)
int XLALPearsonHash(void *hval, const size_t hval_len, const void *data, const size_t data_len)
int XLALHashTblAdd(LALHashTbl *ht, void *x)
int XLALHashTblExtract(LALHashTbl *ht, const void *x, void **y)
LALHashTbl * XLALHashTblCreate(LALHashTblDtorFcn dtor, LALHashTblHashFcn hash, LALHashTblCmpFcn cmp)
void XLALHashTblDestroy(LALHashTbl *ht)
void * XLALMalloc(size_t n)
void * XLALCalloc(size_t m, size_t n)
void * XLALRealloc(void *p, size_t n)
char * XLALStringAppendFmt(char *s, const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(2
const char * SFTErrorMessage(int errorcode)
int CheckSFTHeaderConsistency(struct headertag2 *headerone, struct headertag2 *headertwo)
int ReadSFTHeader(FILE *fp, struct headertag2 *info, char **comment, int *swapendian, int validate)
int WriteSFT(FILE *fp, int gps_sec, int gps_nsec, double tbase, int firstfreqindex, int nsamples, const char *detector, unsigned short windowspec, const char *comment, float *data)
int ReadSFTData(FILE *fp, float *data, int firstbin, int nsamples, char **comment, struct headertag2 *info)
char * XLALBuildSFTFilenameFromSpec(const SFTFilenameSpec *spec)
Build an SFT file name from the given specification.
UINT4 XLALRoundFrequencyUpToSFTBin(const REAL8 freq, const REAL8 df)
Round a REAL8 frequency up to the nearest integer SFT bin number.
UINT4 XLALRoundFrequencyDownToSFTBin(const REAL8 freq, const REAL8 df)
Round a REAL8 frequency down to the nearest integer SFT bin number.
int XLALCWGPSinRange(const LIGOTimeGPS gps, const LIGOTimeGPS *minGPS, const LIGOTimeGPS *maxGPS)
Defines the official CW convention for whether a GPS time is 'within' a given range,...
int XLALParseSFTFilenameIntoSpec(SFTFilenameSpec *spec, const char *SFTpath)
Parse a SFT file path and return its specification.
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 int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_MAIN(assertion,...)
LIGOTimeGPS * XLALGPSSetREAL8(LIGOTimeGPS *epoch, REAL8 t)
static UINT8 hash_SFTFilenameSpec(const void *x)
#define COMPARE_BY_NUM(x, y)
int main(int argc, char **argv)
main program
static int is_directory(const char *fname)
UNIT_SOURCE read_bandwidth
throtteling settings
static void request_resource(UNIT_SOURCE *us, int units)
request a resurce.
UNIT_SOURCE write_open_rate
#define COMPARE_BY_STR(x, y)
static int compare_SFTFilenameSpec(const void *x, const void *y)
UNIT_SOURCE write_bandwidth
static int move_to_next_SFT(FILE *fpin, int nsamples, int comment_length)
UNIT_SOURCE read_open_rate
const char *const vcsStatus
Structure specifying an SFT file name, following the convention in .
UINT4 pubRevision
For public SFTs: revision number of SFT production.
UINT4 SFTtimebase
Timebase in seconds of the SFT; set by XLALWriteSFT[Vector]2StandardFile()
UINT4 SFTspan
Total time interval in seconds covered by SFT file; set by XLALWriteSFT[Vector]2StandardFile()
UINT4 nbBinWidthRem
For narrow-band SFTs: remainder of division of SFT bandwidth by SFT time base.
UINT4 gpsStart
GPS time in seconds at the beginning of the first SFT in the file; set by XLALWriteSFT[Vector]2Standa...
CHAR pubChannel[256]
For public SFTs: channel name of data used to make SFTs.
UINT4 nbBinWidthFreq
For narrow-band SFTs: SFT bandwidth divided by SFT time base, rounded down.
CHAR detector[3]
2-character detector prefix (e.g.
CHAR pubObsKind[4]
For public SFTs: kind of data ('RUN', 'AUX', 'SIM', 'DEV')
UINT4 nbFirstBinRem
For narrow-band SFTs: remainder of division of SFT first bin frequency by SFT time base.
UINT4 numSFTs
Number of SFTs in the file; set by XLALWriteSFT[Vector]2StandardFile()
UINT4 pubObsRun
For public SFTs: observing run number.
CHAR window_type[32]
window function applied to SFT
UINT4 nbFirstBinFreq
For narrow-band SFTs: SFT first bin frequency divided by SFT time base, rounded down.
REAL8 window_param
parameter of window function, if required
CHAR privMisc[256]
For private SFTs: miscellaneous description field.
int resource_rate
this many resource units become available in one second
int resource_units
number of resource units available for consumption
time_t last_checked
time we last checked