LALPulsar  6.1.0.1-b72065a
SFTnaming.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010, 2014, 2016, 2022 Karl Wette
3  * Copyright (C) 2010 Chris Messenger
4  * Copyright (C) 2004, 2005 Reinhard Prix, Bernd Machenschalk, Alicia Sintes
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with with program; see the file COPYING. If not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301 USA
20  */
21 
22 /*---------- includes ----------*/
23 
24 #define _XOPEN_SOURCE // for isascii()
25 
26 #include <ctype.h>
27 
28 #include "SFTinternal.h"
29 
30 /*---------- macros ----------*/
31 
32 #define LAST_ELEMENT(buf) ( (buf)[XLAL_NUM_ELEM(buf) - 1] )
33 
34 #define STRCPYCHK(name, dest, src) do { \
35  const char *const STRCPYCHK_p = (src); \
36  XLAL_CHECK( strlen(STRCPYCHK_p) < sizeof(dest), XLAL_ESIZE, "%s '%s' does not fit in a buffer of size %zu", name, STRCPYCHK_p, sizeof(dest) ); \
37  strncpy((dest), STRCPYCHK_p, sizeof(dest)); \
38  } while(0)
39 
40 /*---------- constants ----------*/
41 
42 /** SFT window specification; see \cite SFT-spec */
43 static const struct {
44  const char *window_type;
45  const char *short_name;
48 } windowspec_table[] = {
49  /* zero-parameter windows */
50  { .window_type = "unknown", .short_name = "UNKN", .B = 0 },
51  { .window_type = "rectangular", .short_name = "RECT", .B = 1 },
52  { .window_type = "hann", .short_name = "HANN", .B = 2 },
53  /* one-parameter windows */
54  { .window_type = "tukey", .short_name = "TKEY", .A = 1 },
55 };
56 
57 /*---------- internal variables ----------*/
58 
59 /* Registry for special CW detectors which are assigned prefixes "[XYZ][0123456789]" */
61 
62 /*========== function definitions ==========*/
63 
64 /// \addtogroup SFTfileIO_h
65 /// @{
66 
67 /**
68  * Register a special detector for use with CW codes.
69  *
70  * The special detector must have a 2-character prefix of the form "[XYZ][0123456789]".
71  */
72 int
73 XLALRegisterSpecialCWDetector( const LALDetector *specialDetector )
74 {
75 
76  // check input
77  XLAL_CHECK( specialDetector != NULL, XLAL_EFAULT );
78  XLAL_CHECK( specialDetector->frDetector.prefix[2] == 0, XLAL_EINVAL );
79 
80  // store special CW detector in registry indexed by prefix
81 
82  const int index_1 = ( ( int ) specialDetector->frDetector.prefix[0] ) - ( ( int ) 'X' );
83  XLAL_CHECK( 0 <= index_1 && index_1 < 3, XLAL_EINVAL,
84  "Special CW detector prefix '%s' must start with one of [XYZ]", specialDetector->frDetector.prefix );
85 
86  const int index_2 = ( ( int ) specialDetector->frDetector.prefix[1] ) - ( ( int ) '0' );
87  XLAL_CHECK( 0 <= index_1 && index_1 < 9, XLAL_EINVAL,
88  "Special CW detector prefix '%s' must end with one of [0123456789]", specialDetector->frDetector.prefix );
89 
90  const int index = 10 * index_1 + index_2;
91 
92  SpecialDetectorRegistry[index] = *specialDetector;
93 
94  return XLAL_SUCCESS;
95 
96 }
97 
98 /**
99  * Parses valid CW detector names and prefixes. 'name' input can be either a valid detector name or prefix
100  *
101  * \return XLAL_SUCCESS if 'name' is a valid detector name/prefix, an XLAL error code on failure
102  *
103  * If passed a non-NULL pointer 'prefix', will be set to the Allocated prefix string (2 characters+0)
104  * for valid detectors, NULL otherwise.
105  *
106  * If passed a non-NULL pointer 'lalCachedIndex', will set to index >= 0 into the
107  * lalCachedDetectors[] array if found there, or -1 if it's one of the "CW special" detectors
108  *
109  * \note This should be the *only* function defining valid CW detector names and prefixes
110  *
111  * \note 'prefix' is allocated here and needs to be free'ed by caller!
112  *
113  * \note Unless 'exactMatch' is true, if first two characters of 'name' match a valid detector prefix,
114  * that is accepted, which allows passing longer strings beginning with a detector prefix ('H1:blabla')
115  * without extra hassle
116  */
117 int
118 XLALFindCWDetector( CHAR **prefix, INT4 *lalCachedIndex, const CHAR *name, const BOOLEAN exactMatch )
119 {
120  XLAL_CHECK( name != NULL, XLAL_EINVAL );
121  XLAL_CHECK( strlen( name ) >= 2, XLAL_EINVAL ); // need at least a full prefix 'letter+number'
122 
123  // ----- first check if 'name' corresponds to one of our 'CW special' detectors
124  const UINT4 numSpecialDetectors = sizeof( SpecialDetectorRegistry ) / sizeof( SpecialDetectorRegistry[0] );
125  for ( UINT4 i = 0; i < numSpecialDetectors; i ++ ) {
126  const CHAR *prefix_i = SpecialDetectorRegistry[i].frDetector.prefix;
127  if ( strncmp( prefix_i, name, 2 ) == 0 ) {
128  if ( exactMatch && strcmp( name + strlen( prefix_i ), "" ) != 0 ) {
129  XLAL_ERROR( XLAL_EINVAL, "Trailing garbage '%s' after detector prefix\n", name + strlen( prefix_i ) );
130  }
131  if ( prefix != NULL ) {
132  ( *prefix ) = XLALStringDuplicate( prefix_i );
133  }
134  if ( lalCachedIndex != NULL ) {
135  ( *lalCachedIndex ) = -1;
136  }
137  return XLAL_SUCCESS;
138  }
139  } // for i < numSpecialDetectors
140 
141  // ----- if not found, go through list of 'official' cached lalsuite detectors
142  const UINT4 numLALDetectors = sizeof( lalCachedDetectors ) / sizeof( lalCachedDetectors[0] );
143  for ( UINT4 i = 0; i < numLALDetectors; i ++ ) {
144  const CHAR *prefix_i = lalCachedDetectors[i].frDetector.prefix;
145  const CHAR *name_i = lalCachedDetectors[i].frDetector.name;
146  if ( strncmp( prefix_i, name, 2 ) == 0 ) {
147  if ( exactMatch && strcmp( name + strlen( prefix_i ), "" ) != 0 ) {
148  XLAL_ERROR( XLAL_EINVAL, "Trailing garbage '%s' after detector prefix\n", name + strlen( prefix_i ) );
149  }
150  if ( prefix != NULL ) {
151  ( *prefix ) = XLALStringDuplicate( prefix_i );
152  }
153  if ( lalCachedIndex != NULL ) {
154  ( *lalCachedIndex ) = i;
155  }
156  return XLAL_SUCCESS;
157  }
158  if ( strncmp( name, name_i, strlen( name_i ) ) == 0 ) {
159  if ( exactMatch && strcmp( name + strlen( name_i ), "" ) != 0 ) {
160  XLAL_ERROR( XLAL_EINVAL, "Trailing garbage '%s' after detector prefix\n", name + strlen( name_i ) );
161  }
162  if ( prefix != NULL ) {
163  ( *prefix ) = XLALStringDuplicate( prefix_i );
164  }
165  if ( lalCachedIndex != NULL ) {
166  ( *lalCachedIndex ) = i;
167  }
168  return XLAL_SUCCESS;
169  }
170 
171  } // for i < numLALDetectors
172 
173  if ( prefix != NULL ) {
174  ( *prefix ) = NULL;
175  }
176  XLAL_ERROR( XLAL_EINVAL, "Unknown detector name '%s'\n", name );
177 
178 } // XLALFindCWDetector()
179 
180 
181 /**
182  * Determine if 'name' is a valid detector name or prefix
183  *
184  * \return TRUE if 'name' is a valid detector name/prefix, FALSE otherwise
185  * (or if an error is encountered; this function does not raise XLAL errors)
186  */
187 BOOLEAN
189 {
190  int UNUSED errnum;
191  int retn;
192  XLAL_TRY_SILENT( retn = XLALFindCWDetector( NULL, NULL, name, 1 ), errnum );
193  return ( retn == XLAL_SUCCESS );
194 }
195 
196 
197 /**
198  * Find the valid CW detector prefix. 'name' input can be either a valid detector name or prefix
199  *
200  * \note The returned string is allocated here!
201  */
202 CHAR *
204 {
205  XLAL_CHECK_NULL( name != NULL, XLAL_EINVAL );
206 
207  CHAR *prefix = NULL;
208  XLAL_CHECK_NULL( XLALFindCWDetector( &prefix, NULL, name, 0 ) == XLAL_SUCCESS, XLAL_EINVAL, "Unknown detector name '%s'\n", name );
209 
210  return prefix;
211 } // XLALGetChannelPrefix()
212 
213 
214 /**
215  * Find the site geometry-information 'LALDetector' for given a detector name (or prefix).
216  */
217 const LALDetector *
219 {
220  XLAL_CHECK_NULL( name != NULL, XLAL_EINVAL );
221 
222  const INT4 numLALDetectors = sizeof( lalCachedDetectors ) / sizeof( lalCachedDetectors[0] );
223 
224  // first turn the free-form 'detector-name' into a well-defined channel-prefix, and find lalCachedDetector[] index
225  INT4 lalCachedIndex = -1;
226  CHAR *prefix;
227  XLAL_CHECK_NULL( XLALFindCWDetector( &prefix, &lalCachedIndex, name, 0 ) == XLAL_SUCCESS, XLAL_EFUNC );
228 
229  const LALDetector *site;
230 
231  if ( strchr( "XYZ", prefix[0] ) != NULL ) { // special CW detector
232  const int index_1 = ( ( int ) prefix[0] ) - ( ( int ) 'X' );
233  XLAL_CHECK_NULL( 0 <= index_1 && index_1 < 3, XLAL_EFAILED );
234 
235  const int index_2 = ( ( int ) prefix[1] ) - ( ( int ) '0' );
236  XLAL_CHECK_NULL( 0 <= index_1 && index_1 < 9, XLAL_EINVAL,
237  "Special CW detector prefix '%s' must be of the form [XYZ][0123456789]", prefix );
238 
239  const int index = 10 * index_1 + index_2;
240 
241  site = &SpecialDetectorRegistry[index];
242  } else { // official LALSuite detector
243  XLAL_CHECK_NULL( ( lalCachedIndex >= 0 ) && ( lalCachedIndex < numLALDetectors ), XLAL_EFAILED, "Internal inconsistency found (for 'name=%s, prefix=%s')\n", name, prefix );
244  site = &lalCachedDetectors[lalCachedIndex];
245  }
246 
247  XLALFree( prefix );
248 
249  return site;
250 
251 } // XLALGetSiteInfo()
252 
253 
254 /**
255  * Convenience function for filling out the string fields in a SFTFilenameSpec
256  */
258  SFTFilenameSpec *spec, /**< [out] SFT filename specification */
259  const CHAR *path, /**< [in] Path to the SFT file */
260  const CHAR *extn, /**< [in] Extension of the SFT file; defaults to 'sft' */
261  const CHAR *detector, /**< [in] 2-character detector prefix (e.g. 'H1', 'L1', 'V1') */
262  const CHAR *window_type, /**< [in] window function applied to SFT */
263  const CHAR *privMisc, /**< [in] For private SFTs: miscellaneous description field */
264  const CHAR *pubObsKind, /**< [in] For public SFTs: kind of data ('RUN', 'AUX', 'SIM', 'DEV') */
265  const CHAR *pubChannel /**< [in] For public SFTs: channel name of data used to make SFTs */
266 )
267 {
268 
269  // check input
270  XLAL_CHECK( spec != NULL, XLAL_EFAULT );
271 
272  // fill string fields
273  if ( path != NULL ) {
274  STRCPYCHK( "'spec->path'", spec->path, path );
275  }
276  if ( extn != NULL ) {
277  STRCPYCHK( "'spec->extn'", spec->extn, extn );
278  }
279  if ( detector != NULL ) {
280  STRCPYCHK( "'spec->detector'", spec->detector, detector );
281  }
282  if ( window_type != NULL ) {
283  STRCPYCHK( "'spec->window_type'", spec->window_type, window_type );
284  }
285  if ( privMisc != NULL ) {
286  STRCPYCHK( "'spec->privMisc'", spec->privMisc, privMisc );
287  }
288  if ( pubObsKind != NULL ) {
289  STRCPYCHK( "'spec->pubObsKind'", spec->pubObsKind, pubObsKind );
290  }
291  if ( pubChannel != NULL ) {
292  STRCPYCHK( "'spec->pubChannel'", spec->pubChannel, pubChannel );
293  }
294 
295  return XLAL_SUCCESS;
296 
297 }
298 
299 /**
300  * Build an SFT file name from the given specification
301  */
303  const SFTFilenameSpec *spec /**< [in] SFT filename specification */
304 )
305 {
306 
307  // check input
308  XLAL_CHECK_NULL( spec != NULL, XLAL_EFAULT );
309 
310  // check specification
312  "'path' is not a null-terminated string" );
314  "'extn' is not a null-terminated string" );
315  XLAL_CHECK_NULL( spec->numSFTs > 0, XLAL_EINVAL,
316  "'numSFTs' must be strictly positive" );
318  "'detector' is not a null-terminated string" );
320  "'%s' is not a valid 2-character detector prefix", spec->detector );
322  "'SFTtimebase' must be strictly positive" );
324  "'window_type' is not a null-terminated string" );
326  "'privMisc' is not a null-terminated string" );
327  XLAL_CHECK_NULL( spec->pubObsRun == 0 || strlen( spec->privMisc ) == 0, XLAL_EINVAL,
328  "Public SFTs (with pubObsRun=%u) cannot include a private description '%s'",
329  spec->pubObsRun, spec->privMisc );
331  "Private description '%s' contains disallowed characters", spec->privMisc );
333  "'pubObsKind' is not a null-terminated string" );
334  XLAL_CHECK_NULL( spec->pubObsRun == 0 ||
335  strcmp( spec->pubObsKind, "RUN" ) == 0 ||
336  strcmp( spec->pubObsKind, "AUX" ) == 0 ||
337  strcmp( spec->pubObsKind, "SIM" ) == 0 ||
338  strcmp( spec->pubObsKind, "DEV" ) == 0, XLAL_EINVAL,
339  "'pubObsKind=%s' must be one of 'RUN'|'AUX'|'SIM'|'DEV'", spec->pubObsKind );
340  XLAL_CHECK_NULL( spec->pubObsRun == 0 || spec->pubRevision > 0, XLAL_EINVAL,
341  "Public SFTs (with pubObsRun=%u) must include a positive revision 'pubRevision'",
342  spec->pubObsRun );
344  "'pubChannel' is not a null-terminated string" );
345  XLAL_CHECK_NULL( spec->pubObsRun == 0 || strlen( spec->pubChannel ) > 0, XLAL_EINVAL,
346  "Public SFTs (with pubObsRun=%u) must include a channel name 'pubChannel'",
347  spec->pubObsRun );
348  XLAL_CHECK_NULL( spec->pubObsRun == 0 || strlen( spec->window_type ) > 0, XLAL_EINVAL,
349  "Public SFTs (with pubObsRun=%u) must include a window function 'window_type'",
350  spec->pubObsRun );
351  XLAL_CHECK_NULL( spec->nbFirstBinFreq == 0 || spec->nbBinWidthFreq > 0 || spec->nbBinWidthRem > 0, XLAL_EINVAL,
352  "Narrow-band SFTs (with nbFirstBinFreq>0) must have nbBinWidthFreq>0 or nbBinWidthRem>0" );
354  "'gpsStart' must be strictly positive" );
355  XLAL_CHECK_NULL( spec->SFTspan > 0, XLAL_EINVAL,
356  "'SFTspan' must be strictly positive" );
357 
358  char windowspec_str[9];
359  if ( spec->pubObsRun > 0 ) {
360  XLAL_CHECK_NULL( build_sft_windowspec( NULL, &windowspec_str, spec->window_type, spec->window_param ) == XLAL_SUCCESS, XLAL_EINVAL,
361  "'%s' is not a valid SFT window function", spec->window_type );
362  }
363 
364  // SFT filename string
365  char *fname = NULL;
366 
367  // append SFT path, if any
368  if ( strlen( spec->path ) > 0 ) {
369  fname = XLALStringAppendFmt(
370  fname,
371  "%s/",
372  spec->path
373  );
374  XLAL_CHECK_NULL( fname != NULL, XLAL_EFUNC );
375  }
376 
377  // append SFT filename fields <S>, <D1>, <D2>, <D3> (see \cite SFT-spec)
378  fname = XLALStringAppendFmt(
379  fname,
380  "%c-%d_%s_%dSFT",
381  spec->detector[0],
382  spec->numSFTs,
383  spec->detector,
384  spec->SFTtimebase
385  );
386  XLAL_CHECK_NULL( fname != NULL, XLAL_EFUNC );
387 
388  // append optional SFT filename field <D4> (see \cite SFT-spec)
389  if ( spec->pubObsRun == 0 ) { // private SFT
390 
391  if ( strlen( spec->privMisc ) > 0 ) { // miscellaneous description
392 
393  // append private SFT miscellaneous description
394  fname = XLALStringAppendFmt(
395  fname,
396  "_%s",
397  spec->privMisc
398  );
399  XLAL_CHECK_NULL( fname != NULL, XLAL_EFUNC );
400 
401  }
402 
403  } else { // public SFT
404 
405  // strip prefix and disallowed characters from channel name
406  char pubChannel[XLAL_NUM_ELEM( spec->pubChannel )];
407  strcpy( pubChannel, spec->pubChannel );
408  char *pubChannel_no_prefix = strchr( pubChannel, ':' );
409  if ( !pubChannel_no_prefix ) {
410  pubChannel_no_prefix = pubChannel;
411  }
412  XLAL_CHECK_NULL( XLALStringKeepChars( pubChannel_no_prefix, isascii ) != NULL, XLAL_EFUNC );
413  XLAL_CHECK_NULL( XLALStringKeepChars( pubChannel_no_prefix, isalnum ) != NULL, XLAL_EFUNC );
414 
415  // append public SFT descriptor
416  fname = XLALStringAppendFmt(
417  fname,
418  "_O%d%s+R%d+C%s+W%s",
419  spec->pubObsRun,
420  spec->pubObsKind,
421  spec->pubRevision,
422  pubChannel_no_prefix,
423  windowspec_str
424  );
425  XLAL_CHECK_NULL( fname != NULL, XLAL_EFUNC );
426 
427  }
428 
429  // append optional SFT filename field <D5> (see \cite SFT-spec)
430  if ( spec->nbFirstBinFreq > 0 ) { // narrow-band SFTs
431 
432  // append narrow-band SFT descriptor
433  fname = XLALStringAppendFmt(
434  fname,
435  "_NBF%04dHz%dW%04dHz%d",
436  spec->nbFirstBinFreq,
437  spec->nbFirstBinRem,
438  spec->nbBinWidthFreq,
439  spec->nbBinWidthRem
440  );
441  XLAL_CHECK_NULL( fname != NULL, XLAL_EFUNC );
442 
443  }
444 
445  // append optional SFT filename fields <G>, <T> (see \cite SFT-spec), and extension
446  fname = XLALStringAppendFmt(
447  fname,
448  "-%09d-%d.%s",
449  spec->gpsStart,
450  spec->SFTspan,
451  strlen( spec->extn ) > 0 ? spec->extn : "sft"
452  );
453  XLAL_CHECK_NULL( fname != NULL, XLAL_EFUNC );
454 
455  return fname;
456 
457 } // XLALBuildSFTFilenameFromSpec(()
458 
459 
460 /**
461  * Parse a SFT file path and return its specification
462  */
464  SFTFilenameSpec *spec, /**< [out] SFT filename specification */
465  const char *SFTpath /**< [in] SFT file path */
466 )
467 {
468 
469  // check input
470  XLAL_CHECK( spec != NULL, XLAL_EFAULT );
471  XLAL_CHECK( SFTpath != NULL, XLAL_EFAULT );
472  XLALPrintInfo( "%s(): SFTpath='%s'\n",
473  __func__, SFTpath );
474 
475  // clear specification
476  memset( spec, 0, sizeof( *spec ) );
477 
478  // local copy of path
479  char localSFTpath[8192];
480  STRCPYCHK( "SFT filename and path", localSFTpath, SFTpath );
481 
482  // split SFT filename
483  char *SFTfname = strrchr( localSFTpath, '/' );
484  if ( !SFTfname ) {
485  SFTfname = localSFTpath;
486  } else {
487  *SFTfname++ = '\0';
488  STRCPYCHK( "SFT path", spec->path, localSFTpath );
489  }
490  XLALPrintInfo( "%s(): spec->path='%s' SFTfname='%s'\n",
491  __func__, spec->path, SFTfname );
492 
493  // split SFT filename <S>, <D>, <G>, <T> fields (see \cite SFT-spec)
494  char *S, *D, *G, *T;
495  {
496  char *p = SFTfname;
497  S = XLALStringToken( &p, "-", 1 );
498  XLAL_CHECK( S != NULL, XLAL_EINVAL,
499  "SFT file path '%s' contains no <S> field", SFTpath );
500  D = XLALStringToken( &p, "-", 1 );
501  XLAL_CHECK( D != NULL, XLAL_EINVAL,
502  "SFT file path '%s' contains no <D> field", SFTpath );
503  G = XLALStringToken( &p, "-", 1 );
504  XLAL_CHECK( G != NULL, XLAL_EINVAL,
505  "SFT file path '%s' contains no <G> field", SFTpath );
506  T = XLALStringToken( &p, ".", 1 );
507  XLAL_CHECK( T != NULL, XLAL_EINVAL,
508  "SFT file path '%s' contains no <T> field", SFTpath );
509  XLALPrintInfo( "%s(): S='%s' D='%s' G='%s' T='%s' extn='%s'\n",
510  __func__, S, D, G, T, p );
511  STRCPYCHK( "SFT extension", spec->extn, p );
512  }
513 
514  // split SFT filename <D> field into <D1>, <D2>, <D3>[, <D4>, <D5>] fields (see \cite SFT-spec)
515  char *D1, *D2, *D3, *D4, *D5;
516  {
517  char *p = D;
518  D1 = XLALStringToken( &p, "_", 1 );
519  XLAL_CHECK( D1 != NULL, XLAL_EINVAL,
520  "SFT file path '%s' contains no <D1> field", SFTpath );
521  D2 = XLALStringToken( &p, "_", 1 );
522  XLAL_CHECK( D2 != NULL, XLAL_EINVAL,
523  "SFT file path '%s' contains no <D2> field", SFTpath );
524  D3 = XLALStringToken( &p, "_", 1 );
525  XLAL_CHECK( D3 != NULL, XLAL_EINVAL,
526  "SFT file path '%s' contains no <D3> field", SFTpath );
527  if ( p == NULL ) { // no <D4>, <D5> fields
528  D4 = NULL;
529  D5 = NULL;
530  } else if ( strncmp( p, "NBF", 3 ) == 0 ) { // old style SFT name: <D5> appears before <D4>
531  D5 = XLALStringToken( &p, "_", 1 );
532  D4 = p;
533  // ensure <D4> is a valid description field
534  XLAL_CHECK( XLALStringKeepChars( D4, isascii ) != NULL, XLAL_EFUNC );
535  XLAL_CHECK( XLALStringKeepChars( D4, isalnum ) != NULL, XLAL_EFUNC );
536  } else {
537  int underscores = 0;
538  for ( char *q = p; *q != '\0'; ++q ) {
539  if ( *q == '_' ) {
540  ++underscores;
541  }
542  }
543  if ( underscores > 1 ) { // old style SFT name: <D4> includes underscores
544  D5 = NULL;
545  D4 = p;
546  // ensure <D4> is a valid description field
547  XLAL_CHECK( XLALStringKeepChars( D4, isascii ) != NULL, XLAL_EFUNC );
548  XLAL_CHECK( XLALStringKeepChars( D4, isalnum ) != NULL, XLAL_EFUNC );
549  } else { // compliant SFT name
550  D4 = XLALStringToken( &p, "_", 1 );
551  D5 = XLALStringToken( &p, "_", 1 );
552  }
553  }
554  XLALPrintInfo( "%s(): D1='%s' D2='%s' D3='%s' D4='%s' D5='%s' p='%s'\n",
555  __func__, D1, D2, D3, D4, D5, p );
556  }
557 
558  // parse required SFT filename fields <S>, <D1>, <D2>, <D3>, <G>, <T>
559  XLAL_CHECK( sscanf( D1, "%d", &spec->numSFTs ) == 1, XLAL_EFUNC,
560  "Could not parse 'numSFTs' from field D1='%s'", D1 );
561  XLAL_CHECK( spec->numSFTs > 0, XLAL_EINVAL,
562  "'numSFTs' must be strictly positive" );
563  STRCPYCHK( "SFT detector prefix", spec->detector, D2 );
565  "'%s' is not a valid 2-character detector prefix", spec->detector );
566  XLAL_CHECK( S[0] == spec->detector[0] && S[1] == '\0', XLAL_EINVAL,
567  "Inconsistent site/detector fields S='%s' and D2='%s'", S, D2 );
568  XLAL_CHECK( sscanf( D3, "%dSFT", &spec->SFTtimebase ) == 1, XLAL_EFUNC,
569  "Could not parse 'SFTtimebase' from field D3='%s'", D3 );
570  XLAL_CHECK( spec->SFTtimebase > 0, XLAL_EINVAL,
571  "'SFTtimebase' must be strictly positive" );
572  XLAL_CHECK( sscanf( G, "%d", &spec->gpsStart ) == 1, XLAL_EFUNC,
573  "Could not parse 'gpsStart' from field G='%s'", G );
574  XLAL_CHECK( spec->gpsStart > 0, XLAL_EINVAL,
575  "'gpsStart' must be strictly positive" );
576  XLAL_CHECK( sscanf( T, "%d", &spec->SFTspan ) == 1, XLAL_EFUNC,
577  "Could not parse 'SFTspan' from field T='%s'", T );
578  XLAL_CHECK( spec->SFTspan > 0, XLAL_EINVAL,
579  "'SFTspan' must be strictly positive" );
580 
581  // parse optional SFT filename field <D4>
582  if ( D4 != NULL ) {
583  if ( strchr( D4, '+' ) ) { // public SFT
584  char *D41, *D42, *D43, *D44;
585  char *p = D4;
586  D41 = XLALStringToken( &p, "+", 1 );
587  XLAL_CHECK( D41 != NULL, XLAL_EINVAL,
588  "SFT file path '%s' contains no <D41> field", SFTpath );
589  D42 = XLALStringToken( &p, "+", 1 );
590  XLAL_CHECK( D42 != NULL, XLAL_EINVAL,
591  "SFT file path '%s' contains no <D42> field", SFTpath );
592  D43 = XLALStringToken( &p, "+", 1 );
593  XLAL_CHECK( D43 != NULL, XLAL_EINVAL,
594  "SFT file path '%s' contains no <D43> field", SFTpath );
595  D44 = XLALStringToken( &p, "+", 1 );
596  XLAL_CHECK( D44 != NULL, XLAL_EINVAL,
597  "SFT file path '%s' contains no <D44> field", SFTpath );
598  XLALPrintInfo( "%s(): D41='%s' D42='%s' D43='%s' D44='%s' p='%s'\n",
599  __func__, D41, D42, D43, D44, p );
600  char buf[8192];
601  XLAL_CHECK( sscanf( D41, "O%d%255s", &spec->pubObsRun, buf ) == 2, XLAL_EINVAL,
602  "Could not parse public SFT fields 'pubObsRun' and 'pubObsKind' from field D41='%s'", D41 );
603  STRCPYCHK( "Public SFT field 'pubObsKind'", spec->pubObsKind, buf );
604  XLAL_CHECK( sscanf( D42, "R%d", &spec->pubRevision ) == 1, XLAL_EFUNC,
605  "Could not parse public SFT field 'pubRevision' from field D42='%s'", D42 );
606  XLAL_CHECK( sscanf( D43, "C%255s", buf ) == 1, XLAL_EINVAL,
607  "Could not parse public SFT field 'pubChannel' from field D43='%s'", D43 );
608  STRCPYCHK( "Public SFT field 'pubChannel'", spec->pubChannel, buf );
609  XLAL_CHECK( sscanf( D44, "W%255s", buf ) == 1, XLAL_EINVAL,
610  "Could not parse public SFT fields 'window_type' and 'window_param' from field D44='%s'", D44 );
612  "'%s' does not specify a valid SFT window function", buf );
613  } else { // private SFT
615  "Private description '%s' contains disallowed characters", D4 );
616  STRCPYCHK( "Private SFT miscellaneous description", spec->privMisc, D4 );
617  }
618  }
619 
620  // parse optional SFT filename field <D5>
621  if ( D5 != NULL ) { // narrow-band SFTs
622  XLAL_CHECK( sscanf( D5, "NBF%dHz%dW%dHz%d",
623  &spec->nbFirstBinFreq, &spec->nbFirstBinRem,
624  &spec->nbBinWidthFreq, &spec->nbBinWidthRem
625  ) == 4, XLAL_EINVAL,
626  "Could not parse narrow-band SFT field D5='%s'", D5 );
627  }
628 
629  return XLAL_SUCCESS;
630 
631 } // XLALParseSFTFilenameIntoSpec()
632 
633 
634 /**
635  * Check whether given string qualifies as a valid 'description' field of a
636  * FRAME filename (per \cite frame-naming-spec) or SFT filename (per \cite SFT-spec)
637  */
638 int
640 {
641  XLAL_CHECK( desc != NULL, XLAL_EINVAL );
642 
643  size_t len = strlen( desc );
644 
645  if ( len == 1 && isupper( desc[0] ) ) {
646  XLAL_ERROR( XLAL_EINVAL, "Single uppercase description reserved for class-1 raw frames!\n" );
647  }
648 
649  for ( UINT4 i = 0; i < len; i ++ ) {
650  int c = desc[i];
651  // SFT filenames only allow alphanumeric characters, which is more restrictive than FRAME filenames which also allow [_+#]
652  XLAL_CHECK( isascii( c ) && isalnum( c ), XLAL_EINVAL, "Invalid chacter '%c' found, only ASCII alphanumeric are allowed\n", c );
653  } // for i < len
654 
655  return XLAL_SUCCESS;
656 
657 } // XLALCheckValidDescriptionField()
658 
659 
660 /**
661  * Check whether two SFT windows, each defined by a type name and parameter value, match.
662  *
663  * This builds standardized windowspec numbers out of the inputs and compares those,
664  * ensuring consistent rounding before the comparison.
665  */
666 int
668  const CHAR *type1, /**< [in] type name of the first window */
669  const REAL8 param1, /**< [in] parameter value of the first window */
670  const CHAR *type2, /**< [in] type name of the second window */
671  const REAL8 param2 /**< [in] parameter value of the second window */
672 )
673 {
674 
675  UINT2 spec1 = 0;
676  UINT2 spec2 = 0;
677 
678  XLAL_CHECK( build_sft_windowspec( &spec1, NULL, type1, param1 ) == XLAL_SUCCESS, XLAL_EINVAL, "Failed to build windowspec from type '%s' and param '%f'", type1, param1 );
679  XLAL_CHECK( build_sft_windowspec( &spec2, NULL, type2, param2 ) == XLAL_SUCCESS, XLAL_EINVAL, "Failed to build windowspec from type '%s' and param '%f'", type2, param2 );
680 
681  XLAL_CHECK( spec1 == spec2, XLAL_EINVAL );
682 
683  return XLAL_SUCCESS;
684 
685 } // XLALCompareSFTWindows()
686 
687 
688 /**
689  * Build an SFT 2-byte 'windowspec' or filename field 'windowspec_str' for the window given by 'window_type' and 'window_param'
690  */
691 int build_sft_windowspec( UINT2 *windowspec, CHAR( *windowspec_str )[9], const char *window_type, REAL8 window_param )
692 {
693 
694  // check input
695  XLAL_CHECK( window_type != NULL, XLAL_EFAULT );
696 
697  // default to unknown window
698  if ( windowspec ) {
699  *windowspec = windowspec_table[0].B;
700  }
701  if ( windowspec_str ) {
702  XLAL_CHECK( snprintf( *windowspec_str, sizeof( *windowspec_str ), "%s", windowspec_table[0].short_name ) < ( int ) sizeof( *windowspec_str ), XLAL_ESYS );
703  }
704 
705  // lookup windows
706  for ( size_t w = 0; w < XLAL_NUM_ELEM( windowspec_table ); ++w ) {
708 
709  // build windowspec and windowspec_str
710  if ( windowspec_table[w].A == 0 ) { /* zero-parameter windows */
711 
712  XLAL_CHECK( window_param <= 0, XLAL_EINVAL, "Invalid window_param=%0.10g for SFT window type '%s'", window_param, window_type );
713 
714  if ( windowspec ) {
715  *windowspec = windowspec_table[w].B;
716  }
717 
718  if ( windowspec_str ) {
719  XLAL_CHECK( snprintf( *windowspec_str, sizeof( *windowspec_str ), "%s", windowspec_table[w].short_name ) < ( int ) sizeof( *windowspec_str ), XLAL_ESYS );
720  }
721 
722  } else { /* one-parameter windows */
723 
724  REAL8 Breal = window_param * 5000;
725  long B = lrint( Breal );
726  XLAL_CHECK( B == ( ( long ) Breal ), XLAL_ETOL, "SFT window_param=%0.10g cannot be exactly represented by an integer [0,5000]", window_param );
727  XLAL_CHECK( 0 <= B && B <= 5000, XLAL_ERANGE, "SFT window_param=%0.10g is out of range [0.0,1.0] (B=%ld)", window_param, B );
728 
729  if ( windowspec ) {
730  *windowspec = windowspec_table[w].A * 5001 + B;
731  }
732 
733  if ( windowspec_str ) {
734  XLAL_CHECK( snprintf( *windowspec_str, sizeof( *windowspec_str ), "%s%ld", windowspec_table[w].short_name, B ) < ( int ) sizeof( *windowspec_str ), XLAL_ESYS );
735  }
736 
737  }
738 
739  break;
740 
741  }
742  }
743 
744  return XLAL_SUCCESS;
745 
746 }
747 
748 
749 /**
750  * Parse an SFT 2-byte 'windowspec' into a window name 'window_type' and possible parameter 'window_param'
751  */
752 int parse_sft_windowspec( const UINT2 windowspec, const char **window_type, REAL8 *window_param )
753 {
754 
755  // parse windowspec
756  const UINT2 A = windowspec / 5001;
757  const UINT2 B = windowspec - 5001 * A;
758 
759  // lookup windows
760  for ( size_t w = 0; w < XLAL_NUM_ELEM( windowspec_table ); ++w ) {
761  if ( A == windowspec_table[w].A ) {
762 
763  // build window_type and window_param
764  if ( A == 0 && B == windowspec_table[w].B ) { /* zero-parameter windows */
765 
766  if ( window_type ) {
767  *window_type = windowspec_table[w].window_type;
768  }
769 
770  if ( window_param ) {
771  *window_param = 0;
772  }
773 
774  return XLAL_SUCCESS;
775 
776  } else if ( A > 0 ) { /* one-parameter windows */
777 
778  if ( window_type ) {
779  *window_type = windowspec_table[w].window_type;
780  }
781 
782  if ( window_param ) {
783  *window_param = ( ( REAL8 ) B ) / 5000;
784  }
785 
786  return XLAL_SUCCESS;
787 
788  }
789 
790  }
791  }
792 
793  XLAL_ERROR( XLAL_EINVAL, "Illegal SFT windowspec=%d : windowspecA=%d, windowspecB=%d",
794  windowspec, A, B );
795 
796 }
797 
798 
799 /**
800  * Parse an SFT filename field 'windowspec_str' into a window name 'window_type' and possible parameter 'window_param'
801  */
802 int parse_sft_windowspec_str( const CHAR *windowspec_str, CHAR( *window_type )[32], REAL8 *window_param )
803 {
804 
805  // check input
806  XLAL_CHECK( windowspec_str != NULL, XLAL_EFAULT );
807 
808  // parse windowspec_str
809  char short_name[5];
810  long B = 0;
811  int parsed = sscanf( windowspec_str, "%4s%li", short_name, &B );
812  XLAL_CHECK( 0 < parsed, XLAL_EINVAL, "Could not parse SFT filename field windowspec_str='%s'", windowspec_str );
813  XLAL_CHECK( 0 <= B && B <= 5000, XLAL_ERANGE, "SFT window_param=%0.10g is out of range [0.0,1.0] (B=%ld)", ( ( REAL8 ) B ) / 5000, B );
814 
815  // lookup windows
816  for ( size_t w = 0; w < XLAL_NUM_ELEM( windowspec_table ); ++w ) {
817  if ( strcmp( short_name, windowspec_table[w].short_name ) == 0 ) {
818 
819  // build window_type
820  if ( window_type ) {
821  XLAL_CHECK( snprintf( *window_type, sizeof( *window_type ), "%s", windowspec_table[w].window_type ) < ( int ) sizeof( *window_type ), XLAL_ESYS );
822  }
823 
824  // build window_param
825  if ( window_param ) {
826  if ( windowspec_table[w].A == 0 ) { /* zero-parameter windows */
827  *window_param = 0;
828  } else { /* one-parameter windows */
829  *window_param = ( ( REAL8 ) B ) / 5000;
830  }
831  }
832 
833  return XLAL_SUCCESS;
834 
835  }
836  }
837 
838  XLAL_ERROR( XLAL_EINVAL, "Illegal SFT windowspec_str='%s'", windowspec_str );
839 
840 }
841 
842 /// @}
#define __func__
log an I/O error, i.e.
INT4 D2(REAL8 *f, REAL8 dx, INT4 n, REAL8 *d2f)
#define c
#define D(j)
Internal SFT types and functions.
const char * short_name
Definition: SFTnaming.c:45
const char * window_type
Definition: SFTnaming.c:44
#define LAST_ELEMENT(buf)
Definition: SFTnaming.c:32
UINT2 A
Definition: SFTnaming.c:46
#define STRCPYCHK(name, dest, src)
Definition: SFTnaming.c:34
static LALDetector SpecialDetectorRegistry[30]
Definition: SFTnaming.c:60
static const struct @6 windowspec_table[]
SFT window specification; see .
UINT2 B
Definition: SFTnaming.c:47
const char * name
Definition: SearchTiming.c:93
const double w
const LALDetector lalCachedDetectors[LAL_NUM_DETECTORS]
unsigned char BOOLEAN
#define XLAL_NUM_ELEM(x)
double REAL8
uint16_t UINT2
char CHAR
uint32_t UINT4
int32_t INT4
void XLALFree(void *p)
int XLALStringCaseCompare(const char *s1, const char *s2)
char char * XLALStringDuplicate(const char *s)
char * XLALStringKeepChars(char *s, int(*f)(int))
char * XLALStringAppendFmt(char *s, const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(2
char * XLALStringToken(char **s, const char *delim, int empty)
static const INT4 q
int parse_sft_windowspec(const UINT2 windowspec, const char **window_type, REAL8 *window_param)
Parse an SFT 2-byte 'windowspec' into a window name 'window_type' and possible parameter 'window_para...
Definition: SFTnaming.c:752
const LALDetector * XLALGetSiteInfo(const CHAR *name)
Find the site geometry-information 'LALDetector' for given a detector name (or prefix).
Definition: SFTnaming.c:218
int XLALRegisterSpecialCWDetector(const LALDetector *specialDetector)
Register a special detector for use with CW codes.
Definition: SFTnaming.c:73
CHAR * XLALGetChannelPrefix(const CHAR *name)
Find the valid CW detector prefix.
Definition: SFTnaming.c:203
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 XLALCompareSFTWindows(const CHAR *type1, const REAL8 param1, const CHAR *type2, const REAL8 param2)
Check whether two SFT windows, each defined by a type name and parameter value, match.
Definition: SFTnaming.c:667
char * XLALBuildSFTFilenameFromSpec(const SFTFilenameSpec *spec)
Build an SFT file name from the given specification.
Definition: SFTnaming.c:302
int XLALFindCWDetector(CHAR **prefix, INT4 *lalCachedIndex, const CHAR *name, const BOOLEAN exactMatch)
Parses valid CW detector names and prefixes.
Definition: SFTnaming.c:118
int XLALCheckValidDescriptionField(const char *desc)
Check whether given string qualifies as a valid 'description' field of a FRAME filename (per ) or SFT...
Definition: SFTnaming.c:639
int XLALParseSFTFilenameIntoSpec(SFTFilenameSpec *spec, const char *SFTpath)
Parse a SFT file path and return its specification.
Definition: SFTnaming.c:463
int parse_sft_windowspec_str(const CHAR *windowspec_str, CHAR(*window_type)[32], REAL8 *window_param)
Parse an SFT filename field 'windowspec_str' into a window name 'window_type' and possible parameter ...
Definition: SFTnaming.c:802
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
BOOLEAN XLALIsValidCWDetector(const CHAR *name)
Determine if 'name' is a valid detector name or prefix.
Definition: SFTnaming.c:188
#define XLAL_TRY_SILENT(statement, errnum)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
XLAL_SUCCESS
XLAL_EFAULT
XLAL_ERANGE
XLAL_EFUNC
XLAL_ETOL
XLAL_ESYS
XLAL_EINVAL
XLAL_EFAILED
T
path
string prefix
desc
LALFrDetector frDetector
CHAR prefix[3]
CHAR name[LALNameLength]
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 extn[32]
Extension of the SFT file; defaults to 'sft'.
Definition: SFTfileIO.h:268
CHAR window_type[32]
window function applied to SFT
Definition: SFTfileIO.h:272
CHAR path[4096]
Path to the SFT file.
Definition: SFTfileIO.h:267
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
enum @4 site