Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-15fff1b
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
splitSFTs.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020, 2022 Karl Wette
3 * Copyright (C) 2008, 2010 Bernd Machenschalk, Bruce Allen
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with with program; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 */
20
21/**
22 * \file
23 * \ingroup lalpulsar_bin_SFTTools
24 * \author Bernd Machenschalk, Bruce Allen
25 *
26 * \brief This program reads in binary SFTs and writes out narrow-banded merged SFTs.
27 *
28 * Writen by Bernd Machenschalk for Einstein\@home 2008
29 *
30 * Revision splitSFTs.c,v 1.41 2008/10/29 16:54:13 was
31 * reviewed by the LSC CW Review Committee Thur Oct 30, 2008
32 *
33 * Suggested improvements:
34 * issue warning at ambiguous frequency values that are so close to the boundary of a bin
35 * that rounding might end up giving an unintended bin
36 * check for consistency of input SFTs (same timebase, ascending timestamps etc., see spec)
37 * and merged SFTs (check last header of a file we are appending to)
38 *
39 * Other possible improvements not suggested by the committee
40 * keep output files open (if there aren't too many)
41 * obscure a mystery factor in command-line record even if given with long option --factor
42 */
43
44#include "config.h"
45
46#include <math.h>
47#include <time.h>
48#ifdef HAVE_UNISTD_H
49#include <unistd.h>
50#endif
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <glob.h>
55#include <sys/stat.h>
56#include <lal/LALStdlib.h>
57#include <lal/LALHashTbl.h>
58#include <lal/Date.h>
59#include <lal/SFTfileIO.h>
60#include <lal/SFTReferenceLibrary.h>
61#include <lal/LALPulsarVCSInfo.h>
62
63#define FALSE 0
64#define TRUE (!FALSE)
65
66#define CMT_NONE 0
67#define CMT_OLD 1
68#define CMT_FULL 2
69
70// Compare two quantities, and return a sort order value if they are unequal
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)
73
74typedef struct {
75 int resource_units; /**< number of resource units available for consumption */
76 int resource_rate; /**< this many resource units become available in one second */
77 time_t last_checked; /**< time we last checked */
79
80/** throtteling settings */
85
86/** request a resurce. Function returns after waiting for throttle time */
87static void request_resource( UNIT_SOURCE *us, int units )
88{
89 time_t now;
90 int seconds;
91
92 /* negative rate indicates no throttling */
93 if ( us->resource_rate <= 0 ) {
94 return;
95 }
96
97 us->resource_units -= units;
98 while ( us->resource_units <= 0 ) {
99 time( &now );
100 seconds = now - us->last_checked;
101 /* guard against overflow and condor checkpointing */
102 if ( seconds < 0 ) {
103 seconds = 0;
104 }
105 if ( seconds > 10 ) {
106 seconds = 10;
107 }
108 if ( seconds == 0 ) {
109 sleep( 1 );
110 }
111 us->resource_units += seconds * us->resource_rate;
112 us->last_checked = now;
113 }
114}
115
116/* determine if the given filepath is an existing directory or not */
117static int is_directory( const char *fname )
118{
119 struct stat stat_buf;
120
121 if ( stat( fname, &stat_buf ) ) {
122 return 0;
123 }
124
125 if ( ! S_ISDIR( stat_buf.st_mode ) ) {
126 return 0;
127 } else {
128 return 1;
129 }
130
131}
132
133/* hash an SFTFilenameSpec */
134static UINT8 hash_SFTFilenameSpec( const void *x )
135{
136 const SFTFilenameSpec *rec = ( const SFTFilenameSpec * ) x;
137 UINT4 hval = 0;
138 XLALPearsonHash( &hval, sizeof( hval ), &rec->detector, sizeof( rec->detector ) );
139 XLALPearsonHash( &hval, sizeof( hval ), &rec->SFTtimebase, sizeof( rec->SFTtimebase ) );
140 XLALPearsonHash( &hval, sizeof( hval ), &rec->window_type, sizeof( rec->window_type ) );
141 XLALPearsonHash( &hval, sizeof( hval ), &rec->window_param, sizeof( rec->window_param ) );
142 XLALPearsonHash( &hval, sizeof( hval ), &rec->privMisc, sizeof( rec->privMisc ) );
143 XLALPearsonHash( &hval, sizeof( hval ), &rec->pubObsRun, sizeof( rec->pubObsRun ) );
144 XLALPearsonHash( &hval, sizeof( hval ), &rec->pubObsKind, sizeof( rec->pubObsKind ) );
145 XLALPearsonHash( &hval, sizeof( hval ), &rec->pubRevision, sizeof( rec->pubRevision ) );
146 XLALPearsonHash( &hval, sizeof( hval ), &rec->pubChannel, sizeof( rec->pubChannel ) );
147 XLALPearsonHash( &hval, sizeof( hval ), &rec->nbFirstBinFreq, sizeof( rec->nbFirstBinFreq ) );
148 XLALPearsonHash( &hval, sizeof( hval ), &rec->nbFirstBinRem, sizeof( rec->nbFirstBinRem ) );
149 XLALPearsonHash( &hval, sizeof( hval ), &rec->nbBinWidthFreq, sizeof( rec->nbBinWidthFreq ) );
150 XLALPearsonHash( &hval, sizeof( hval ), &rec->nbBinWidthRem, sizeof( rec->nbBinWidthRem ) );
151 return hval;
152}
153
154/* compare an SFTFilenameSpec */
155static int compare_SFTFilenameSpec( const void *x, const void *y )
156{
157 const SFTFilenameSpec *recx = ( const SFTFilenameSpec * ) x;
158 const SFTFilenameSpec *recy = ( const SFTFilenameSpec * ) y;
159 COMPARE_BY_STR( recx->detector, recy->detector );
160 COMPARE_BY_NUM( recx->SFTtimebase, recy->SFTtimebase );
161 COMPARE_BY_STR( recx->window_type, recy->window_type );
163 COMPARE_BY_STR( recx->privMisc, recy->privMisc );
164 COMPARE_BY_NUM( recx->pubObsRun, recy->pubObsRun );
165 COMPARE_BY_STR( recx->pubObsKind, recy->pubObsKind );
166 COMPARE_BY_NUM( recx->pubRevision, recy->pubRevision );
167 COMPARE_BY_STR( recx->pubChannel, recy->pubChannel );
172 return 0;
173}
174
175static int move_to_next_SFT( FILE *fpin, int nsamples, int comment_length )
176{
177 int move;
178 move = sizeof( struct headertag2 ) + nsamples * 2 * sizeof( float ) + comment_length;
179 fseek( fpin, move, SEEK_CUR );
180 return XLAL_SUCCESS;
181}
182
183/** main program */
184int main( int argc, char **argv )
185{
186 int arg; /* current command-line argument */
187 unsigned int bin; /* current bin */
188 struct headertag2 hd, lasthd; /* header of input SFT */
189 FILE *fpin; /* currently open input filepointer */
190 FILE *fpout; /* currently open output filepointer */
191 char *oldcomment; /* comment of input SFT */
192 char *cmdline = NULL; /* records command-line to add it to comment */
193 char *comment = NULL; /* comment to be written into output SFT file */
194 int swap; /* do we need to swap bytes? */
195 float *data; /* SFT data */
196 char outdir0[] = ".";
197 char *outdir = ( char * )outdir0; /* output filename prefix */
198 double factor = 1.0; /* "mystery" factor */
199 int firstfile = TRUE; /* are we processing the first input SFT file? */
200 int allcomments = FALSE; /* write comment into _every_ SFT in the file */
201 int add_comment = CMT_FULL; /* add VCS ID and full command-line to every SFT file */
202 unsigned int startBin = 0, endBin = 0; /* start and end in bins */
203 unsigned int width = 0, overlap = 0; /* width and overlap in bins */
204 double fMin = -1.0, fMax = -1.0; /* start and end in Hz */
205 double fWidth = -1.0, fOverlap = -1; /* width and overlap in Hz */
206 unsigned int nactivesamples; /* number of bins to actually read in */
207 int validate = TRUE; /* validate the checksum of each input SFT before using it? */
208 LIGOTimeGPS *minStartTime = NULL; /* pointer for optional constraint */
209 LIGOTimeGPS *maxStartTime = NULL; /* pointer for optional constraint */
210 LIGOTimeGPS XLAL_INIT_DECL( userMinStartTime ); /* user-given constraint: earliest SFT timestamp to start using */
211 LIGOTimeGPS XLAL_INIT_DECL( userMaxStartTime ); /* user-given constraint: earliest SFT timestamp to no longer use */
212 int assumeSorted = 0; /* Are SFT input files chronologically sorted? */
213 int sfterrno = 0; /* SFT error number return from reference library */
214 LALHashTbl *nbsfts = NULL; /* hash table of existing narrow-band SFTs */
215
216 /* initialize throtteling */
221
222 /* help / usage message */
223 if ( ( argv[1] == NULL ) ||
224 ( strcmp( argv[1], "-h" ) == 0 ) ||
225 ( strcmp( argv[1], "--help" ) == 0 ) ) {
226 fprintf( stderr,
227 "%s -h\n"
228 "\n"
229 " Write this help message\n"
230 "\n"
231 "%s\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"
249 "\n"
250 " This program reads in binary SFTs and writes out narrow-banded\n"
251 " merged SFTs.\n"
252 "\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"
258 "\n"
259 " A 'mystery factor' can be specified with '-m' option.\n"
260 "\n"
261 " '-v' skips validation of the CRC checksum of the input files\n"
262 "\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"
266 " where\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"
287 "\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"
294 "\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"
303 "\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"
307 "\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"
310 " syntax).\n"
311 "\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",
314 argv[0], argv[0] );
315 exit( 0 );
316 }
317
318 /* record VCS ID and command-line for the comment */
319 XLAL_CHECK_MAIN( ( cmdline = ( char * )XLALMalloc( strlen( lalPulsarVCSIdentInfo.vcsId ) + strlen( lalPulsarVCSIdentInfo.vcsStatus ) + 2 ) ) != NULL, XLAL_ENOMEM, "out of memory allocating cmdline" );
320 strcpy( cmdline, lalPulsarVCSIdentInfo.vcsId );
321 strcat( cmdline, lalPulsarVCSIdentInfo.vcsStatus );
322 strcat( cmdline, "\n" );
323 for ( arg = 0; arg < argc; arg++ ) {
324 if ( strcmp( argv[arg], "-m" ) == 0 ) {
325 /* obscure the mystery factor */
326 XLAL_CHECK_MAIN( ( cmdline = ( char * )XLALRealloc( ( void * )cmdline, strlen( cmdline ) + 8 ) ) != NULL, XLAL_ENOMEM, "out of memory allocating cmdline" );
327 strcat( cmdline, "-m xxx " );
328 arg++;
329 } else {
330 XLAL_CHECK_MAIN( ( cmdline = ( char * )XLALRealloc( ( void * )cmdline, strlen( cmdline ) + strlen( argv[arg] ) + 2 ) ) != NULL, XLAL_ENOMEM, "out of memory allocating cmdline" );
331 strcat( cmdline, argv[arg] );
332 if ( arg == argc - 1 ) {
333 strcat( cmdline, "\n" );
334 } else {
335 strcat( cmdline, " " );
336 }
337 }
338 }
339
340 /* get parameters from command-line */
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 ) ) {
347 allcomments = TRUE;
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 ) ) {
374 XLAL_CHECK_MAIN( XLALGPSSetREAL8( &userMinStartTime, ( REAL8 )atof( argv[++arg] ) ) != NULL, XLAL_EDOM );
375 minStartTime = &userMinStartTime;
376 } else if ( ( strcmp( argv[arg], "-te" ) == 0 ) ||
377 ( strcmp( argv[arg], "--maxStartTime" ) == 0 ) ) {
378 XLAL_CHECK_MAIN( XLALGPSSetREAL8( &userMaxStartTime, ( REAL8 )atof( argv[++arg] ) ) != NULL, XLAL_EDOM );
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 ) ) {
388 validate = FALSE;
389 } else if ( ( strcmp( argv[arg], "-n" ) == 0 ) ||
390 ( strcmp( argv[arg], "--output-directory" ) == 0 ) ) {
391 outdir = argv[++arg];
392 } else if ( ( strcmp( argv[arg], "-rb" ) == 0 ) ||
393 ( strcmp( argv[arg], "--read-bandwidth" ) == 0 ) ) {
394 read_bandwidth.resource_rate = atoi( argv[++arg] );
395 } else if ( ( strcmp( argv[arg], "-ror" ) == 0 ) ||
396 ( strcmp( argv[arg], "--read-open-rate" ) == 0 ) ) {
397 read_open_rate.resource_rate = atoi( argv[++arg] );
398 } else if ( ( strcmp( argv[arg], "-wb" ) == 0 ) ||
399 ( strcmp( argv[arg], "--write-bandwidth" ) == 0 ) ) {
400 write_bandwidth.resource_rate = atoi( argv[++arg] );
401 } else if ( ( strcmp( argv[arg], "-wor" ) == 0 ) ||
402 ( strcmp( argv[arg], "--write-open-rate" ) == 0 ) ) {
403 write_open_rate.resource_rate = atoi( argv[++arg] );
404 } else if ( strcmp( argv[arg], "--" ) == 0 ) {
405 ++arg;
406 break;
407 } else if ( strncmp( argv[arg], "-", 1 ) == 0 ) {
408 fprintf( stderr, "unknown option '%s', try '-h' for help\n", argv[arg] );
409 exit( -1 );
410 } else {
411 break;
412 }
413 }
414
415 /* build an output string for the user timestamps constraint */
416 char *constraint_str;
417 const size_t constraint_str_len = 32; /* just needs to be big enough for two INT4 and a comma */
418 XLAL_CHECK_MAIN( ( constraint_str = ( char * )XLALMalloc( constraint_str_len ) ) != NULL,
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" );
423 } else {
424 XLAL_CHECK_MAIN( snprintf( constraint_str, constraint_str_len, "," ) < ( int )constraint_str_len,
425 XLAL_ESYS, "output of snprintf() was truncated" );
426 }
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" );
430 }
431
432 /* check if there was an input-file option given at all */
433 XLAL_CHECK_MAIN( argv[arg] != NULL, XLAL_EINVAL, "no input files specified" );
434
435 /* check output directory exists */
436 XLAL_CHECK_MAIN( is_directory( outdir ), XLAL_ESYS, "output directory does not exist" );
437
438 /* find existing narrow-band SFTs */
440 XLAL_CHECK_MAIN( nbsfts != NULL, XLAL_EFUNC, "XLALHashTblCreate() failed" );
441 {
442 char *pattern = XLALStringAppendFmt( NULL, "%s/*.sft", outdir );
443 XLAL_CHECK( pattern != NULL, XLAL_ENOMEM );
444 glob_t globbuf;
445 glob( pattern, GLOB_MARK | GLOB_NOSORT, NULL, &globbuf );
446 for ( size_t i = 0; i < globbuf.gl_pathc; ++i ) {
447
448 /* parse SFT filename */
449 SFTFilenameSpec nbSFTspec;
450 XLAL_CHECK_MAIN( XLALParseSFTFilenameIntoSpec( &nbSFTspec, globbuf.gl_pathv[i] ) == XLAL_SUCCESS, XLAL_EFUNC );
451
452 /* filter the narrow-band SFTs */
453 if ( nbSFTspec.nbFirstBinFreq == 0 ) {
454 continue;
455 }
456
457 /* create new SFT record */
458 SFTFilenameSpec *rec = NULL;
459 XLAL_CHECK_MAIN( ( rec = XLALMalloc( sizeof( *rec ) ) ) != NULL, XLAL_ENOMEM, "out of memory allocating SFT record" );
460 *rec = nbSFTspec;
461
462 /* add SFT record */
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",
464 rec->detector, rec->SFTtimebase, rec->window_type, rec->window_param,
465 rec->privMisc, rec->pubObsRun, rec->pubObsKind, rec->pubRevision, rec->pubChannel,
467 globbuf.gl_pathv[i] );
468 XLAL_CHECK_MAIN( XLALHashTblAdd( nbsfts, rec ) == XLAL_SUCCESS, XLAL_EFUNC, "XLALHashTblAdd() failed" );
469
470 }
471 globfree( &globbuf );
472 XLALFree( pattern );
473 }
474
475 int stopInputCauseSorted = 0;
476 /* loop over all input SFT files */
477 for ( ; ( arg < argc ) && !stopInputCauseSorted; arg++ ) {
478
479 /* parse SFT filename */
480 SFTFilenameSpec inputSFTspec;
481 XLAL_CHECK_MAIN( XLALParseSFTFilenameIntoSpec( &inputSFTspec, argv[arg] ) == XLAL_SUCCESS, XLAL_EFUNC );
482
483 /* open input SFT file */
485 XLAL_CHECK_MAIN( ( fpin = fopen( argv[arg], "r" ) ) != NULL, XLAL_EIO, "could not open SFT file for reading" );
486
487 /* loop until end of input SFT file, when ReadSFTHeader() will return SFTENONE */
488 int firstread = TRUE;
489 int nSFT_this_file = 0;
490 while ( 1 ) {
491
492 /* read header, break if ReadSFTHeader() returns SFTENONE
493 (unless this is the first read, i.e. fail is SFT file is completely empty) */
495 sfterrno = ReadSFTHeader( fpin, &hd, &oldcomment, &swap, validate );
496 if ( !firstread ) {
497 if ( sfterrno == SFTENONE ) {
498 break;
499 }
500 }
501 XLAL_CHECK_MAIN( sfterrno == 0, XLAL_EIO, "could not read SFT header: %s", SFTErrorMessage( sfterrno ) );
502
503 /* Check that various bits of header information are consistent.
504 * This includes a check for monotonic increasing timestamps.
505 */
506 XLAL_CHECK_MAIN( firstread || !( sfterrno = CheckSFTHeaderConsistency( &lasthd, &hd ) ), XLAL_EIO, "Inconsistent SFT headers: %s", SFTErrorMessage( sfterrno ) );
507 lasthd = hd; /* keep copy of header for comparison the next time */
508
509 /* only use SFTs within specified ranges */
510 LIGOTimeGPS startTimeGPS = {hd.gps_sec, 0};
511 int inRange = XLALCWGPSinRange( startTimeGPS, minStartTime, maxStartTime );
512 XLAL_CHECK_MAIN( !( firstread && ( inRange == 1 ) ), XLAL_EIO, "First timestamp %d in file was after user constraint [%s)!", hd.gps_sec, constraint_str );
513 firstread = FALSE;
514 if ( inRange == -1 ) { /* input timestamp too early, skip */
516 continue;
517 }
518 if ( inRange == 1 ) { /* input timestamp too late, stop with this file */
519 stopInputCauseSorted = assumeSorted;
520 break;
521 }
522 nSFT_this_file += 1;
523
524 /* calculate bins from frequency parameters if they were given */
525 /* deltaF = 1.0 / tbase; bins = freq / deltaF => bins = freq * tbase */
526 {
527 const double deltaF = 1.0 / hd.tbase;
528 if ( fMin >= 0.0 ) {
530 }
531 if ( fMax >= 0.0 ) {
532 endBin = XLALRoundFrequencyUpToSFTBin( fMax, deltaF ) - 1;
533 }
534 if ( fWidth >= 0.0 ) {
535 width = XLALRoundFrequencyUpToSFTBin( fWidth, deltaF );
536 }
537 if ( fOverlap >= 0.0 ) {
538 overlap = XLALRoundFrequencyUpToSFTBin( fOverlap, deltaF );
539 }
540 }
541
542 /* allocate space for SFT data */
543 XLAL_CHECK_MAIN( ( data = ( float * )XLALCalloc( hd.nsamples, 2 * sizeof( float ) ) ) != NULL, XLAL_ENOMEM, "out of memory allocating data" );
544
545 /* error if desired start bin < hd.firstfreqindex */
546 if ( ( int )startBin < hd.firstfreqindex ) {
547 fprintf( stderr,
548 "ERROR: start bin (%d) is smaller than first bin in input SFT (%d)\n",
549 startBin, hd.firstfreqindex );
550 exit( 9 );
551 }
552
553 /* error if desired end bin > hd.firstfreqindex + hd.nsamples - 1 */
554 if ( startBin + width > endBin + 1 ) {
555 fprintf( stderr,
556 "ERROR: end bin (%d) is larger than last bin in input SFT (%d)\n",
557 endBin, hd.firstfreqindex + hd.nsamples - 1 );
558 exit( 10 );
559 }
560
561 /* error if overlap is larger than the width */
562 if ( overlap >= width ) {
563 fprintf( stderr,
564 "ERROR: overlap (%d) is not smaller than the width (%d)\n",
565 overlap, width );
566 exit( 11 );
567 }
568
569 /* construct comment for output SFTs */
570 if ( add_comment > CMT_OLD ) {
571
572 /* allocate space for new comment */
573 XLAL_CHECK_MAIN( ( comment = ( char * )XLALMalloc( hd.comment_length + strlen( cmdline ) + 1 ) ) != NULL, XLAL_ENOMEM, "out of memory allocating comment" );
574
575 /* append the commandline of this program to the old comment */
576 if ( oldcomment ) {
577 strcpy( comment, oldcomment );
578 } else {
579 *comment = '\0';
580 }
581 strcat( comment, cmdline );
582
583 } else if ( add_comment == CMT_OLD ) {
584
585 /* only copied existing comment, no additional space needed */
586 comment = oldcomment;
587
588 } /* else (add_comment == CMT_NONE) and (comment == NULL) i.e. no comment at all */
589
590 /* get the detector name from SFT header */
591 const char detector[] = { hd.detector[0], hd.detector[1], 0 };
592
593 /* calculate number of bins to actually read (from width + overlap) */
594 /* add width-overlap samples as lon as they are < the total number og bins to write */
595 for ( nactivesamples = 0; nactivesamples < endBin - startBin; nactivesamples += width - overlap );
596 /* add the last overlap */
597 nactivesamples += overlap + 1;
598 /* if this number is larger than the bins in the input sft, just use the latter */
599 if ( nactivesamples > hd.nsamples + hd.firstfreqindex - startBin ) {
600 nactivesamples = hd.nsamples + hd.firstfreqindex - startBin;
601 }
602
603 /* read in SFT bins */
604 request_resource( &read_bandwidth, nactivesamples * 8 );
605 sfterrno = ReadSFTData( fpin, data, startBin, nactivesamples, NULL, NULL );
606 XLAL_CHECK_MAIN( sfterrno == 0, XLAL_EIO, "could not read SFT data: %s", SFTErrorMessage( sfterrno ) );
607
608 /* apply mystery factor and possibly normalization factor */
609 for ( bin = 0; bin < 2 * nactivesamples; bin++ ) {
610 data[bin] *= factor;
611 }
612
613 /* loop over start bins for output SFTs */
614 for ( bin = startBin; bin < endBin; bin += width - overlap ) {
615 /* determine the number of bins actually to write from the desired 'width',
616 given that the remaining number of bin may be odd (especially from overlapping)
617 and the bins to write need to be present in the input sft
618 */
619 int last_input_bin = hd.firstfreqindex + hd.nsamples - 1;
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;
624
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;
630
631 /* check if this narrow-band SFT exists */
633 .SFTtimebase = inputSFTspec.SFTtimebase,
634 .window_param = inputSFTspec.window_param,
635 .pubObsRun = inputSFTspec.pubObsRun,
636 .pubRevision = inputSFTspec.pubRevision,
637 .nbFirstBinFreq = outfreq,
638 .nbFirstBinRem = outfreqbin,
639 .nbBinWidthFreq = outwidth,
640 .nbBinWidthRem = outwidthbin,
641 };
642 strncpy( key.detector, inputSFTspec.detector, sizeof( key.detector ) );
643 strncpy( key.window_type, inputSFTspec.window_type, sizeof( key.window_type ) );
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 );
651 SFTFilenameSpec *rec = NULL;
652 XLAL_CHECK_MAIN( XLALHashTblExtract( nbsfts, &key, ( void ** ) &rec ) == XLAL_SUCCESS, XLAL_EFUNC, "XLALHashTblExtract() failed" );
653 char *existingSFTfilename = NULL;
654 if ( rec == NULL ) {
655
656 /* create new SFT record, starting from input SFT filename */
657 XLAL_CHECK_MAIN( ( rec = XLALCalloc( 1, sizeof( *rec ) ) ) != NULL, XLAL_ENOMEM, "out of memory allocating SFT record" );
658 *rec = inputSFTspec;
659
660 /* change to output directory */
661 XLAL_CHECK_MAIN( XLALFillSFTFilenameSpecStrings( rec, outdir, NULL, NULL, NULL, NULL, NULL, NULL ) == XLAL_SUCCESS, XLAL_EFUNC );
662
663 /* zero number of SFTs & SFT span (to be updated) */
664 rec->numSFTs = 0;
665 rec->SFTspan = 0;
666
667 /* set starting GPS time from header (respecting -ts, -te) */
668 rec->gpsStart = hd.gps_sec;
669
670 /* add narrow-band fields */
671 rec->nbFirstBinFreq = outfreq;
672 rec->nbFirstBinRem = outfreqbin;
673 rec->nbBinWidthFreq = outwidth;
674 rec->nbBinWidthRem = outwidthbin;
675
676 } else {
677
678 /* reconstruct filename of existing SFT */
679 existingSFTfilename = XLALBuildSFTFilenameFromSpec( rec );
680 XLAL_CHECK( existingSFTfilename != NULL, XLAL_EFUNC );
681
682 /* check if added record would break increasing timestamps */
683 int rec_last_gpsStart = rec->gpsStart + rec->SFTspan - rec->SFTtimebase;
684 XLAL_CHECK_MAIN( hd.gps_sec >= rec_last_gpsStart, XLAL_EDOM,
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.",
686 hd.gps_sec, rec->gpsStart, rec->SFTspan, rec->SFTtimebase, rec_last_gpsStart, existingSFTfilename );
687
688 }
689
690 /* update number of SFTs and SFT timespan */
691 rec->numSFTs += 1;
692 rec->SFTspan = hd.gps_sec - rec->gpsStart + rec->SFTtimebase;
693 if ( hd.gps_nsec > 0 ) {
694 rec->SFTspan += 1;
695 }
696
697 /* construct filename for this output SFT */
698 char *newSFTfilename = XLALBuildSFTFilenameFromSpec( rec );
699 XLAL_CHECK( newSFTfilename != NULL, XLAL_EFUNC );
700
701 /* update SFT filename */
702 if ( existingSFTfilename != NULL && strcmp( existingSFTfilename, newSFTfilename ) != 0 ) {
703 XLALPrintInfo( "Renaming SFT '%s' to '%s'\n", existingSFTfilename, newSFTfilename );
704 rename( existingSFTfilename, newSFTfilename );
705 }
706
707 /* store new SFT record */
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",
709 rec->detector, rec->SFTtimebase, rec->window_type, rec->window_param,
710 rec->privMisc, rec->pubObsRun, rec->pubObsKind, rec->pubRevision, rec->pubChannel,
712 newSFTfilename );
713 XLAL_CHECK_MAIN( XLALHashTblAdd( nbsfts, rec ) == XLAL_SUCCESS, XLAL_EFUNC, "XLALHashTblAdd() failed" );
714
715 /* append this SFT */
717 XLAL_CHECK_MAIN( ( fpout = fopen( newSFTfilename, "a" ) ) != NULL, XLAL_EIO, "could not open SFT for writing" );
718
719 /* write the data */
720 /* write the comment only to the first SFT of a "block", i.e. of a call of this program */
721 request_resource( &write_bandwidth, 40 + this_width * 8 );
722 sfterrno = WriteSFT( fpout, hd.gps_sec, hd.gps_nsec, hd.tbase, bin, this_width, detector, hd.windowspec, ( firstfile || allcomments ) ? comment : NULL, data + 2 * ( bin - startBin ) );
723 XLAL_CHECK_MAIN( sfterrno == 0, XLAL_EIO, "could not write SFT data: %s", SFTErrorMessage( sfterrno ) );
724
725 /* close output SFT file */
726 fclose( fpout );
727
728 XLALFree( existingSFTfilename );
729 XLALFree( newSFTfilename );
730
731 } /* loop over output SFTs */
732
733 /* cleanup */
734 if ( add_comment > CMT_OLD ) {
735 XLALFree( comment );
736 }
737 XLALFree( data );
738
739 /* next file is not the first file anymore */
740 firstfile = FALSE;
741
742 /* Move forward to next SFT in merged file */
744
745 } /* end loop over SFTs in this file */
746
747 XLAL_CHECK_MAIN( nSFT_this_file > 0, XLAL_EIO, "Found no matching SFTs in file." );
748
749 /* close the input SFT file */
750 fclose( fpin );
751
752 } /* loop over input SFT files */
753
754 /* cleanup */
755 XLALFree( constraint_str );
756 if ( add_comment > CMT_OLD ) {
757 XLALFree( cmdline );
758 }
759 XLALHashTblDestroy( nbsfts );
761
762 return ( 0 );
763}
void LALCheckMemoryLeaks(void)
const LALVCSInfo lalPulsarVCSIdentInfo
Identable VCS and build information for LALPulsar.
const char * comment
Definition: SearchTiming.c:94
#define fprintf
uint64_t UINT8
double REAL8
#define XLAL_INIT_DECL(var,...)
uint32_t UINT4
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)
void XLALFree(void *p)
char * XLALStringAppendFmt(char *s, const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(2
const char * SFTErrorMessage(int errorcode)
#define SFTENONE
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.
Definition: SFTnaming.c:302
UINT4 XLALRoundFrequencyUpToSFTBin(const REAL8 freq, const REAL8 df)
Round a REAL8 frequency up to the nearest integer SFT bin number.
Definition: SFTtypes.c:82
UINT4 XLALRoundFrequencyDownToSFTBin(const REAL8 freq, const REAL8 df)
Round a REAL8 frequency down to the nearest integer SFT bin number.
Definition: SFTtypes.c:70
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,...
Definition: SFTtypes.c:52
int XLALParseSFTFilenameIntoSpec(SFTFilenameSpec *spec, const char *SFTpath)
Parse a SFT file path and return its specification.
Definition: SFTnaming.c:463
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.
Definition: SFTnaming.c:257
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_MAIN(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_ESYS
XLAL_EINVAL
LIGOTimeGPS * XLALGPSSetREAL8(LIGOTimeGPS *epoch, REAL8 t)
float data[BLOCKSIZE]
Definition: hwinject.c:360
list y
key
def now
int deltaF
static UINT8 hash_SFTFilenameSpec(const void *x)
Definition: splitSFTs.c:134
#define COMPARE_BY_NUM(x, y)
Definition: splitSFTs.c:71
int main(int argc, char **argv)
main program
Definition: splitSFTs.c:184
static int is_directory(const char *fname)
Definition: splitSFTs.c:117
UNIT_SOURCE read_bandwidth
throtteling settings
Definition: splitSFTs.c:81
static void request_resource(UNIT_SOURCE *us, int units)
request a resurce.
Definition: splitSFTs.c:87
UNIT_SOURCE write_open_rate
Definition: splitSFTs.c:84
#define TRUE
Definition: splitSFTs.c:64
#define FALSE
Definition: splitSFTs.c:63
#define COMPARE_BY_STR(x, y)
Definition: splitSFTs.c:72
static int compare_SFTFilenameSpec(const void *x, const void *y)
Definition: splitSFTs.c:155
#define CMT_OLD
Definition: splitSFTs.c:67
#define CMT_FULL
Definition: splitSFTs.c:68
UNIT_SOURCE write_bandwidth
Definition: splitSFTs.c:83
static int move_to_next_SFT(FILE *fpin, int nsamples, int comment_length)
Definition: splitSFTs.c:175
UNIT_SOURCE read_open_rate
Definition: splitSFTs.c:82
const char *const vcsStatus
const char *const vcsId
Structure specifying an SFT file name, following the convention in .
Definition: SFTfileIO.h:266
UINT4 pubRevision
For public SFTs: revision number of SFT production.
Definition: SFTfileIO.h:279
UINT4 SFTtimebase
Timebase in seconds of the SFT; set by XLALWriteSFT[Vector]2StandardFile()
Definition: SFTfileIO.h:271
UINT4 SFTspan
Total time interval in seconds covered by SFT file; set by XLALWriteSFT[Vector]2StandardFile()
Definition: SFTfileIO.h:275
UINT4 nbBinWidthRem
For narrow-band SFTs: remainder of division of SFT bandwidth by SFT time base.
Definition: SFTfileIO.h:284
UINT4 gpsStart
GPS time in seconds at the beginning of the first SFT in the file; set by XLALWriteSFT[Vector]2Standa...
Definition: SFTfileIO.h:274
CHAR pubChannel[256]
For public SFTs: channel name of data used to make SFTs.
Definition: SFTfileIO.h:280
UINT4 nbBinWidthFreq
For narrow-band SFTs: SFT bandwidth divided by SFT time base, rounded down.
Definition: SFTfileIO.h:283
CHAR detector[3]
2-character detector prefix (e.g.
Definition: SFTfileIO.h:270
CHAR pubObsKind[4]
For public SFTs: kind of data ('RUN', 'AUX', 'SIM', 'DEV')
Definition: SFTfileIO.h:278
UINT4 nbFirstBinRem
For narrow-band SFTs: remainder of division of SFT first bin frequency by SFT time base.
Definition: SFTfileIO.h:282
UINT4 numSFTs
Number of SFTs in the file; set by XLALWriteSFT[Vector]2StandardFile()
Definition: SFTfileIO.h:269
UINT4 pubObsRun
For public SFTs: observing run number.
Definition: SFTfileIO.h:277
CHAR window_type[32]
window function applied to SFT
Definition: SFTfileIO.h:272
UINT4 nbFirstBinFreq
For narrow-band SFTs: SFT first bin frequency divided by SFT time base, rounded down.
Definition: SFTfileIO.h:281
REAL8 window_param
parameter of window function, if required
Definition: SFTfileIO.h:273
CHAR privMisc[256]
For private SFTs: miscellaneous description field.
Definition: SFTfileIO.h:276
int resource_rate
this many resource units become available in one second
Definition: splitSFTs.c:76
int resource_units
number of resource units available for consumption
Definition: splitSFTs.c:75
time_t last_checked
time we last checked
Definition: splitSFTs.c:77
unsigned short windowspec