Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
SFTfileIO.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010, 2013, 2014, 2016, 2019--2022 Karl Wette
3 * Copyright (C) 2010 Chris Messenger
4 * Copyright (C) 2009, 2011 Adam Mercer
5 * Copyright (C) 2006 Badri Krishnan
6 * Copyright (C) 2004--2007, 2010, 2012, 2017 Bernd Machenschalk
7 * Copyright (C) 2004--2008, 2010--2016 Reinhard Prix
8 * Copyright (C) 2004, 2005 Alicia Sintes
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with with program; see the file COPYING. If not, write to the
22 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 * MA 02110-1301 USA
24 */
25
26/*---------- includes ----------*/
27
28#include "SFTinternal.h"
29#include "SFTReferenceLibrary.h"
30
31/*---------- constants ----------*/
32
33/** blocksize used in SFT-reading for the CRC-checksum computation (has to be multiple of 8 !!) */
34#define BLOCKSIZE 8192 * 8
35
36/*---------- internal types ----------*/
37
38typedef struct {
50
51/** segments read so far from one SFT */
52typedef struct {
53 UINT4 first; /**< first bin in this segment */
54 UINT4 last; /**< last bin in this segment */
55 LIGOTimeGPS epoch; /**< timestamp of this SFT */
56 struct tagSFTLocator *lastfrom; /**< last bin read from this locator */
58
59/*---------- internal prototypes ----------*/
60
61static int read_header_from_fp( FILE *fp, SFTtype *header, UINT4 *nsamples, UINT8 *header_crc64, UINT8 *ref_crc64, UINT2 *SFTwindowspec, CHAR **SFTcomment, BOOLEAN swapEndian );
62
63/*========== function definitions ==========*/
64
65/// \addtogroup SFTfileIO_h
66/// @{
67
68/**
69 * Load the given frequency-band <tt>[fMin, fMax)</tt> (half-open) from the SFT-files listed in the
70 * SFT-'catalogue' ( returned by XLALSFTdataFind() ).
71 *
72 * Note: \a fMin (or \a fMax) is allowed to be set to \c -1, which means to read in all
73 * Frequency-bins from the lowest (or up to the highest) found in all SFT-files of the catalog.
74 *
75 * Note 2: The returned frequency-interval is guaranteed to contain <tt>[fMin, fMax)</tt>,
76 * but is allowed to be larger, as it must be an interval of discrete frequency-bins as found
77 * in the SFT-file.
78 *
79 * Note 3: This function has the capability to read sequences of SFT segments and
80 * putting them together to single SFTs while reading.
81 *
82 * Note 4: The 'fudge region' allowing for numerical noise is fudge= 10*LAL_REAL8_EPS ~2e-15
83 * relative deviation: ie if the SFT contains a bin at 'fi', then we consider for example
84 * "fMin == fi" if fabs(fi - fMin)/fi < fudge.
85 */
87XLALLoadSFTs( const SFTCatalog *catalog, /**< The 'catalogue' of SFTs to load */
88 REAL8 fMin, /**< minumum requested frequency (-1 = read from lowest) */
89 REAL8 fMax /**< maximum requested frequency (-1 = read up to highest) */
90 )
91{
92 UINT4 catPos; /**< current file in catalog */
93 UINT4 firstbin, lastbin; /**< the first and last bin we want to read */
94 UINT4 minbin, maxbin; /**< min and max bin of all SFTs in the catalog */
95 UINT4 nSFTs = 1; /**< number of SFTs, i.e. different GPS timestamps */
96 REAL8 deltaF; /**< frequency spacing of SFT */
97 SFTCatalog locatalog; /**< local copy of the catalog to be sorted by 'locator' */
98 SFTVector *sftVector = NULL; /**< the vector of SFTs to be returned */
99 SFTReadSegment *segments = NULL; /**< array of segments already read of an SFT */
100 char empty = '\0'; /**< empty string */
101 char *fname = &empty; /**< name of currently open file, initially "" */
102 FILE *fp = NULL; /**< open file */
103 SFTtype *thisSFT = NULL; /**< SFT to read from file */
104
105 /* error handler: free memory and return with error */
106#define XLALLOADSFTSERROR(eno) { \
107 if(fp) \
108 fclose(fp); \
109 if(segments) \
110 XLALFree(segments); \
111 if(locatalog.data) \
112 XLALFree(locatalog.data); \
113 if(thisSFT) \
114 XLALDestroySFT(thisSFT); \
115 if(sftVector) \
116 XLALDestroySFTVector(sftVector); \
117 XLAL_ERROR_NULL(eno); \
118 }
119
120 /* initialize locatalog.data so it doesn't get free()d on early error */
121 locatalog.data = NULL;
122
123 /* check function parameters */
124 if ( !catalog ) {
126 }
127
128 /* determine number of SFTs, i.e. number of different GPS timestamps.
129 The catalog should be sorted by GPS time, so just count changes.
130 Record the 'index' of GPS time in the 'isft' field of the locator,
131 so that we know later in which SFT to put this segment
132
133 while at it, record max and min bin of all SFTs in the catalog */
134
135 LIGOTimeGPS epoch = catalog->data[0].header.epoch;
136 catalog->data[0].locator->isft = nSFTs - 1;
137 deltaF = catalog->data[0].header.deltaF; /* Hz/bin */
138 minbin = firstbin = lround( catalog->data[0].header.f0 / deltaF );
139 maxbin = lastbin = firstbin + catalog->data[0].numBins - 1;
140 for ( catPos = 1; catPos < catalog->length; catPos++ ) {
141 firstbin = lround( catalog->data[catPos].header.f0 / deltaF );
142 lastbin = firstbin + catalog->data[catPos].numBins - 1;
143 if ( firstbin < minbin ) {
144 minbin = firstbin;
145 }
146 if ( lastbin > maxbin ) {
147 maxbin = lastbin;
148 }
149 if ( !GPSEQUAL( epoch, catalog->data[catPos].header.epoch ) ) {
150 epoch = catalog->data[catPos].header.epoch;
151 nSFTs++;
152 }
153 catalog->data[catPos].locator->isft = nSFTs - 1;
154 }
155 XLALPrintInfo( "%s: fMin: %f, fMax: %f, deltaF: %f, minbin: %u, maxbin: %u\n", __func__, fMin, fMax, deltaF, minbin, maxbin );
156
157 /* calculate first and last frequency bin to read */
158 if ( fMin < 0 ) {
159 firstbin = minbin;
160 } else {
162 }
163 if ( fMax < 0 ) {
164 lastbin = maxbin;
165 } else {
166 lastbin = XLALRoundFrequencyUpToSFTBin( fMax, deltaF ) - 1;
167 if ( ( lastbin == 0 ) && ( fMax != 0 ) ) {
168 XLALPrintError( "ERROR: last bin to read is 0 (fMax: %f, deltaF: %f)\n", fMax, deltaF );
170 }
171 }
172 XLALPrintInfo( "%s: Reading from first bin: %u, last bin: %u\n", __func__, firstbin, lastbin );
173
174 /* allocate the SFT vector that will be returned */
175 if ( !( sftVector = XLALCreateSFTVector( nSFTs, lastbin + 1 - firstbin ) ) ) {
176 XLALPrintError( "ERROR: Couldn't create sftVector\n" );
178 }
179
180 /* allocate an additional single SFT where SFTs are read in */
181 if ( !( thisSFT = XLALCreateSFT( lastbin + 1 - firstbin ) ) ) {
182 XLALPrintError( "ERROR: Couldn't create thisSFT\n" );
184 }
185
186 /* make a copy of the catalog that gets sorted by locator.
187 Eases maintaing a correctly (epoch-)sorted catalog, particulary in case of errors
188 note: only the pointers to the SFTdescriptors are copied & sorted, not the descriptors */
189 locatalog.length = catalog->length;
190 {
191 UINT4 size = catalog->length * sizeof( catalog->data[0] );
192 if ( !( locatalog.data = XLALMalloc( size ) ) ) {
193 XLALPrintError( "ERROR: Couldn't allocate locatalog.data\n" );
195 }
196 memcpy( locatalog.data, catalog->data, size );
197 }
198
199 /* sort catalog by f0, locator */
200 qsort( ( void * )locatalog.data, locatalog.length, sizeof( locatalog.data[0] ), compareSFTloc );
201
202 /* allocate segment vector, one element per final SFT */
203 if ( !( segments = XLALCalloc( nSFTs, sizeof( SFTReadSegment ) ) ) ) {
204 XLALPrintError( "ERROR: Couldn't allocate locatalog.data\n" );
206 }
207
208 /* loop over all files (actually locators) in the catalog */
209 for ( catPos = 0; catPos < catalog->length; catPos++ ) {
210
211 struct tagSFTLocator *locator = locatalog.data[catPos].locator;
212 UINT4 isft = locator->isft;;
213 UINT4 firstBinRead;
214 UINT4 lastBinRead;
215
216 if ( locatalog.data[catPos].header.data ) {
217 /* the SFT data has already been read into the catalog,
218 copy the relevant part to thisSFT */
219
220 volatile REAL8 tmp = locatalog.data[catPos].header.f0 / deltaF;
221 UINT4 firstSFTbin = lround( tmp );
222 UINT4 lastSFTbin = firstSFTbin + locatalog.data[catPos].numBins - 1;
223 UINT4 firstBin2read = firstbin;
224 UINT4 lastBin2read = lastbin;
225 UINT4 numBins2read, offsetBins;
226
227 /* limit the interval to be read to what's actually in the SFT */
228 if ( firstBin2read < firstSFTbin ) {
229 firstBin2read = firstSFTbin;
230 }
231 if ( lastBin2read > lastSFTbin ) {
232 lastBin2read = lastSFTbin;
233 }
234
235 /* check that requested interval is found in SFT */
236 if ( firstBin2read <= lastBin2read ) {
237
238 /* keep a copy of the data pointer */
239 COMPLEX8Sequence *data = thisSFT->data;
240
241 firstBinRead = firstBin2read;
242 lastBinRead = lastBin2read;
243 offsetBins = firstBin2read - firstSFTbin;
244 numBins2read = lastBin2read - firstBin2read + 1;
245
246 /* copy the header */
247 *thisSFT = locatalog.data[catPos].header;
248 /* restore data pointer */
249 thisSFT->data = data;
250 /* copy the data */
251 memcpy( thisSFT->data->data,
252 locatalog.data[catPos].header.data + offsetBins,
253 numBins2read * sizeof( COMPLEX8 ) );
254
255 /* update the start-frequency entry in the SFT-header to the new value */
256 thisSFT->f0 = 1.0 * firstBin2read * thisSFT->deltaF;
257
258 } else {
259 /* no data was needed from this SFT (segment) */
260 firstBinRead = 0;
261 lastBinRead = 0;
262 }
263
264 } else {
265 /* SFT data had not yet been read - read it */
266
267 /* open and close a file only when necessary, i.e. reading a different file */
268 if ( strcmp( fname, locator->fname ) ) {
269 if ( fp ) {
270 fclose( fp );
271 fp = NULL;
272 }
273 fname = locator->fname;
274 fp = fopen( fname, "rb" );
275 XLALPrintInfo( "%s: Opening file '%s'\n", __func__, fname );
276 if ( !fp ) {
277 XLALPrintError( "ERROR: Couldn't open file '%s'\n", fname );
279 }
280 }
281
282 /* seek to the position of the SFT in the file (if necessary) */
283 if ( locator->offset )
284 if ( fseek( fp, locator->offset, SEEK_SET ) == -1 ) {
285 XLALPrintError( "ERROR: Couldn't seek to position %ld in file '%s'\n",
286 locator->offset, fname );
288 }
289
290 /* read SFT data */
291 lastBinRead = read_sft_bins_from_fp( thisSFT, &firstBinRead, firstbin, lastbin, fp );
292 XLALPrintInfo( "%s: Read data from %s:%lu: %u - %u\n", __func__, locator->fname, locator->offset, firstBinRead, lastBinRead );
293 }
294 /* SFT data has been read from file or taken from catalog */
295
296 if ( lastBinRead ) {
297 /* data was actually read */
298
299 if ( segments[isft].last == 0 ) {
300
301 /* no data was read for this SFT yet: must be first segment */
302 if ( firstBinRead != firstbin ) {
303 XLALPrintError( "ERROR: data gap or overlap at first bin of SFT#%u (GPS %lf)"
304 " expected bin %u, bin %u read from file '%s'\n",
305 isft, GPS2REAL8( thisSFT->epoch ),
306 firstbin, firstBinRead, fname );
308 }
309 segments[isft].first = firstBinRead;
310 segments[isft].epoch = thisSFT->epoch;
311
312 /* if not first segment, segment must fit at the end of previous data */
313 } else if ( firstBinRead != segments[isft].last + 1 ) {
314 XLALPrintError( "ERROR: data gap or overlap in SFT#%u (GPS %lf)"
315 " between bin %u read from file '%s' and bin %u read from file '%s'\n",
316 isft, GPS2REAL8( thisSFT->epoch ),
317 segments[isft].last, segments[isft].lastfrom->fname,
318 firstBinRead, fname );
320 }
321
322 /* consistency checks */
323 if ( deltaF != thisSFT->deltaF ) {
324 XLALPrintError( "ERROR: deltaF mismatch (%f/%f) in SFT read from file '%s'\n",
325 thisSFT->deltaF, deltaF, fname );
327 }
328 if ( !GPSEQUAL( segments[isft].epoch, thisSFT->epoch ) ) {
329 XLALPrintError( "ERROR: GPS epoch mismatch (%f/%f) in SFT read from file '%s'\n",
330 GPS2REAL8( segments[isft].epoch ), GPS2REAL8( thisSFT->epoch ), fname );
332 }
333
334 /* data is ok, add to SFT */
335 segments[isft].last = lastBinRead;
336 segments[isft].lastfrom = locator;
337 memcpy( sftVector->data[isft].name, locatalog.data[catPos].header.name, sizeof( sftVector->data[isft].name ) );
338 sftVector->data[isft].sampleUnits = locatalog.data[catPos].header.sampleUnits;
339 memcpy( sftVector->data[isft].data->data + ( firstBinRead - firstbin ),
340 thisSFT->data->data,
341 ( lastBinRead - firstBinRead + 1 ) * sizeof( COMPLEX8 ) );
342
343 } else if ( !firstBinRead ) {
344 /* no needed data had been in this segment */
345 XLALPrintInfo( "%s: No data read from %s:%lu\n", __func__, locator->fname, locator->offset );
346
347 /* set epoch if not yet set, if already set, check it */
348 if ( GPSZERO( segments[isft].epoch ) ) {
349 segments[isft].epoch = thisSFT->epoch;
350 } else if ( !GPSEQUAL( segments[isft].epoch, thisSFT->epoch ) ) {
351 XLALPrintError( "ERROR: GPS epoch mismatch (%f/%f) in SFT read from file '%s'\n",
352 GPS2REAL8( segments[isft].epoch ), GPS2REAL8( thisSFT->epoch ), fname );
354 }
355
356 } else {
357 /* failed to read data */
358
359 XLALPrintError( "ERROR: Error (%u) reading SFT from file '%s'\n", firstBinRead, fname );
361 }
362 }
363
364 /* close the last file */
365 if ( fp ) {
366 fclose( fp );
367 fp = NULL;
368 }
369
370 /* check that all SFTs are complete */
371 for ( UINT4 isft = 0; isft < nSFTs; isft++ ) {
372 if ( segments[isft].last == lastbin ) {
373 sftVector->data[isft].f0 = 1.0 * firstbin * deltaF;
374 sftVector->data[isft].epoch = segments[isft].epoch;
375 sftVector->data[isft].deltaF = deltaF;
376 } else {
377 if ( segments[isft].last )
378 XLALPrintError( "ERROR: data missing at end of SFT#%u (GPS %lf)"
379 " expected bin %u, bin %u read from file '%s'\n",
380 isft, GPS2REAL8( segments[isft].epoch ),
381 lastbin, segments[isft].last,
382 segments[isft].lastfrom->fname );
383 else
384 XLALPrintError( "ERROR: no data could be read for SFT#%u (GPS %lf)\n",
385 isft, GPS2REAL8( segments[isft].epoch ) );
387 }
388 }
389
390 /* cleanup */
391 XLALFree( segments );
392 XLALFree( locatalog.data );
393 XLALDestroySFT( thisSFT );
394
395 return ( sftVector );
396
397} /* XLALLoadSFTs() */
398
399
400/**
401 * Function to load a catalog of SFTs from possibly different detectors.
402 * This is similar to XLALLoadSFTs except that the input SFT catalog is
403 * allowed to contain multiple ifos. The output is the structure
404 * MultiSFTVector which is a vector of (pointers to) SFTVectors, one for
405 * each ifo found in the catalog. As in XLALLoadSFTs, fMin and fMax can be
406 * set to -1 to get the full SFT from the lowest to the highest frequency
407 * bin found in the SFT.
408 *
409 * output SFTvectors are sorted alphabetically by detector-name
410 *
411 * NOTE: this is basically a backwards-compatible API wrapper to
412 * XLALLoadMultiSFTsFromView(), which takes a MultiSFTCatalogView as input instead.
413 *
414 */
416XLALLoadMultiSFTs( const SFTCatalog *inputCatalog, /**< The 'catalogue' of SFTs to load */
417 REAL8 fMin, /**< minumum requested frequency (-1 = read from lowest) */
418 REAL8 fMax /**< maximum requested frequency (-1 = read up to highest) */
419 )
420
421{
422 XLAL_CHECK_NULL( ( inputCatalog != NULL ) && ( inputCatalog->length != 0 ), XLAL_EINVAL );
423
424 MultiSFTCatalogView *multiCatalogView;
425 // get the (alphabetically-sorted!) multiSFTCatalogView
426 XLAL_CHECK_NULL( ( multiCatalogView = XLALGetMultiSFTCatalogView( inputCatalog ) ) != NULL, XLAL_EFUNC );
427
429 XLAL_CHECK_NULL( ( multiSFTs = XLALLoadMultiSFTsFromView( multiCatalogView, fMin, fMax ) ) != NULL, XLAL_EFUNC );
430
431 /* free memory and exit */
432 XLALDestroyMultiSFTCatalogView( multiCatalogView );
433
434 return multiSFTs;
435
436} /* XLALLoadMultiSFTs() */
437
438
439/**
440 * This function loads a MultiSFTVector from a given input MultiSFTCatalogView,
441 * otherwise the documentation of XLALLoadMultiSFTs() applies.
442 *
443 * Note: this is basically the core-function of XLALLoadMultiSFTs() doing the
444 * actual work.
445 *
446 * Note2: we keep the IFO sort-order of the input multiCatalogView
447 */
449XLALLoadMultiSFTsFromView( const MultiSFTCatalogView *multiCatalogView, /**< The multi-SFT catalogue view of SFTs to load */
450 REAL8 fMin, /**< minumum requested frequency (-1 = read from lowest) */
451 REAL8 fMax /**< maximum requested frequency (-1 = read up to highest) */
452 )
453{
454 XLAL_CHECK_NULL( multiCatalogView != NULL, XLAL_EINVAL );
455 XLAL_CHECK_NULL( multiCatalogView->length != 0, XLAL_EINVAL );
456
457 UINT4 numIFOs = multiCatalogView->length;
458
459 /* create multi sft vector */
461 XLAL_CHECK_NULL( ( multiSFTs = XLALCalloc( 1, sizeof( *multiSFTs ) ) ) != NULL, XLAL_ENOMEM );
462 XLAL_CHECK_NULL( ( multiSFTs->data = XLALCalloc( numIFOs, sizeof( *multiSFTs->data ) ) ) != NULL, XLAL_ENOMEM );
463 multiSFTs->length = numIFOs;
464
465 for ( UINT4 X = 0; X < numIFOs; X++ ) {
466 if ( ( multiSFTs->data[X] = XLALLoadSFTs( &( multiCatalogView->data[X] ), fMin, fMax ) ) == NULL ) {
467 /* free sft vectors created previously in loop */
469 XLAL_ERROR_NULL( XLAL_EFUNC, "Failed to XLALLoadSFTs() for IFO X = %d\n", X );
470 } // if XLALLoadSFTs() failed
471
472 } // for X < numIFOs
473
474 // return final multi-SFT vector
475 return multiSFTs;
476
477} // XLALLoadMultiSFTsFromView()
478
479
480/**
481 * Write the given SFTtype to a FILE pointer.
482 * Add the comment to SFT if SFTcomment != NULL.
483 *
484 * NOTE: the comment written into the SFT-file contains the 'sft->name' field concatenated with
485 * the user-specified 'SFTcomment'
486 */
487int
489 const SFTtype *sft, /**< SFT to write to disk */
490 FILE *fp, /**< pointer to open file */
491 const CHAR *SFTwindowtype, /**< window applied to SFT, if any */
492 const REAL8 SFTwindowparam, /**< parameter of window */
493 const CHAR *SFTcomment /**< optional comment */
494)
495{
496 UINT4 comment_len = 0;
497 CHAR *_SFTcomment;
498 UINT4 pad_len = 0;
499 CHAR pad[] = {0, 0, 0, 0, 0, 0, 0}; /* for comment-padding */
500 _SFT_header_t rawheader;
501
502 /* check input consistency */
503 if ( !sft || !sft->data || sft->deltaF <= 0 || sft->f0 < 0 || sft->data->length == 0 ) {
505 }
506 if ( !( ( sft->epoch.gpsSeconds >= 0 ) && ( sft->epoch.gpsNanoSeconds >= 0 ) ) ) {
508 }
509 if ( !( sft->epoch.gpsNanoSeconds < 1000000000 ) ) {
511 }
512 if ( !XLALIsValidCWDetector( sft->name ) ) {
513 XLALPrintError( "\nInvalid detector prefix '%c%c'\n\n", sft->name[0], sft->name[1] );
515 }
516
517 if ( !fp ) {
519 }
520
521 XLAL_CHECK( SFTwindowtype != NULL, XLAL_EFAULT );
522
523 /* concat sft->name + SFTcomment for SFT-file comment-field */
524 comment_len = strlen( sft->name ) + 1;
525 if ( SFTcomment ) {
526 comment_len += strlen( SFTcomment ) + 1; /* separate by "\n" */
527 }
528
529 if ( ( _SFTcomment = XLALCalloc( comment_len, sizeof( CHAR ) ) ) == NULL ) {
531 }
532 strcpy( _SFTcomment, sft->name );
533 if ( SFTcomment ) {
534 strcat( _SFTcomment, "\n" );
535 strcat( _SFTcomment, SFTcomment );
536 }
537
538 /* comment length including null terminator to string must be an
539 * integer multiple of eight bytes.
540 */
541 pad_len = ( 8 - ( comment_len % 8 ) ) % 8;
542
543 /* ----- fill out header */
544 rawheader.version = MAX_SFT_VERSION;
545 rawheader.gps_sec = sft->epoch.gpsSeconds;
546 rawheader.gps_nsec = sft->epoch.gpsNanoSeconds;
547 rawheader.tbase = TSFTfromDFreq( sft->deltaF );
548 rawheader.first_frequency_index = lround( sft->f0 / sft->deltaF );
549 rawheader.nsamples = sft->data->length;
550 rawheader.crc64 = 0; /* set to 0 for crc-calculation */
551 rawheader.detector[0] = sft->name[0];
552 rawheader.detector[1] = sft->name[1];
553 rawheader.comment_length = comment_len + pad_len;
554
555 XLAL_CHECK( build_sft_windowspec( &rawheader.windowspec, NULL, SFTwindowtype, SFTwindowparam ) == XLAL_SUCCESS, XLAL_EFUNC );
556
557 /* ----- compute CRC */
558 rawheader.crc64 = crc64( ( const unsigned char * )&rawheader, sizeof( rawheader ), ~( 0ULL ) );
559
560 rawheader.crc64 = crc64( ( const unsigned char * )_SFTcomment, comment_len, rawheader.crc64 );
561 rawheader.crc64 = crc64( ( const unsigned char * )pad, pad_len, rawheader.crc64 );
562
563 rawheader.crc64 = crc64( ( const unsigned char * ) sft->data->data, sft->data->length * sizeof( *sft->data->data ), rawheader.crc64 );
564
565 /* ----- write the header to file */
566 if ( 1 != fwrite( &rawheader, sizeof( rawheader ), 1, fp ) ) {
568 }
569
570 /* ----- write the comment to file */
571 if ( comment_len != fwrite( _SFTcomment, 1, comment_len, fp ) ) {
573 }
574 if ( pad_len != fwrite( pad, 1, pad_len, fp ) ) {
576 }
577
578 XLALFree( _SFTcomment );
579
580 /* write the data to the file. Data must be packed REAL,IMAG,REAL,IMAG,... */
581 if ( sft->data->length != fwrite( sft->data->data, sizeof( *sft->data->data ), sft->data->length, fp ) ) {
583 }
584
585 return XLAL_SUCCESS;
586
587} /* XLALWriteSFT2FilePointer() */
588
589
590/**
591 * Write the given SFTtype to a SFT file with the supplied filename.
592 * Add the comment to SFT if SFTcomment != NULL.
593 *
594 * NOTE: the comment written into the SFT-file contains the 'sft->name' field concatenated with
595 * the user-specified 'SFTcomment'
596 */
597int
599 const SFTtype *sft, /**< SFT to write to disk */
600 const CHAR *SFTfilename, /**< SFT filename */
601 const CHAR *SFTwindowtype, /**< window applied to SFT, if any */
602 const REAL8 SFTwindowparam, /**< parameter of window */
603 const CHAR *SFTcomment /**< optional comment */
604)
605{
606 FILE *fp = NULL;
607
608 /* Make sure the arguments are not NULL */
609 if ( !( sft ) ) {
611 }
612 if ( !( sft->data ) ) {
614 }
615 if ( !( SFTfilename ) ) {
617 }
618
619 if ( !XLALIsValidCWDetector( sft->name ) ) {
620 XLALPrintError( "\nInvalid detector prefix '%c%c'\n\n", sft->name[0], sft->name[1] );
622 }
623
624 XLAL_CHECK( SFTwindowtype != NULL, XLAL_EFAULT );
625
626 /* open SFT-file for writing */
627 if ( ( fp = fopen( SFTfilename, "wb" ) ) == NULL ) {
628 XLALPrintError( "\nFailed to open file '%s' for writing: %s\n\n", SFTfilename, strerror( errno ) );
630 }
631
632 /* write SFT to file */
633 if ( XLALWriteSFT2FilePointer( sft, fp, SFTwindowtype, SFTwindowparam, SFTcomment ) != XLAL_SUCCESS ) {
635 }
636
637 fclose( fp );
638
639 return XLAL_SUCCESS;
640
641} /* XLALWriteSFT2NamedFile() */
642
643
644/**
645 * Write the given SFTtype to a SFT file with a standard (\cite SFT-spec) filename.
646 * Add the comment to SFT if SFTcomment != NULL.
647 *
648 * NOTE: the comment written into the SFT-file contains the 'sft->name' field concatenated with
649 * the user-specified 'SFTcomment'
650 *
651 * NOTE: The SFT filename spec is updated to reflect the filename of the written SFT, by
652 * setting the \c numSFTs, \c detector, \c SFTtimebase, \c gpsStart, and \c SFTspan fields.
653 * if needed, the SFT filename can be reconstructed with XLALBuildSFTFilenameFromSpec()
654 */
655int
657 const SFTtype *sft, /**< SFT to write to disk */
658 SFTFilenameSpec *SFTfnspec, /**< SFT filename specification used to construct filename */
659 const CHAR *SFTcomment /**< optional comment */
660)
661{
662
663 /* Make sure the arguments are not NULL */
664 if ( !( sft ) ) {
666 }
667 if ( !( sft->data ) ) {
669 }
670
671 if ( !XLALIsValidCWDetector( sft->name ) ) {
672 XLALPrintError( "\nInvalid detector prefix '%c%c'\n\n", sft->name[0], sft->name[1] );
674 }
675
676 XLAL_CHECK( SFTfnspec != NULL, XLAL_EFAULT );
677
678 const UINT4 Tsft = ( UINT4 ) round( 1.0 / sft->deltaF );
679
680 SFTfnspec->numSFTs = 1;
681 SFTfnspec->detector[0] = sft->name[0];
682 SFTfnspec->detector[1] = sft->name[1];
683 SFTfnspec->detector[2] = 0;
684 SFTfnspec->SFTtimebase = Tsft;
685 SFTfnspec->gpsStart = sft->epoch.gpsSeconds;
686
687 /* calculate sft 'duration' -- may be different from timebase if nanosecond of sft-epoch is non-zero */
688 SFTfnspec->SFTspan = Tsft;
689 if ( sft->epoch.gpsNanoSeconds > 0 ) {
690 SFTfnspec->SFTspan += 1;
691 }
692
693 // build SFT filename
694 char *SFTfilename = XLALBuildSFTFilenameFromSpec( SFTfnspec );
695 XLAL_CHECK( SFTfilename != NULL, XLAL_EFUNC );
696
697 // write SFT
698 XLAL_CHECK( XLALWriteSFT2NamedFile( sft, SFTfilename, SFTfnspec->window_type, SFTfnspec->window_param, SFTcomment ) == XLAL_SUCCESS, XLAL_EFUNC );
699
700 XLALFree( SFTfilename );
701
702 return XLAL_SUCCESS;
703
704} /* XLALWriteSFT2StandardFile() */
705
706
707/**
708 * Write the given SFTVector to a single merged SFT file with the supplied filename.
709 * Add the comment to SFT if SFTcomment != NULL.
710 */
711int
713 const SFTVector *sftVect, /**< SFT vector to write to disk */
714 const CHAR *SFTfilename, /**< SFT filename */
715 const CHAR *SFTwindowtype, /**< window applied to SFT, if any */
716 const REAL8 SFTwindowparam, /**< parameter of window */
717 const CHAR *SFTcomment /**< optional comment */
718)
719{
720 XLAL_CHECK( sftVect != NULL, XLAL_EINVAL );
721 XLAL_CHECK( sftVect->data != NULL, XLAL_EINVAL );
722 XLAL_CHECK( sftVect->length > 0, XLAL_EINVAL );
723 XLAL_CHECK( SFTfilename != NULL, XLAL_EINVAL );
724
725 const UINT4 numSFTs = sftVect->length;
726
727 /* open SFT-file for writing */
728 FILE *fp;
729 XLAL_CHECK( ( fp = fopen( SFTfilename, "wb" ) ) != NULL, XLAL_EIO, "Failed to open '%s' for writing: %s\n\n", SFTfilename, strerror( errno ) );
730
731 for ( UINT4 k = 0; k < numSFTs; k++ ) {
732 SFTtype *sft = &( sftVect->data[k] );
733
734 /* write the k^th sft */
735 XLAL_CHECK( XLALWriteSFT2FilePointer( sft, fp, SFTwindowtype, SFTwindowparam, SFTcomment ) == XLAL_SUCCESS, XLAL_EFUNC );
736
737 } // for k < numSFTs
738
739 fclose( fp );
740
741 return XLAL_SUCCESS;
742
743} /* XLALWriteSFTVector2NamedFile() */
744
745
746/**
747 * Write the given SFTVector to SFT file(s) with a standard (\cite SFT-spec) filename(s).
748 * Add the comment to SFT if SFTcomment != NULL.
749 *
750 * NOTE: The SFT filename spec is updated to reflect the filename of the written SFT, by
751 * setting the \c numSFTs, \c detector, \c SFTtimebase, \c gpsStart, and \c SFTspan fields.
752 * if needed, the SFT filename can be reconstructed with XLALBuildSFTFilenameFromSpec()
753 */
754int
756 const SFTVector *sftVect, /**< SFT vector to write to disk */
757 SFTFilenameSpec *SFTfnspec, /**< SFT filename specification used to construct filename(s) */
758 const CHAR *SFTcomment, /**< optional comment */
759 const BOOLEAN merged /**< If true, write a single merged SFT file; otherwise, write individual SFT files */
760)
761{
762 XLAL_CHECK( sftVect != NULL, XLAL_EINVAL );
763 XLAL_CHECK( sftVect->data != NULL, XLAL_EINVAL );
764 XLAL_CHECK( sftVect->length > 0, XLAL_EINVAL );
765
766 XLAL_CHECK( SFTfnspec != NULL, XLAL_EFAULT );
767
768 const UINT4 numSFTs = sftVect->length;
769 const SFTtype *sftStart = &( sftVect->data[0] );
770 const SFTtype *sftEnd = &( sftVect->data[numSFTs - 1] );
771 const LIGOTimeGPS *epochStart = &( sftStart->epoch );
772 const LIGOTimeGPS *epochEnd = &( sftEnd->epoch );
773
774 const UINT4 Tsft = ( UINT4 ) round( 1.0 / sftStart->deltaF );
775
776 if ( merged ) { // write a single merged SFT file
777
778 SFTfnspec->numSFTs = numSFTs;
779 SFTfnspec->detector[0] = sftStart->name[0];
780 SFTfnspec->detector[1] = sftStart->name[1];
781 SFTfnspec->detector[2] = 0;
782 SFTfnspec->SFTtimebase = Tsft;
783 SFTfnspec->gpsStart = sftStart->epoch.gpsSeconds;
784
785 /* calculate time interval covered -- may be different from timebase if nanosecond of sft-epochs are non-zero */
786 SFTfnspec->SFTspan = epochEnd->gpsSeconds - epochStart->gpsSeconds + Tsft;
787 if ( epochStart->gpsNanoSeconds > 0 ) {
788 SFTfnspec->SFTspan += 1;
789 }
790 if ( epochEnd->gpsNanoSeconds > 0 ) {
791 SFTfnspec->SFTspan += 1;
792 }
793
794 // build SFT filename
795 char *SFTfilename = XLALBuildSFTFilenameFromSpec( SFTfnspec );
796 XLAL_CHECK( SFTfilename != NULL, XLAL_EFUNC );
797
798 // write SFT
799 XLAL_CHECK( XLALWriteSFTVector2NamedFile( sftVect, SFTfilename, SFTfnspec->window_type, SFTfnspec->window_param, SFTcomment ) == XLAL_SUCCESS, XLAL_EFUNC );
800
801 XLALFree( SFTfilename );
802
803 } else { // write individual SFT files
804
805 // local copy of 'SFTfnspec' so that we can return name of first written SFT
806 SFTFilenameSpec spec = *SFTfnspec;
807
808 for ( UINT4 k = 0; k < numSFTs; k++ ) {
809
810 SFTtype *sft = &( sftVect->data[k] );
811
812 // return spec of first written SFT in 'SFTfnspec'; otherwise use local copy
813 SFTFilenameSpec *p_spec = ( k == 0 ) ? SFTfnspec : &spec;
814
815 XLAL_CHECK( XLALWriteSFT2StandardFile( sft, p_spec, SFTcomment ) == XLAL_SUCCESS, XLAL_EFUNC );
816
817 } // for k < numSFTs
818
819 }
820
821 return XLAL_SUCCESS;
822
823} /* XLALWriteSFTVector2StandardFile() */
824
825
826/**
827 * Verify that the contents of a SFT file are valid.
828 *
829 * This is just an XLAL wrapper to the SFTReferenceLibrary function ValidateSFTFile().
830 *
831 * \return: XLAL_SUCCESS if no validation errors encountered.
832 */
833int
835{
836 int errcode = ValidateSFTFile( fname );
837 XLAL_CHECK( errcode == 0, XLAL_EFUNC, "SFT validation error on file '%s': code %d (%s)", fname, errcode, SFTErrorMessage( errcode ) );
838 return XLAL_SUCCESS;
839} /* XLALCheckSFTFileIsValid */
840
841
842/* a little endian-swapper needed for SFT reading/writing */
843void
844endian_swap( CHAR *pdata, size_t dsize, size_t nelements )
845{
846 UINT4 i, j, indx;
847 CHAR tempbyte;
848
849 if ( dsize <= 1 ) {
850 return;
851 }
852
853 for ( i = 0; i < nelements; i++ ) {
854 indx = dsize;
855 for ( j = 0; j < dsize / 2; j++ ) {
856 tempbyte = pdata[j];
857 indx = indx - 1;
858 pdata[j] = pdata[indx];
859 pdata[indx] = tempbyte;
860 }
861
862 pdata = pdata + dsize;
863 }
864
865 return;
866
867} /* endian swap */
868
869
870/**
871 * Open an "SFT" defined by the SFT-locator, return a FILE-pointer to the beginning of this SFT.
872 * \note The returned filepointer could point to an SFT-block within a merged SFT-file,
873 * so you should not assume that SEEK_SET takes you to the beginning of this block!
874 * (instead you'd have to save the current position returned by this function, which \
875 * points to the beginning of the block!)
876 *
877 * NOTE: Ideally this should be the *ONLY* function using the internal structure of the opaque
878 * SFTLocator type
879 *
880 */
881FILE *
883{
884 FILE *fp = NULL;
885 CHAR *fname;
886
887 if ( !locator ) {
888 return NULL;
889 }
890
891 fname = locator->fname;
892 if ( ( fp = fopen( fname, "rb" ) ) == NULL ) {
893 XLALPrintError( "\nFailed to open SFT '%s' for reading: %s\n\n", fname, strerror( errno ) );
894 return NULL;
895 }
896
897 if ( fseek( fp, locator->offset, SEEK_SET ) == -1 ) {
898 XLALPrintError( "\nFailed to set fp-offset to '%ld': %s\n\n", locator->offset, strerror( errno ) );
899 fclose( fp );
900 return NULL;
901 }
902
903 return fp;
904
905} /* fopen_SFTLocator() */
906
907
908/**
909 * Read valid SFT version-number at position fp, and determine if we need to
910 * endian-swap the data.
911 * Restores filepointer to original position before returning.
912 *
913 * RETURN: 0 = OK, -1 = ERROR
914 */
915int
917{
918 long save_filepos;
919 REAL8 ver;
920
921 /* store fileposition for restoring in case of failure */
922 if ( ( save_filepos = ftell( fp ) ) == -1 ) {
923 XLALPrintError( "\nftell() failed: %s\n\n", strerror( errno ) );
924 return -1;
925 }
926
927 /* read version-number */
928 if ( 1 != fread( &ver, sizeof( ver ), 1, fp ) ) {
929 if ( lalDebugLevel ) {
930 XLALPrintError( "\nCould not read version-number from file\n\n" );
931 }
932 goto failed;
933 }
934
935
936 /* figure out endian-ness and check version-range */
937 for ( *version = MAX_SFT_VERSION; *version >= MIN_SFT_VERSION; --( *version ) ) {
938 REAL8 vertest = *version;
939 if ( ! memcmp( &ver, &vertest, sizeof( ver ) ) ) {
940 *need_swap = FALSE;
941 break;
942 }
943 endian_swap( ( char * )( &vertest ), sizeof( vertest ), 1 );
944 if ( ! memcmp( &ver, &vertest, sizeof( ver ) ) ) {
945 *need_swap = TRUE;
946 break;
947 }
948 }
949 if ( *version < MIN_SFT_VERSION ) {
950 if ( lalDebugLevel ) {
951 unsigned char *v = ( unsigned char * )( &ver );
952 XLALPrintError( "\nERROR: illegal SFT-version (%X %X %X %X %X %X %X %X) not within [%.0f, %.0f]\n",
953 v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7],
954 ( float )MIN_SFT_VERSION, ( float )MAX_SFT_VERSION );
955 }
956 goto failed;
957 }
958
959 /* restore initial filepointer position */
960 if ( fseek( fp, save_filepos, SEEK_SET ) == -1 ) {
961 XLALPrintError( "\nfseek() failed to return to intial fileposition: %s\n\n", strerror( errno ) );
962 goto failed;
963 }
964
965 return 0;
966
967failed:
968 fseek( fp, save_filepos, SEEK_SET );
969 return -1;
970
971} /* read_SFTversion_from_fp() */
972
973
974/* Try to read an SFT-header (of ANY VALID SFT-VERSION) at the given FILE-pointer fp,
975 * and return the SFT-header, SFT-version-number and number of frequency-samples in the SFT.
976 *
977 * Sets the filepointer fp at the end of the header if successful, leaves it at
978 * initial position if not.
979 *
980 * RETURN 0 = OK, -1 on ERROR
981 *
982 * We do basic checking of compliance with the SFT-spec (<tt>LIGO-T04164-01-Z</tt>)
983 * as far as a single header is concerned.
984 *
985 * NOTE: fatal errors will produce a XLALPrintError() error-message, but
986 * non-fatal 'SFT-format'-errors will only output error-messages if lalDebugLevel > 0.
987 * --> this function can therefore be used to check if a given file actually contains SFTs
988 *
989 *
990 */
991int
992read_sft_header_from_fp( FILE *fp, SFTtype *header, UINT4 *version, UINT8 *crc64, UINT2 *SFTwindowspec, BOOLEAN *swapEndian, CHAR **SFTcomment, UINT4 *numBins )
993{
995 UINT4 nsamples;
996 CHAR *comm = NULL;
997 UINT8 ref_crc = 0;
998 UINT8 header_crc;
999 UINT2 windowspec;
1000
1001 UINT4 ver;
1002 BOOLEAN need_swap;
1003 long save_filepos;
1004
1005 if ( !header || !version || !numBins || !fp ) {
1006 XLALPrintError( "\nERROR read_sft_header_from_fp(): called with NULL input\n\n" );
1007 return -1;
1008 }
1009 if ( SFTcomment && ( ( *SFTcomment ) != NULL ) ) {
1010 XLALPrintError( "\nERROR: Comment-string passed to read_sft_header_from_fp() is not empty!\n\n" );
1011 return -1;
1012 }
1013
1014 /* store fileposition for restoring in case of failure */
1015 if ( ( save_filepos = ftell( fp ) ) == -1 ) {
1016 XLALPrintError( "\nftell() failed: %s\n\n", strerror( errno ) );
1017 return -1;
1018 }
1019
1020 if ( read_SFTversion_from_fp( &ver, &need_swap, fp ) != 0 ) {
1021 return -1;
1022 }
1023
1024 /* read this SFT-header */
1026
1027 if ( MIN_SFT_VERSION <= ver && ver <= MAX_SFT_VERSION ) {
1028 if ( read_header_from_fp( fp, &head, &nsamples, &header_crc, &ref_crc, &windowspec, &comm, need_swap ) != 0 ) {
1029 goto failed;
1030 }
1031 } else {
1032 XLALPrintError( "\nUnsupported SFT-version %d.\n\n", ver );
1033 goto failed;
1034 } /* switch(ver) */
1035
1036
1037 /* ----- some general SFT-header consistency-checks */
1038 if ( ( head.epoch.gpsSeconds < 0 ) || ( head.epoch.gpsNanoSeconds < 0 ) || ( head.epoch.gpsNanoSeconds >= 1000000000 ) ) {
1039 XLALPrintError( "\nInvalid GPS-epoch in SFT : [%d, %d]!\n\n",
1040 head.epoch.gpsSeconds, head.epoch.gpsNanoSeconds );
1041 goto failed;
1042 }
1043
1044 if ( head.deltaF <= 0 ) {
1045 XLALPrintError( "\nNegative frequency-spacing in SFT!\n\n" );
1046 goto failed;
1047 }
1048
1049 if ( head.f0 < 0 ) {
1050 XLALPrintError( "\nNegative start-frequency in SFT!\n\n" );
1051 goto failed;
1052 }
1053
1054 /* ok */
1055 ( *header ) = head;
1056 ( *version ) = ver;
1057
1058 if ( SFTcomment ) { /* return of comment is optional */
1059 ( *SFTcomment ) = comm;
1060 } else if ( comm ) {
1061 LALFree( comm );
1062 }
1063
1064 ( *swapEndian ) = need_swap;
1065 ( *crc64 ) = ref_crc;
1066 ( *numBins ) = nsamples;
1067
1068 if ( SFTwindowspec ) { /* return of windowspec is optional */
1069 ( *SFTwindowspec ) = windowspec;
1070 }
1071
1072 return 0;
1073
1074 /* ---------- */
1075failed:
1076 /* restore filepointer initial position */
1077 if ( fseek( fp, save_filepos, SEEK_SET ) == -1 ) {
1078 XLALPrintError( "\nfseek() failed to return to intial fileposition: %s\n\n", strerror( errno ) );
1079 }
1080
1081 /* free comment if we allocated one */
1082 if ( comm ) {
1083 LALFree( comm );
1084 }
1085
1086 return -1;
1087
1088} /* read_sft_header_from_fp() */
1089
1090
1091/* ----- SFT header-reading function:
1092 *
1093 * return general SFTtype header, place filepointer at the end of the header if it succeeds,
1094 * set fp to initial position if it fails.
1095 * RETURN: 0 = OK, -1 = ERROR
1096 *
1097 * NOTE: fatal errors will produce a XLALPrintError() error-message, but
1098 * non-fatal 'SFT-format'-errors will only output error-messages if lalDebugLevel > 0.
1099 *
1100 */
1101int
1102read_header_from_fp( FILE *fp, SFTtype *header, UINT4 *nsamples, UINT8 *header_crc64, UINT8 *ref_crc64, UINT2 *SFTwindowspec, CHAR **SFTcomment, BOOLEAN swapEndian )
1103{
1104 _SFT_header_t rawheader;
1105 long save_filepos;
1106 CHAR *comm = NULL;
1107 UINT8 crc;
1108
1109
1110 /* check input-consistency */
1111 if ( !fp || !header || !nsamples || !SFTcomment ) {
1112 XLALPrintError( "\nERROR read_header_from_fp(): called with NULL input!\n\n" );
1113 return -1;
1114 }
1115 if ( SFTcomment && ( *SFTcomment != NULL ) ) {
1116 XLALPrintError( "\nERROR: Comment-string passed to read_header_from_fp() is not NULL!\n\n" );
1117 return -1;
1118 }
1119
1120 /* store fileposition for restoring in case of failure */
1121 if ( ( save_filepos = ftell( fp ) ) == -1 ) {
1122 XLALPrintError( "\nERROR: ftell() failed: %s\n\n", strerror( errno ) );
1123 return -1;
1124 }
1125
1126 /* read the whole header */
1127 if ( fread( &rawheader, sizeof( rawheader ), 1, fp ) != 1 ) {
1128 if ( lalDebugLevel ) {
1129 XLALPrintError( "\nCould not read header. %s\n\n", strerror( errno ) );
1130 }
1131 goto failed;
1132 }
1133
1134 /* ----- compute CRC for the header:
1135 * NOTE: the CRC checksum is computed on the *bytes*, not the numbers,
1136 * so this must be computed before any endian-swapping.
1137 */
1138 {
1139 UINT8 save_crc = rawheader.crc64;
1140 rawheader.crc64 = 0;
1141
1142 crc = crc64( ( const unsigned char * )&rawheader, sizeof( rawheader ), ~( 0ULL ) );
1143
1144 rawheader.crc64 = save_crc;
1145 /* NOTE: we're not done with crc yet, because we also need to
1146 * include the comment's CRC , see below
1147 */
1148 }/* compute crc64 checksum */
1149
1150 /* ----- swap endian-ness if required ----- */
1151 if ( swapEndian ) {
1152 endian_swap( ( CHAR * )( &rawheader.version ), sizeof( rawheader.version ), 1 );
1153 endian_swap( ( CHAR * )( &rawheader.gps_sec ), sizeof( rawheader.gps_sec ), 1 );
1154 endian_swap( ( CHAR * )( &rawheader.gps_nsec ), sizeof( rawheader.gps_nsec ), 1 );
1155 endian_swap( ( CHAR * )( &rawheader.tbase ), sizeof( rawheader.tbase ), 1 );
1156 endian_swap( ( CHAR * )( &rawheader.first_frequency_index ), sizeof( rawheader.first_frequency_index ), 1 );
1157 endian_swap( ( CHAR * )( &rawheader.nsamples ), sizeof( rawheader.nsamples ), 1 );
1158 endian_swap( ( CHAR * )( &rawheader.crc64 ), sizeof( rawheader.crc64 ), 1 );
1159 endian_swap( ( CHAR * )( &rawheader.windowspec ), sizeof( rawheader.windowspec ), 1 );
1160 endian_swap( ( CHAR * )( &rawheader.comment_length ), sizeof( rawheader.comment_length ), 1 );
1161 /* ----- */
1162
1163 } /* if endian_swap */
1164
1165 /* double-check version-number */
1166 if ( !( MIN_SFT_VERSION <= rawheader.version && rawheader.version <= MAX_SFT_VERSION ) ) {
1167 XLALPrintError( "\nWrong SFT-version %g in read_header_from_fp()\n\n", rawheader.version );
1168 goto failed;
1169 }
1170
1171 if ( rawheader.nsamples <= 0 ) {
1172 XLALPrintError( "\nNon-positive number of samples in SFT!\n\n" );
1173 goto failed;
1174 }
1175
1176 if ( rawheader.comment_length < 0 ) {
1177 XLALPrintError( "\nNegative comment-length in SFT!\n\n" );
1178 goto failed;
1179 }
1180
1181 if ( rawheader.comment_length % 8 != 0 ) {
1182 XLALPrintError( "\nComment-length must be multiple of 8 bytes!\n\n" );
1183 goto failed;
1184 }
1185
1186 const CHAR detector[3] = { rawheader.detector[0], rawheader.detector[1], 0 };
1187 if ( ! XLALIsValidCWDetector( detector ) ) {
1188 XLALPrintError( "\nIllegal detector-name in SFT: '%s'\n\n", detector );
1189 goto failed;
1190 }
1191
1192 if ( rawheader.version == 2 ) {
1193 rawheader.windowspec = 0; /* window of version 2 SFTs is unknown */
1194 }
1195
1196 /* ----- Now read comment (if any) ----- */
1197 comm = NULL;
1198 if ( rawheader.comment_length ) {
1199 CHAR *ptr;
1200 if ( ( comm = LALCalloc( 1, rawheader.comment_length ) ) == NULL ) {
1201 XLALPrintError( "\nFATAL: out of memory ...\n\n" );
1202 goto failed;
1203 }
1204 if ( ( size_t )rawheader.comment_length != fread( comm, 1, rawheader.comment_length, fp ) ) {
1205 XLALPrintError( "\nCould not read %d-bytes comment\n\n", rawheader.comment_length );
1206 goto failed;
1207 }
1208
1209 /* check that comment is 0-terminated */
1210 if ( comm[ rawheader.comment_length - 1] != 0 ) {
1211 XLALPrintError( "\nComment is not properly 0-terminated!\n\n" );
1212 goto failed;
1213 }
1214
1215 /* check that no NON-NULL bytes after first NULL in comment (->spec) */
1216 ptr = strchr( comm, 0 ); /* guaranteed to find sth, after previous check */
1217 while ( ptr < ( comm + rawheader.comment_length - 1 ) )
1218 if ( *ptr++ != 0 ) {
1219 XLALPrintError( "\nNon-NULL bytes found after comment-end!\n\n" );
1220 goto failed;
1221 }
1222
1223 /* comment length including null terminator to string must be an
1224 * integer multiple of eight bytes. comment==NULL means 'no
1225 * comment'
1226 */
1227 if ( SFTcomment ) {
1228 CHAR pad[] = {0, 0, 0, 0, 0, 0, 0}; /* for comment-padding */
1229 UINT4 comment_len = strlen( comm ) + 1;
1230 UINT4 pad_len = ( 8 - ( comment_len % 8 ) ) % 8;
1231
1232 crc = crc64( ( const unsigned char * )comm, comment_len, crc );
1233 crc = crc64( ( const unsigned char * )pad, pad_len, crc );
1234 }
1235
1236 } /* if comment_length > 0 */
1237
1238 /* ok: */
1239 memset( header, 0, sizeof( *header ) );
1240
1241 strncpy( header->name, detector, sizeof( header->name ) );
1242
1243 header->epoch.gpsSeconds = rawheader.gps_sec;
1244 header->epoch.gpsNanoSeconds = rawheader.gps_nsec;
1245
1246 header->f0 = rawheader.first_frequency_index / rawheader.tbase;
1247 header->deltaF = 1.0 / rawheader.tbase;
1248
1249 ( *nsamples ) = rawheader.nsamples;
1250 ( *ref_crc64 ) = rawheader.crc64;
1251 ( *SFTcomment ) = comm;
1252 ( *header_crc64 ) = crc;
1253 ( *SFTwindowspec ) = rawheader.windowspec;
1254
1255 return 0;
1256
1257failed:
1258 /* restore filepointer initial position */
1259 if ( fseek( fp, save_filepos, SEEK_SET ) == -1 ) {
1260 XLALPrintError( "\nfseek() failed to return to intial fileposition: %s\n\n", strerror( errno ) );
1261 }
1262
1263 /* free comment if we allocated one */
1264 if ( comm ) {
1265 LALFree( comm );
1266 }
1267
1268 return -1;
1269
1270} /* read_header_from_fp() */
1271
1272
1273/*
1274 This function reads an SFT (segment) from an open file pointer into a buffer.
1275 firstBin2read specifies the first bin to read from the SFT, lastBin2read is the last bin.
1276 If the SFT contains fewer bins than specified, all bins from the SFT are read.
1277 The function returns the last bin actually read, firstBinRead
1278 is set to the first bin actually read. In case of an error, 0 is returned
1279 and firstBinRead is set to a code further decribing the error condition.
1280*/
1281UINT4
1282read_sft_bins_from_fp( SFTtype *ret, UINT4 *firstBinRead, UINT4 firstBin2read, UINT4 lastBin2read, FILE *fp )
1283{
1284 UINT4 version;
1285 UINT8 crc64;
1286 BOOLEAN swapEndian;
1287 UINT4 numBins2read;
1288 UINT4 firstSFTbin, lastSFTbin, numSFTbins;
1289 INT4 offsetBins;
1290 long offsetBytes;
1291 volatile REAL8 tmp; /* intermediate results: try to force IEEE-arithmetic */
1292
1293 if ( !firstBinRead ) {
1294 XLALPrintError( "read_sft_bins_from_fp(): got passed NULL *firstBinRead\n" );
1295 return ( ( UINT4 ) - 1 );
1296 }
1297
1298 *firstBinRead = 0;
1299
1300 if ( ( ret == NULL ) ||
1301 ( ret->data == NULL ) ||
1302 ( ret->data->data == NULL ) ) {
1303 XLALPrintError( "read_sft_bins_from_fp(): got passed NULL SFT*\n" );
1304 *firstBinRead = 1;
1305 return ( 0 );
1306 }
1307
1308 if ( !fp ) {
1309 XLALPrintError( "read_sft_bins_from_fp(): got passed NULL FILE*\n" );
1310 *firstBinRead = 1;
1311 return ( 0 );
1312 }
1313
1314 if ( firstBin2read > lastBin2read ) {
1315 XLALPrintError( "read_sft_bins_from_fp(): Empty frequency-interval requested [%d, %d] bins\n",
1316 firstBin2read, lastBin2read );
1317 *firstBinRead = 1;
1318 return ( 0 );
1319 }
1320
1321 {
1322 COMPLEX8Sequence *data = ret->data;
1323 if ( read_sft_header_from_fp( fp, ret, &version, &crc64, NULL, &swapEndian, NULL, &numSFTbins ) != 0 ) {
1324 XLALPrintError( "read_sft_bins_from_fp(): Failed to read SFT-header!\n" );
1325 *firstBinRead = 2;
1326 return ( 0 );
1327 }
1328 ret->data = data;
1329 }
1330
1331 tmp = ret->f0 / ret->deltaF;
1332 firstSFTbin = lround( tmp );
1333 lastSFTbin = firstSFTbin + numSFTbins - 1;
1334
1335 /* limit the interval to be read to what's actually in the SFT */
1336 if ( firstBin2read < firstSFTbin ) {
1337 firstBin2read = firstSFTbin;
1338 }
1339 if ( lastBin2read > lastSFTbin ) {
1340 lastBin2read = lastSFTbin;
1341 }
1342
1343 /* check that requested interval is found in SFT */
1344 /* return 0 (no bins read) if this isn't the case */
1345 if ( firstBin2read > lastBin2read ) {
1346 *firstBinRead = 0;
1347 return ( 0 );
1348 }
1349
1350 *firstBinRead = firstBin2read;
1351
1352 offsetBins = firstBin2read - firstSFTbin;
1353 offsetBytes = offsetBins * 2 * sizeof( REAL4 );
1354 numBins2read = lastBin2read - firstBin2read + 1;
1355
1356 if ( ret->data->length < numBins2read ) {
1357 XLALPrintError( "read_sft_bins_from_fp(): passed SFT has not enough bins (%u/%u)\n",
1358 ret->data->length, numBins2read );
1359 *firstBinRead = 1;
1360 return ( 0 );
1361 }
1362
1363 /* seek to the desired bins */
1364 if ( fseek( fp, offsetBytes, SEEK_CUR ) != 0 ) {
1365 XLALPrintError( "read_sft_bins_from_fp(): Failed to fseek() to first frequency-bin %d: %s\n",
1366 firstBin2read, strerror( errno ) );
1367 *firstBinRead = 3;
1368 return ( 0 );
1369 }
1370
1371 /* actually read the data */
1372 if ( numBins2read != fread( ret->data->data, sizeof( COMPLEX8 ), numBins2read, fp ) ) {
1373 XLALPrintError( "read_sft_bins_from_fp(): Failed to read %d bins from SFT!\n", numBins2read );
1374 *firstBinRead = 4;
1375 return ( 0 );
1376 }
1377
1378 /* update the start-frequency entry in the SFT-header to the new value */
1379 ret->f0 = 1.0 * firstBin2read * ret->deltaF;
1380
1381 /* take care of normalization and endian-swapping */
1382 if ( swapEndian ) {
1383 UINT4 i;
1384
1385 for ( i = 0; i < numBins2read; i ++ ) {
1386 REAL4 re = crealf( ret->data->data[i] );
1387 REAL4 im = cimagf( ret->data->data[i] );
1388
1389 if ( swapEndian ) {
1390 endian_swap( ( CHAR * ) &re, sizeof( re ), 1 );
1391 endian_swap( ( CHAR * ) &im, sizeof( im ), 1 );
1392 }
1393
1394 ret->data->data[i] = crectf( re, im );
1395 } /* for i < numBins2read */
1396 } /* swapEndian */
1397
1398 /* return last bin read */
1399 return ( lastBin2read );
1400
1401} /* read_sft_bins_from_fp() */
1402
1403
1404/**
1405 * Check the SFT-block starting at fp for valid crc64 checksum.
1406 * Restores filepointer before leaving.
1407 */
1408BOOLEAN
1410{
1411 long save_filepos;
1412 UINT8 computed_crc, ref_crc;
1414 UINT4 numBins;
1415 UINT2 windowspec;
1416 CHAR *SFTcomment = NULL;
1417 UINT4 data_len;
1418 char block[BLOCKSIZE];
1419 UINT4 version;
1420 BOOLEAN need_swap;
1421
1422 /* input consistency */
1423 if ( !fp ) {
1424 XLALPrintError( "\nhas_valid_crc64() was called with NULL filepointer!\n\n" );
1425 return FALSE;
1426 }
1427
1428 /* store fileposition for restoring in case of failure */
1429 if ( ( save_filepos = ftell( fp ) ) == -1 ) {
1430 XLALPrintError( "\nERROR: ftell() failed: %s\n\n", strerror( errno ) );
1431 return -1;
1432 }
1433
1434 if ( read_SFTversion_from_fp( &version, &need_swap, fp ) != 0 ) {
1435 return -1;
1436 }
1437
1438 if ( !( MIN_SFT_VERSION <= version && version <= MAX_SFT_VERSION ) ) {
1439 XLALPrintError( "\nhas_valid_crc64() was called on an invalid version(=%u) SFT.\n\n", version );
1440 return -1;
1441 }
1442
1443 /* ----- compute CRC ----- */
1444 /* read the header, unswapped, only to obtain it's crc64 checksum */
1445 if ( read_header_from_fp( fp, &header, &numBins, &computed_crc, &ref_crc, &windowspec, &SFTcomment, need_swap ) != 0 ) {
1446 if ( SFTcomment ) {
1447 LALFree( SFTcomment );
1448 }
1449 return FALSE;
1450 }
1451 if ( SFTcomment ) {
1452 LALFree( SFTcomment );
1453 }
1454
1455 /* read data in blocks of BLOCKSIZE, computing CRC */
1456 data_len = numBins * 8 ; /* COMPLEX8 data */
1457 while ( data_len > 0 ) {
1458 /* read either BLOCKSIZE or amount remaining */
1459 int toread = ( BLOCKSIZE < data_len ) ? BLOCKSIZE : data_len;
1460 if ( toread != ( int )fread( block, 1, toread, fp ) ) {
1461 XLALPrintError( "\nFailed to read all frequency-bins from SFT.\n\n" );
1462 return FALSE;
1463 }
1464 data_len -= toread;
1465
1466 /* compute CRC64: don't endian-swap for that! */
1467 computed_crc = crc64( ( const unsigned char * )block, toread, computed_crc );
1468
1469 } /* while data */
1470
1471 /* check that checksum is consistent */
1472 return ( computed_crc == ref_crc );
1473
1474} /* has_valid_crc64 */
1475
1476/// @}
#define __func__
log an I/O error, i.e.
#define GPS2REAL8(gps)
convert GPS-time to REAL8
int j
ProcessParamsTable * ptr
int k
#define LALCalloc(m, n)
#define LALFree(p)
#define XLALLOADSFTSERROR(eno)
#define BLOCKSIZE
blocksize used in SFT-reading for the CRC-checksum computation (has to be multiple of 8 !...
Definition: SFTfileIO.c:34
Internal SFT types and functions.
#define GPSZERO(gps)
Definition: SFTinternal.h:81
unsigned long long crc64(const unsigned char *data, unsigned int length, unsigned long long crc)
#define MAX_SFT_VERSION
Definition: SFTinternal.h:54
#define GPSEQUAL(gps1, gps2)
Definition: SFTinternal.h:80
#define MIN_SFT_VERSION
Definition: SFTinternal.h:53
unsigned char BOOLEAN
#define XLAL_INIT_MEM(x)
uint64_t UINT8
double REAL8
#define XLAL_INIT_DECL(var,...)
#define crectf(re, im)
uint16_t UINT2
char CHAR
uint32_t UINT4
float complex COMPLEX8
int32_t INT4
float REAL4
#define lalDebugLevel
void * XLALMalloc(size_t n)
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
const char * SFTErrorMessage(int errorcode)
int ValidateSFTFile(const char *fname)
Verify that the contents of a SFT file are valid.
SFTtype * XLALCreateSFT(UINT4 numBins)
XLAL function to create one SFT-struct.
Definition: SFTtypes.c:152
MultiSFTVector * XLALLoadMultiSFTs(const SFTCatalog *inputCatalog, REAL8 fMin, REAL8 fMax)
Function to load a catalog of SFTs from possibly different detectors.
Definition: SFTfileIO.c:416
void XLALDestroyMultiSFTCatalogView(MultiSFTCatalogView *multiView)
Destroys a MultiSFTCatalogView, without freeing the original catalog that the 'view' was referring to...
Definition: SFTcatalog.c:496
UINT4 read_sft_bins_from_fp(SFTtype *ret, UINT4 *firstBinRead, UINT4 firstBin2read, UINT4 lastBin2read, FILE *fp)
Definition: SFTfileIO.c:1282
void XLALDestroyMultiSFTVector(MultiSFTVector *multvect)
Destroy a multi SFT-vector.
Definition: SFTtypes.c:424
static int read_header_from_fp(FILE *fp, SFTtype *header, UINT4 *nsamples, UINT8 *header_crc64, UINT8 *ref_crc64, UINT2 *SFTwindowspec, CHAR **SFTcomment, BOOLEAN swapEndian)
Definition: SFTfileIO.c:1102
MultiSFTCatalogView * XLALGetMultiSFTCatalogView(const SFTCatalog *catalog)
Return a MultiSFTCatalogView generated from an input SFTCatalog.
Definition: SFTcatalog.c:380
REAL8 TSFTfromDFreq(REAL8 dFreq)
Definition: SFTtypes.c:1144
void endian_swap(CHAR *pdata, size_t dsize, size_t nelements)
Definition: SFTfileIO.c:844
int build_sft_windowspec(UINT2 *windowspec, CHAR(*windowspec_str)[9], const char *window_type, REAL8 window_param)
Build an SFT 2-byte 'windowspec' or filename field 'windowspec_str' for the window given by 'window_t...
Definition: SFTnaming.c:691
int XLALWriteSFT2FilePointer(const SFTtype *sft, FILE *fp, const CHAR *SFTwindowtype, const REAL8 SFTwindowparam, const CHAR *SFTcomment)
Write the given SFTtype to a FILE pointer.
Definition: SFTfileIO.c:488
MultiSFTVector * XLALLoadMultiSFTsFromView(const MultiSFTCatalogView *multiCatalogView, REAL8 fMin, REAL8 fMax)
This function loads a MultiSFTVector from a given input MultiSFTCatalogView, otherwise the documentat...
Definition: SFTfileIO.c:449
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
FILE * fopen_SFTLocator(const struct tagSFTLocator *locator)
Open an "SFT" defined by the SFT-locator, return a FILE-pointer to the beginning of this SFT.
Definition: SFTfileIO.c:882
SFTVector * XLALLoadSFTs(const SFTCatalog *catalog, REAL8 fMin, REAL8 fMax)
Load the given frequency-band [fMin, fMax) (half-open) from the SFT-files listed in the SFT-'catalogu...
Definition: SFTfileIO.c:87
int read_sft_header_from_fp(FILE *fp, SFTtype *header, UINT4 *version, UINT8 *crc64, UINT2 *SFTwindowspec, BOOLEAN *swapEndian, CHAR **SFTcomment, UINT4 *numBins)
Definition: SFTfileIO.c:992
UINT4 XLALRoundFrequencyDownToSFTBin(const REAL8 freq, const REAL8 df)
Round a REAL8 frequency down to the nearest integer SFT bin number.
Definition: SFTtypes.c:70
void XLALDestroySFT(SFTtype *sft)
Destructor for one SFT.
Definition: SFTtypes.c:176
int XLALWriteSFTVector2NamedFile(const SFTVector *sftVect, const CHAR *SFTfilename, const CHAR *SFTwindowtype, const REAL8 SFTwindowparam, const CHAR *SFTcomment)
Write the given SFTVector to a single merged SFT file with the supplied filename.
Definition: SFTfileIO.c:712
int XLALWriteSFTVector2StandardFile(const SFTVector *sftVect, SFTFilenameSpec *SFTfnspec, const CHAR *SFTcomment, const BOOLEAN merged)
Write the given SFTVector to SFT file(s) with a standard () filename(s).
Definition: SFTfileIO.c:755
int XLALWriteSFT2StandardFile(const SFTtype *sft, SFTFilenameSpec *SFTfnspec, const CHAR *SFTcomment)
Write the given SFTtype to a SFT file with a standard () filename.
Definition: SFTfileIO.c:656
int compareSFTloc(const void *ptr1, const void *ptr2)
Definition: SFTtypes.c:1182
int XLALWriteSFT2NamedFile(const SFTtype *sft, const CHAR *SFTfilename, const CHAR *SFTwindowtype, const REAL8 SFTwindowparam, const CHAR *SFTcomment)
Write the given SFTtype to a SFT file with the supplied filename.
Definition: SFTfileIO.c:598
BOOLEAN has_valid_crc64(FILE *fp)
Check the SFT-block starting at fp for valid crc64 checksum.
Definition: SFTfileIO.c:1409
SFTVector * XLALCreateSFTVector(UINT4 numSFTs, UINT4 numBins)
XLAL function to create an SFTVector of numSFT SFTs with SFTlen frequency-bins (which will be allocat...
Definition: SFTtypes.c:230
int XLALCheckSFTFileIsValid(const char *fname)
Verify that the contents of a SFT file are valid.
Definition: SFTfileIO.c:834
int read_SFTversion_from_fp(UINT4 *version, BOOLEAN *need_swap, FILE *fp)
Read valid SFT version-number at position fp, and determine if we need to endian-swap the data.
Definition: SFTfileIO.c:916
BOOLEAN XLALIsValidCWDetector(const CHAR *name)
Determine if 'name' is a valid detector name or prefix.
Definition: SFTnaming.c:188
#define XLAL_ERROR_NULL(...)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EIO
XLAL_EINVAL
float data[BLOCKSIZE]
Definition: hwinject.c:360
head
size
int deltaF
merged
#define TRUE
#define FALSE
REAL8 version
Definition: SFTfileIO.c:39
INT4 comment_length
Definition: SFTfileIO.c:48
INT4 nsamples
Definition: SFTfileIO.c:44
UINT8 crc64
Definition: SFTfileIO.c:45
CHAR detector[2]
Definition: SFTfileIO.c:46
INT4 gps_nsec
Definition: SFTfileIO.c:41
INT4 first_frequency_index
Definition: SFTfileIO.c:43
UINT2 windowspec
Definition: SFTfileIO.c:47
INT4 gps_sec
Definition: SFTfileIO.c:40
REAL8 tbase
Definition: SFTfileIO.c:42
CHAR name[LALNameLength]
COMPLEX8Sequence * data
A vector of COMPLEX8FrequencySeries.
COMPLEX8FrequencySeries * data
Pointer to the data array.
UINT4 length
Number of elements in array.
COMPLEX8 * data
INT4 gpsNanoSeconds
A multi-SFT-catalogue "view": a multi-IFO vector of SFT-catalogs.
Definition: SFTfileIO.h:255
SFTCatalog * data
array of SFT-catalog pointers
Definition: SFTfileIO.h:260
UINT4 length
number of detectors
Definition: SFTfileIO.h:259
A collection of SFT vectors – one for each IFO in a multi-IFO search.
Definition: SFTfileIO.h:179
An "SFT-catalogue": a vector of SFTdescriptors, as returned by XLALSFTdataFind()
Definition: SFTfileIO.h:238
SFTDescriptor * data
array of data-entries describing matched SFTs
Definition: SFTfileIO.h:243
UINT4 length
number of SFTs in catalog
Definition: SFTfileIO.h:242
SFTtype header
SFT-header info.
Definition: SFTfileIO.h:228
struct tagSFTLocator * locator
internal description of where to find this SFT [opaque!]
Definition: SFTfileIO.h:227
UINT4 numBins
number of frequency-bins in this SFT
Definition: SFTfileIO.h:232
Structure specifying an SFT file name, following the convention in .
Definition: SFTfileIO.h:266
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 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 detector[3]
2-character detector prefix (e.g.
Definition: SFTfileIO.h:270
UINT4 numSFTs
Number of SFTs in the file; set by XLALWriteSFT[Vector]2StandardFile()
Definition: SFTfileIO.h:269
CHAR window_type[32]
window function applied to SFT
Definition: SFTfileIO.h:272
REAL8 window_param
parameter of window function, if required
Definition: SFTfileIO.h:273
segments read so far from one SFT
Definition: SFTfileIO.c:52
UINT4 last
last bin in this segment
Definition: SFTfileIO.c:54
struct tagSFTLocator * lastfrom
last bin read from this locator
Definition: SFTfileIO.c:56
LIGOTimeGPS epoch
timestamp of this SFT
Definition: SFTfileIO.c:55
UINT4 first
first bin in this segment
Definition: SFTfileIO.c:53
CHAR * fname
Definition: SFTinternal.h:90
enum @1 epoch
double pad