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
SFTReferenceLibrary.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 Karl Wette
3 * Copyright (C) 2004, 2005 Bruce Allen, Reinhard Prix
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 * \addtogroup lalpulsar_sft
23 * \author Bruce Allen, Reinhard Prix
24 * \brief This is a reference library for the SFT data format \cite SFT-spec
25 */
26
27#include "config.h"
28
29#include <stdio.h>
30#include <string.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <math.h>
34
35#include <lal/XLALError.h>
36
37#include "SFTReferenceLibrary.h"
38#include "SFTinternal.h"
39
40/*
41 The quantity below is: D800000000000000 (base-16) =
42 1101100000000000000000000000000000000000000000000000000000000000
43 (base-2). The primitive polynomial is x^64 + x^4 + x^3 + x + 1.
44*/
45#define POLY64 0xd800000000000000ULL
46#define TABLELEN 256
47#define BLOCKSIZE 65536
48
49/* some local prototypes */
50unsigned long long crc64( const unsigned char *data, unsigned int length, unsigned long long crc );
51static void swap2( char *location );
52static void swap4( char *location );
53static void swap8( char *location );
54static int validate_sizes( void );
55static int validate_version( double version );
56
57/* The crc64 checksum of M bytes of data at address data is returned
58 by crc64(data, M, ~(0ULL)). Call the function multiple times to
59 compute the checksum of data made in contiguous chunks, setting
60 final argument to the previously accumulated checksum value. */
61unsigned long long crc64( const unsigned char *data,
62 unsigned int length,
63 unsigned long long crc )
64{
65
66 unsigned long long CRCTable[TABLELEN];
67 unsigned int i;
68
69 /* is there is no data, simply return previous checksum value */
70 if ( !length || !data ) {
71 return crc;
72 }
73
74 /* initialize the CRC table for fast computation. We could keep
75 this table in memory to make the computation faster, but that is
76 not re-entrant for multi-threaded code.
77 */
78 for ( i = 0; i < TABLELEN; i++ ) {
79 int j;
80 unsigned long long part = i;
81 for ( j = 0; j < 8; j++ ) {
82 if ( part & 1 ) {
83 part = ( part >> 1 ) ^ POLY64;
84 } else {
85 part >>= 1;
86 }
87 }
88 CRCTable[i] = part;
89 }
90
91 /* compute the CRC-64 code */
92 for ( i = 0; i < length; i++ ) {
93 unsigned long long temp1 = crc >> 8;
94 unsigned long long temp2 = CRCTable[( crc ^ ( unsigned long long ) data[i] ) & 0xff];
95 crc = temp1 ^ temp2;
96 }
97
98 return crc;
99}
100
101/* swap 2, 4 or 8 bytes. Point to low address */
102static void swap2( char *location )
103{
104 char tmp = *location;
105 *location = *( location + 1 );
106 *( location + 1 ) = tmp;
107 return;
108}
109
110static void swap4( char *location )
111{
112 char tmp = *location;
113 *location = *( location + 3 );
114 *( location + 3 ) = tmp;
115 swap2( location + 1 );
116 return;
117}
118
119static void swap8( char *location )
120{
121 char tmp = *location;
122 *location = *( location + 7 );
123 *( location + 7 ) = tmp;
124 tmp = *( location + 1 );
125 *( location + 1 ) = *( location + 6 );
126 *( location + 6 ) = tmp;
127 swap4( location + 2 );
128 return;
129}
130
131/* this routine checks that the assumed sizes and structure packing
132 conventions of this code are valid. These checks could also be
133 done at compile time with #error statements */
134static int validate_sizes( void )
135{
136 if (
137 sizeof( char ) != 1 ||
138 sizeof( int ) != 4 ||
139 sizeof( long long ) != 8 ||
140 sizeof( struct headertag2 ) != 48
141 ) {
142 return SFTESIZEWRONG;
143 }
144
145 return SFTNOERROR;
146}
147
148
149static int validate_version( double version )
150{
151 for ( int v = MIN_SFT_VERSION; v <= MAX_SFT_VERSION; ++v ) {
152 if ( version == v ) {
153 return 1;
154 }
155 }
156 return 0;
157}
158
159
160/* translate return values from SFT routines into human-readable
161 character string error messages */
162const char *SFTErrorMessage( int errorcode )
163{
164
165 switch ( errorcode ) {
166 case 0:
167 return "Success";
168 case SFTENULLFP:
169 return "SFT file pointer is NULL";
170 case SFTESEEK:
171 return "SFT fseek() failed in stream";
172 case SFTEREAD:
173 return "SFT fread() failed in stream";
174 case SFTEUNKNOWN:
175 return "SFT version in header is unknown";
176 case SFTEGPSNSEC:
177 return "SFT header GPS nsec not in range 0 to 10^9-1";
178 case SFTEBADCOMMENT:
179 return "SFT comment length not a multiple of 8";
180 case SFTEGETSTREAMPOS:
181 return "SFT fgetpos() failed: unable to save position of stream";
182 case SFTEBADCRC64:
183 return "SFT corrupted: CRC checksum in header does not match data";
185 return "SFT fsetpos() failed: unable to restore stream position";
186 case SFTENOMEM:
187 return "SFT calloc() failed: unable to allocate memory";
188 case SFTESIZEWRONG:
189 return "SFT sizeof() objects does not match assumptions";
190 case SFTEWRITE:
191 return "SFT fwrite() failed";
192 case SFTENULLPOINTER:
193 return "SFT library routine passed a null data pointer";
194 case SFTENONE:
195 return "SFT file empty (zero length)";
197 return "SFT comment contains data AFTER null character";
199 return "SFT comment field is not null-terminated";
201 return "SFT GPS times not increasing between SFT blocks";
202 case SFTETBASECHANGES:
203 return "SFT time base changes between SFT blocks";
205 return "SFT first frequency index changes between SFT blocks";
207 return "SFT number of data samples changes between SFT blocks";
209 return "SFT window specification changes between SFT blocks";
211 return "SFT instrument changes between SFT blocks";
213 return "SFT version changes between SFT blocks";
214 case SFTETBASENOTPOS:
215 return "SFT time base is not positive";
217 return "SFT first frequency index is negative";
219 return "SFT number of data samples is not positive";
221 return "SFT detector not one of A1 B1 E1 G1 H1 H2 K1 L1 N1 O1 P1 T1 V1 V2 X1";
222 case SFTEBEFOREDATA:
223 return "SFT data requested lies before available data";
224 case SFTEAFTERDATA:
225 return "SFT data requested lies after available data";
226 case SFTNOTFINITE:
227 return "SFT data contains a non-FINITE (+/- Inf, NaN) value";
228 }
229 return "SFT Error Code not recognized";
230}
231
232/* return values: see header file
233 On return, this routine leaves the file pointer at the end of the SFT
234*/
235int WriteSFT( FILE *fp, /* stream to write to */
236 int gps_sec, /* GPS sec of first sample */
237 int gps_nsec, /* GPS nsec of first sample */
238 double tbase, /* time baseline of SFTs */
239 int firstfreqindex, /* index of first frequency bin included in data (0=DC)*/
240 int nsamples, /* number of frequency bins to include in SFT */
241 const char *detector,/* channel-prefix defining detector */
242 unsigned short windowspec, /* SFT windowspec */
243 const char *comment, /* null-terminated comment string to include in SFT */
244 float *data /* points to nsamples x 2 x floats (Real/Imag) */
245 )
246{
247 struct headertag2 header;
248 int comment_length, inc, i;
249 char pad[7];
250
251 /* check that all data types have correct length */
252 if ( validate_sizes() ) {
253 return SFTESIZEWRONG;
254 }
255
256 /* check that file pointer is valid */
257 if ( !fp ) {
258 return SFTENULLFP;
259 }
260
261 /* check that nsec times are sensible */
262 if ( gps_nsec < 0 || gps_nsec > 999999999 ) {
263 return SFTEGPSNSEC;
264 }
265
266 /* check that tbase is positive */
267 if ( tbase <= 0.0 ) {
268 return SFTETBASENOTPOS;
269 }
270
271 /* check that first frequency index is non-negative */
272 if ( firstfreqindex < 0 ) {
273 return SFTEFIRSTINDEXNEG;
274 }
275
276 /* check that number of samples is 1 or greater */
277 if ( nsamples <= 0 ) {
278 return SFTENSAMPLESNOTPOS;
279 }
280
281 /* check that detector type is defined and data is present */
282 if ( !detector || !data ) {
283 return SFTENULLPOINTER;
284 }
285
286 /* check that detector type is recognized */
287 if ( strlen( detector ) > 2 || unknownDetector( detector ) ) {
289 }
290
291 /* comment length including null terminator to string must be an
292 integer multiple of eight bytes. comment==NULL means 'no
293 comment' */
294 if ( comment ) {
295 comment_length = strlen( comment ) + 1;
296 inc = ( 8 - ( comment_length % 8 ) ) % 8;
297 for ( i = 0; i < inc; i++ ) {
298 pad[i] = 0;
299 }
300 } else {
301 comment_length = 0;
302 inc = 0;
303 }
304
305 /* fill out header */
306 header.version = MAX_SFT_VERSION;
307 header.gps_sec = gps_sec;
308 header.gps_nsec = gps_nsec;
309 header.tbase = tbase;
310 header.firstfreqindex = firstfreqindex;
311 header.nsamples = nsamples;
312 header.crc64 = 0;
313 header.detector[0] = detector[0];
314 header.detector[1] = detector[1];
315 header.windowspec = windowspec;
316 header.comment_length = comment_length + inc;
317
318 /* compute CRC of header */
319 header.crc64 = crc64( ( const unsigned char * )&header, sizeof( header ), ~( 0ULL ) );
320
321 /* compute CRC of comment */
322 header.crc64 = crc64( ( const unsigned char * )comment, comment_length, header.crc64 );
323
324 /* compute CRC of comment padding */
325 header.crc64 = crc64( ( const unsigned char * )pad, inc, header.crc64 );
326
327 /* compute CRC of data */
328 header.crc64 = crc64( ( const unsigned char * )data, nsamples * 2 * sizeof( float ), header.crc64 );
329
330 /* write the header to file */
331 if ( 1 != fwrite( ( const void * )&header, sizeof( header ), 1, fp ) ) {
332 return SFTEWRITE;
333 }
334
335 /* write the comment to file */
336 if ( comment_length != ( int )fwrite( ( const void * )comment, 1, comment_length, fp ) ) {
337 return SFTEWRITE;
338 }
339
340 /* write comment padding to file */
341 if ( inc != ( int )fwrite( ( const void * )pad, 1, inc, fp ) ) {
342 return SFTEWRITE;
343 }
344
345 /* write the data to the file. Data must be packed
346 REAL,IMAG,REAL,IMAG,... */
347 if ( nsamples != ( int )fwrite( ( const void * )data, 2 * sizeof( float ), nsamples, fp ) ) {
348 return SFTEWRITE;
349 }
350
351 return SFTNOERROR;
352}
353
354/* On return this routine leaves the stream in the same
355 place as when the routine was called */
356int ReadSFTHeader( FILE *fp, /* stream to read */
357 struct headertag2 *info, /* address to return header */
358 char **comment, /* if non-NULL, put pointer to comment */
359 int *swapendian, /* set nonzero if data in reverse endian order */
360 int validate ) /* validate checksum of the file */
361{
362 struct headertag2 header, header_unswapped;
363 int swap = 0;
364 int what, retval = 0;
365 fpos_t streamposition;
366 char *mycomment = NULL;
367
368 /* check that all data types have correct length */
369 if ( validate_sizes() ) {
370 return SFTESIZEWRONG;
371 }
372
373 /* check that pointers are valid */
374 if ( !fp ) {
375 return SFTENULLFP;
376 }
377
378 if ( !info || !swapendian ) {
379 return SFTENULLPOINTER;
380 }
381
382 /* save stream position */
383 if ( fgetpos( fp, &streamposition ) ) {
384 return SFTEGETSTREAMPOS;
385 }
386
387 /* read in header. Note that the second and third arguments to fread() are reversed
388 from conventional practice, so that we can see if the file is zero length */
389 if ( sizeof( header ) != ( what = fread( ( void * )&header, 1, sizeof( header ), fp ) ) ) {
390 if ( !what && feof( fp ) ) {
391 retval = SFTENONE;
392 } else {
393 retval = SFTEREAD;
394 }
395 goto error;
396 }
397
398 /* save an unswapped copy */
399 header_unswapped = header;
400
401 /* check endian ordering, and swap if needed */
402 if ( !validate_version( header.version ) ) {
403 swap8( ( char * )&header.version );
404 swap4( ( char * )&header.gps_sec );
405 swap4( ( char * )&header.gps_nsec );
406 swap8( ( char * )&header.tbase );
407 swap4( ( char * )&header.firstfreqindex );
408 swap4( ( char * )&header.nsamples );
409 swap8( ( char * )&header.crc64 );
410 swap2( ( char * )&header.windowspec );
411 swap4( ( char * )&header.comment_length );
412 swap = 1;
413 }
414
415 /* check if header version is recognized */
416 if ( !validate_version( header.version ) ) {
417 retval = SFTEUNKNOWN;
418 goto error;
419 }
420
421 if ( header.comment_length % 8 ) {
422 retval = SFTEBADCOMMENT;
423 goto error;
424 }
425
426 /* check that number of samples is 1 or greater. We do this check
427 before calculating CRC since the number of values to CRC check
428 must be known first */
429 if ( header.nsamples <= 0 ) {
430 retval = SFTENSAMPLESNOTPOS;
431 goto error;
432 }
433
434 /* validate crc64 checksum ?? Do this BEFORE other checks since if
435 a problem occurs it is more likely file corruption than a bad
436 SFT */
437 if ( validate ) {
438 unsigned long long crc;
439 unsigned long long crc64save = header.crc64;
440 int total_length = header.comment_length + 2 * sizeof( float ) * header.nsamples;
441 char block[BLOCKSIZE];
442 fpos_t streamposition2;
443 int i, tocheck, foundhidden = 0, comment_left = header.comment_length, foundnull = !comment_left;
444
445 /* save stream position */
446 if ( fgetpos( fp, &streamposition2 ) ) {
447 retval = SFTEGETSTREAMPOS;
448 goto error;
449 }
450
451 /* compute CRC of header */
452 header_unswapped.crc64 = 0ULL;;
453 crc = crc64( ( unsigned char * )&header_unswapped, sizeof( header_unswapped ), ~( 0ULL ) );
454
455 /* read data in lengths of BLOCKSIZE, computing CRC */
456 while ( total_length > 0 ) {
457 /* read either BLOCKSIZE or amount remaining */
458 int toread = ( BLOCKSIZE < total_length ) ? BLOCKSIZE : total_length;
459 if ( toread != ( int )fread( block, 1, toread, fp ) ) {
460 retval = SFTEREAD;
461 goto error;
462 }
463 total_length -= toread;
464 crc = crc64( ( unsigned char * )block, toread, crc );
465
466 /* check to see if comment contains NULL termination character
467 and no hidden characters */
468 tocheck = ( comment_left < toread ) ? comment_left : toread;
469 for ( i = 0; i < tocheck; i++ ) {
470 if ( !block[i] ) {
471 foundnull = 1;
472 }
473 if ( foundnull && block[i] ) {
474 foundhidden = 1;
475 }
476 }
477 comment_left -= tocheck;
478 }
479
480 /* check that checksum is consistent */
481 if ( crc != crc64save ) {
482 XLALPrintInfo( "%s: CRC64 computes as %llu\n", __func__, crc );
483 XLALPrintInfo( "%s: CRC64 in SFT is %llu\n", __func__, crc64save );
484 retval = SFTEBADCRC64;
485 goto error;
486 }
487
488 /* check that comment has correct NULL termination */
489 if ( !foundnull ) {
490 retval = SFTENONULLINCOMMENT;
491 goto error;
492 }
493
494 /* check that comment has no hidden characters */
495 if ( foundhidden ) {
496 retval = SFTEHIDDENCOMMENT;
497 goto error;
498 }
499
500 /* return to position just after header to read comment if desired */
501 if ( fsetpos( fp, &streamposition2 ) ) {
502 retval = SFTERESTORESTREAMPOS;
503 goto error;
504 }
505 }
506
507 /* check that time stamps are in a valid range */
508 if ( header.gps_nsec < 0 || header.gps_nsec > 999999999 ) {
509 retval = SFTEGPSNSEC;
510 goto error;
511 }
512
513 /* check that tbase is positive */
514 if ( header.tbase <= 0.0 ) {
515 retval = SFTETBASENOTPOS;
516 goto error;
517 }
518
519 /* check that first frequency index is non-negative */
520 if ( header.firstfreqindex < 0 ) {
521 retval = SFTEFIRSTINDEXNEG;
522 goto error;
523 }
524
525 /* check that detector type is known */
526 if ( unknownDetector( header.detector ) ) {
528 }
529
530 /* if user has asked for comment, store it */
531 if ( comment && header.comment_length ) {
532 int i;
533
534 /* first allocate memory for storing the comment */
535 if ( !( mycomment = calloc( header.comment_length, 1 ) ) ) {
536 retval = SFTENOMEM;
537 goto error;
538 }
539
540 /* now read the comment into memory */
541 if ( header.comment_length != ( int )fread( mycomment, 1, header.comment_length, fp ) ) {
542 free( mycomment );
543 mycomment = NULL;
544 retval = SFTEREAD;
545 goto error;
546 }
547
548 /* check that the comment is null-terminated and contains no
549 messages 'hidden' after a NULL character */
550 retval = SFTENONULLINCOMMENT;
551 for ( i = 0; i < header.comment_length; i++ ) {
552 if ( !mycomment[i] ) {
553 retval = 0;
554 }
555 if ( !retval && mycomment[i] ) {
556 retval = SFTEHIDDENCOMMENT;
557 break;
558 }
559 }
560 if ( retval ) {
561 free( mycomment );
562 mycomment = NULL;
563 goto error;
564 }
565 }
566
567error:
568 /* restore stream pointer to the correct position */
569 if ( fsetpos( fp, &streamposition ) ) {
570 retval = SFTERESTORESTREAMPOS;
571 }
572
573 if ( retval ) {
574 return retval;
575 }
576
577 /* no errors found: now set return values and return */
578 *swapendian = swap;
579
580 if ( comment )
581 /* note: mycomment may be NULL if there is NO comment */
582 {
583 *comment = mycomment;
584 }
585
586 /* return header-info */
587 *info = header;
588
589 return SFTNOERROR;
590}
591
592
593
594int ReadSFTData( FILE *fp, /* data file. Position left unchanged on return */
595 float *data, /* location where data should be written */
596 int firstbin, /* first frequency bin to read from data set */
597 int nsamples, /* number of frequency bin samples to retrieve */
598 char **comment, /* if non-NULL, will contain pointer to comment string */
599 struct headertag2 *info /* if non-NULL, will contain header information */
600 )
601{
602 fpos_t streamposition;
603 int retval = 0, swapendian;
604 int seekforward;
605 struct headertag2 myinfo;
606
607 /* check for null pointers */
608 if ( !fp ) {
609 return SFTENULLFP;
610 }
611
612 if ( !data && nsamples ) {
613 return SFTENULLPOINTER;
614 }
615
616 /* save position of stream */
617 if ( fgetpos( fp, &streamposition ) ) {
618 return SFTEGETSTREAMPOS;
619 }
620
621 /* read header of SFT */
622 if ( ( retval = ReadSFTHeader( fp, &myinfo, comment, &swapendian, 0 ) ) ) {
623 goto error;
624 }
625
626 /* sanity checks -- do we ask for data before the first frequency bin */
627 if ( firstbin < myinfo.firstfreqindex ) {
628 retval = SFTEBEFOREDATA;
629 goto error;
630 }
631
632 /* warning, after this subtraction firstbin contains the offset to
633 the first requested bin! */
634 firstbin -= myinfo.firstfreqindex;
635
636 /* sanity checks -- do we ask for data after the last frequency bin */
637 if ( ( firstbin + nsamples ) > myinfo.nsamples ) {
638 retval = SFTEAFTERDATA;
639 goto error;
640 }
641
642 /* seek to start of data (skip comment if present) */
643 seekforward = sizeof( struct headertag2 ) + myinfo.comment_length + firstbin * 2 * sizeof( float );
644 if ( fseek( fp, seekforward, SEEK_CUR ) ) {
645 retval = SFTESEEK;
646 goto error2;
647 }
648
649 /* read in the data */
650 if ( nsamples != ( int )fread( ( void * )data, 2 * sizeof( float ), nsamples, fp ) ) {
651 retval = SFTEREAD;
652 goto error2;
653 }
654
655 /* byte reverse the data if necessary */
656 if ( swapendian ) {
657 int i;
658 for ( i = 0; i < 2 * nsamples; i++ ) {
659 swap4( ( char * )( data + i ) );
660 }
661 }
662
663error2:
664 /* free storage for the comemnt string */
665 if ( retval && comment && *comment ) {
666 free( *comment );
667 *comment = NULL;
668 }
669
670error:
671 /* return to starting position in stream */
672 if ( fsetpos( fp, &streamposition ) ) {
674 }
675
676 /* if no errors, return header information */
677 if ( info && !retval ) {
678 *info = myinfo;
679 }
680
681 return retval;
682}
683
684/* This routine returns zero if the two headers contain consistent
685 information, else an error code if they are not consistent */
686int CheckSFTHeaderConsistency( struct headertag2 *headerone, /* pointer to earlier header */
687 struct headertag2 *headertwo /* pointer to later header */
688 )
689{
690 /* check for null pointer */
691 if ( !headerone || !headertwo ) {
692 return SFTENULLPOINTER;
693 }
694
695 /* Same version number */
696 if ( headerone->version != headertwo->version ) {
697 return SFTEVERSIONCHANGES;
698 }
699
700 /* GPS times increasing */
701 if ( headerone->gps_sec > headertwo->gps_sec || ( headerone->gps_sec == headertwo->gps_sec && headerone->gps_nsec >= headertwo->gps_nsec ) ) {
703 }
704
705 /* Time base the same */
706 if ( headerone->tbase != headertwo->tbase ) {
707 return SFTETBASECHANGES;
708 }
709
710 /* First frequency index the same */
711 if ( headerone->firstfreqindex != headertwo->firstfreqindex ) {
713 }
714
715 /* Number of samples the same */
716 if ( headerone->nsamples != headertwo->nsamples ) {
717 return SFTENSAMPLESCHANGES;
718 }
719
720 /* check for identical detectors */
721 if ( ( headerone->detector[0] != headertwo->detector[0] ) || ( headerone->detector[1] != headertwo->detector[1] ) ) {
723 }
724
725 /* Window specification the same */
726 if ( headerone->windowspec != headertwo->windowspec ) {
728 }
729
730 return SFTNOERROR;
731}
732
733/* check that channel-prefix defines a 'known' detector. The list of
734 * known detectors implemented here for now follows the list in
735 * Appendix D of LIGO-T970130-F-E:
736 *
737 * returns 0 if known, error code otherwise */
738int unknownDetector( const char *detector )
739{
740 int i;
741 const char *knownDetectors[] = {
742 "A1", /* ALLEGRO */
743 "B1", /* NIOBE */
744 "E1", /* ET */
745 "G1", /* GEO_600 */
746 "H1", /* LHO_4k */
747 "H2", /* LHO_2k */
748 "K1", /* KAGRA */
749 "L1", /* LLO_4k */
750 "N1", /* Nautilus */
751 "O1", /* AURIGA */
752 "P1", /* CIT_40 */
753 "T1", /* TAMA_300 */
754 "V1", /* Virgo (3km) */
755 "V2", /* Virgo_CITF */
756 "X1", /* RXTE */
757 NULL
758 };
759
760 if ( !detector ) {
761 return SFTENULLPOINTER;
762 }
763
764 for ( i = 0; knownDetectors[i]; i++ ) {
765 if ( knownDetectors[i][0] == detector[0] && knownDetectors[i][1] == detector[1] ) {
766 return 0;
767 }
768 }
769
771
772} /* unknownDetector() */
773
774
775/**
776 * Verify that the contents of a SFT file are valid.
777 *
778 * \return 0 if all SFTs are valid.
779 * The exit status will be non-zero if any of the validity checks do not pass.
780 * Error codes are defined in SFTReferenceLibrary.h .
781 *
782 * This has been extracted from lalpulsar_SFTvalidate,
783 * original author: Bruce Allen
784 */
785int
786ValidateSFTFile( const char *fname )
787{
788
789 FILE *fp;
790 int err = 0;
791 float *data = NULL;
792
793 /* clear error status */
794 errno = 0;
795
796 /* open the file */
797 if ( !( fp = fopen( fname, "r" ) ) ) {
798 XLALPrintError( "%s: Unable to open %s", __func__, fname );
799 if ( errno ) {
800 XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
801 }
802 return SFTENULLFP;
803 }
804
805 /* and read successive SFTs blocks from the file and validate CRC
806 checksums */
807 struct headertag2 lastinfo;
808 memset( &lastinfo, 0, sizeof( lastinfo ) );
809 for ( int count = 0; 1; count++ ) {
810 struct headertag2 info;
811 int swapendian, move, j;
812
813 err = ReadSFTHeader( fp, &info, NULL, &swapendian, 1 );
814
815 /* at end of SFT file or merged SFT file blocks */
816 if ( err == SFTENONE && count ) {
817 err = 0;
818 break;
819 }
820
821 /* SFT was invalid: say why */
822 if ( err ) {
823 XLALPrintError( "%s: %s is not a valid SFT (%s)\n", __func__, fname, SFTErrorMessage( err ) );
824 if ( errno ) {
825 XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
826 }
827 break;
828 }
829
830 /* check that various bits of header information are consistent */
831 if ( count && ( err = CheckSFTHeaderConsistency( &lastinfo, &info ) ) ) {
832 XLALPrintError( "%s: %s is not a valid SFT (%s)\n", __func__, fname, SFTErrorMessage( err ) );
833 if ( errno ) {
834 XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
835 }
836 break;
837 }
838
839 /* check that data appears valid */
840 data = ( float * )realloc( ( void * )data, info.nsamples * 4 * 2 );
841 if ( !data ) {
842 errno = SFTENULLPOINTER;
843 XLALPrintError( "%s: ran out of memory at %s (%s)\n", __func__, fname, SFTErrorMessage( err ) );
844 if ( errno ) {
845 XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
846 }
847 break;
848 }
849
850 err = ReadSFTData( fp, data, info.firstfreqindex, info.nsamples, /*comment*/ NULL, /*headerinfo */ NULL );
851 if ( err ) {
852 XLALPrintError( "%s: %s is not a valid SFT (%s)\n", __func__, fname, SFTErrorMessage( err ) );
853 if ( errno ) {
854 XLALPrintError( "%s: errno=%i (%s)", __func__, errno, strerror( errno ) );
855 }
856 break;
857 }
858
859 for ( j = 0; j < info.nsamples; j++ ) {
860 if ( !isfinite( data[2 * j] ) || !isfinite( data[2 * j + 1] ) ) {
861 XLALPrintError( "%s: %s is not a valid SFT (data infinite at freq bin %d)\n", __func__, fname, j + info.firstfreqindex );
863 break;
864 }
865 }
866
867 /* keep copy of header for comparison the next time */
868 lastinfo = info;
869
870 /* Move forward to next SFT in merged file */
871 move = sizeof( struct headertag2 ) + info.nsamples * 2 * sizeof( float ) + info.comment_length;
872 fseek( fp, move, SEEK_CUR );
873 }
874
875 /* cleanup */
876 fclose( fp );
877 free( data );
878
879 return err;
880
881} /* ValidateSFTFile */
#define __func__
log an I/O error, i.e.
int j
static int validate_sizes(void)
static void swap2(char *location)
static void swap4(char *location)
unsigned long long crc64(const unsigned char *data, unsigned int length, unsigned long long crc)
static int validate_version(double version)
#define TABLELEN
static void swap8(char *location)
#define POLY64
#define BLOCKSIZE
Internal SFT types and functions.
#define MAX_SFT_VERSION
Definition: SFTinternal.h:54
#define MIN_SFT_VERSION
Definition: SFTinternal.h:53
const char * comment
Definition: SearchTiming.c:94
#define SFTENULLPOINTER
const char * SFTErrorMessage(int errorcode)
#define SFTENONE
#define SFTERESTORESTREAMPOS
#define SFTEVERSIONCHANGES
#define SFTEBADCRC64
#define SFTNOTFINITE
#define SFTETBASENOTPOS
int CheckSFTHeaderConsistency(struct headertag2 *headerone, struct headertag2 *headertwo)
#define SFTEHIDDENCOMMENT
#define SFTEUNKNOWN
#define SFTNOERROR
#define SFTETBASECHANGES
int unknownDetector(const char *detector)
#define SFTENSAMPLESCHANGES
#define SFTEFIRSTINDEXCHANGES
#define SFTENOMEM
#define SFTEWINDOWSPECCHANGES
#define SFTESEEK
int ReadSFTHeader(FILE *fp, struct headertag2 *info, char **comment, int *swapendian, int validate)
#define SFTEBEFOREDATA
#define SFTENULLFP
int ValidateSFTFile(const char *fname)
Verify that the contents of a SFT file are valid.
#define SFTEAFTERDATA
#define SFTENONULLINCOMMENT
#define SFTEINSTRUMENTUNKNOWN
#define SFTEGPSNSEC
#define SFTESIZEWRONG
#define SFTEGPSNOTINCREASING
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)
#define SFTEBADCOMMENT
#define SFTENSAMPLESNOTPOS
int ReadSFTData(FILE *fp, float *data, int firstbin, int nsamples, char **comment, struct headertag2 *info)
#define SFTEREAD
#define SFTEWRITE
#define SFTEINSTRUMENTCHANGES
#define SFTEFIRSTINDEXNEG
#define SFTEGETSTREAMPOS
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
long long count
Definition: hwinject.c:371
float data[BLOCKSIZE]
Definition: hwinject.c:360
unsigned long long crc64
unsigned short windowspec
double pad