LALPulsar  6.1.0.1-b72065a
SFTtimestamps.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 David Keitel
3  * Copyright (C) 2014, 2015 Evan Goetz
4  * Copyright (C) 2014 Matthew Pitkin
5  * Copyright (C) 2010, 2012--2017, 2020, 2022 Karl Wette
6  * Copyright (C) 2010 Chris Messenger
7  * Copyright (C) 2009, 2011, 2015 Adam Mercer
8  * Copyright (C) 2004--2006, 2009-- 2011, 2013, 2015--2018 Reinhard Prix
9  * Copyright (C) 2004--2006 Bernd Machenschalk
10  * Copyright (C) 2004, 2005 Alicia Sintes
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with with program; see the file COPYING. If not, write to the
24  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25  * MA 02110-1301 USA
26  */
27 
28 /*---------- includes ----------*/
29 
30 #include <lal/ConfigFile.h>
31 
32 #include "SFTinternal.h"
33 
34 /*---------- global variables ----------*/
35 
36 // XLALReadSegmentsFromFile(): applications which still must support
37 // the deprecated 4-column format should set this variable to non-zero
39 
40 /*========== function definitions ==========*/
41 
42 /// \addtogroup SFTfileIO_h
43 /// @{
44 
45 /** Allocate a LIGOTimeGPSVector */
48 {
49  int len;
50  LIGOTimeGPSVector *out = XLALCalloc( 1, len = sizeof( LIGOTimeGPSVector ) );
51  if ( out == NULL ) {
52  XLAL_ERROR_NULL( XLAL_ENOMEM, "Failed to allocate XLALCalloc(1,%d)\n", len );
53  }
54 
55  out->length = length;
56  out->data = XLALCalloc( 1, len = length * sizeof( LIGOTimeGPS ) );
57  if ( out->data == NULL ) {
58  XLALFree( out );
59  XLAL_ERROR_NULL( XLAL_ENOMEM, "Failed to allocate XLALCalloc(1,%d)\n", len );
60  }
61 
62  return out;
63 
64 } /* XLALCreateTimestampVector() */
65 
66 
67 /** De-allocate a LIGOTimeGPSVector */
68 void
70 {
71  if ( !vect ) {
72  return;
73  }
74 
75  XLALFree( vect->data );
76  XLALFree( vect );
77 
78  return;
79 
80 } /* XLALDestroyTimestampVector() */
81 
82 
83 /** Resize a LIGOTimeGPSVector */
86 {
87  if ( ! vector ) {
88  return XLALCreateTimestampVector( length );
89  }
90  if ( ! length ) {
92  return NULL;
93  }
94 
95  vector->data = XLALRealloc( vector->data, length * sizeof( LIGOTimeGPS ) );
96 
97  if ( ! vector->data ) {
98  vector->length = 0;
100  }
101  vector->length = length;
102  return vector;
103 }
104 
105 
106 /**
107  * Simple creator function for MultiLIGOTimeGPSVector with numDetectors entries
108  */
111 {
113 
114  if ( ( ret = XLALMalloc( sizeof( *ret ) ) ) == NULL ) {
115  XLALPrintError( "%s: XLALMalloc(%zu) failed.\n", __func__, sizeof( *ret ) );
117  }
118 
119  ret->length = numDetectors;
120  if ( ( ret->data = XLALCalloc( numDetectors, sizeof( *ret->data ) ) ) == NULL ) {
121  XLALPrintError( "%s: XLALCalloc(%d, %zu) failed.\n", __func__, numDetectors, sizeof( *ret->data ) );
122  XLALFree( ret );
124  }
125 
126  return ret;
127 
128 } /* XLALCreateMultiLIGOTimeGPSVector() */
129 
130 
131 /**
132  * Destroy a MultiLIGOTimeGPSVector timestamps vector
133  */
134 void
136 {
137  UINT4 numIFOs, X;
138 
139  if ( !multiTS ) {
140  return;
141  }
142 
143  numIFOs = multiTS->length;
144  for ( X = 0; X < numIFOs; X ++ ) {
146  }
147 
148  XLALFree( multiTS->data );
149  XLALFree( multiTS );
150 
151  return;
152 
153 } /* XLALDestroyMultiTimestamps() */
154 
155 
156 // Find index values of first and last timestamp within given timeslice range XLALCWGPSinRange(minStartGPS, maxStartGPS)
157 int
159  UINT4 *iEnd,
161  const LIGOTimeGPS *minStartGPS,
162  const LIGOTimeGPS *maxStartGPS
163  )
164 {
165  XLAL_CHECK( ( iStart != NULL ) && ( iEnd != NULL ) && ( timestamps != NULL ) && ( minStartGPS != NULL ) && ( maxStartGPS != NULL ), XLAL_EINVAL );
166  XLAL_CHECK( XLALGPSCmp( minStartGPS, maxStartGPS ) < 1, XLAL_EINVAL, "minStartGPS (%"LAL_GPS_FORMAT") is greater than maxStartGPS (%"LAL_GPS_FORMAT")\n",
167  LAL_GPS_PRINT( *minStartGPS ), LAL_GPS_PRINT( *maxStartGPS ) );
168 
170  ( *iStart ) = 0;
171  ( *iEnd ) = N - 1;
172 
173  // check if there's any timestamps falling into the requested timeslice at all
174  if ( ( ( XLALCWGPSinRange( timestamps->data[0], minStartGPS, maxStartGPS ) == 1 ) || ( XLALCWGPSinRange( timestamps->data[N - 1], minStartGPS, maxStartGPS ) == -1 ) ) ) {
175  // if not: set an emtpy index interval in this case
176  ( *iStart ) = 1;
177  ( *iEnd ) = 0;
178  XLALPrintInfo( "Returning empty timeslice: Timestamps span [%"LAL_GPS_FORMAT", %"LAL_GPS_FORMAT "]"
179  " has no overlap with requested timeslice range [%"LAL_GPS_FORMAT", %"LAL_GPS_FORMAT").\n",
181  LAL_GPS_PRINT( *minStartGPS ), LAL_GPS_PRINT( *maxStartGPS )
182  );
183  return XLAL_SUCCESS;
184  }
185 
186  while ( ( *iStart ) <= ( *iEnd ) && XLALCWGPSinRange( timestamps->data[( *iStart ) ], minStartGPS, maxStartGPS ) < 0 ) {
187  ++ ( *iStart );
188  }
189  while ( ( *iStart ) <= ( *iEnd ) && XLALCWGPSinRange( timestamps->data[( *iEnd ) ], minStartGPS, maxStartGPS ) > 0 ) {
190  -- ( *iEnd );
191  }
192  // note: *iStart >=0, *iEnd >= 0 is now guaranteed due to previous range overlap-check
193 
194  // check if there is any timestamps found witin the interval, ie if iStart <= iEnd
195  if ( ( *iStart ) > ( *iEnd ) ) {
196  XLALPrintInfo( "Returning empty timeslice: no sfttimes fall within given GPS range [%"LAL_GPS_FORMAT", %"LAL_GPS_FORMAT"). "
197  "Closest timestamps are: %"LAL_GPS_FORMAT" and %"LAL_GPS_FORMAT"\n",
198  LAL_GPS_PRINT( *minStartGPS ), LAL_GPS_PRINT( *maxStartGPS ),
199  LAL_GPS_PRINT( timestamps->data[( *iEnd ) ] ), LAL_GPS_PRINT( timestamps->data[( *iStart ) ] )
200  );
201  ( *iStart ) = 1;
202  ( *iEnd ) = 0;
203  }
204 
205  return XLAL_SUCCESS;
206 
207 } // XLALFindTimesliceBounds()
208 
209 
210 /**
211  * Given a start-time, Tspan, Tsft and Toverlap, returns a list of timestamps
212  * covering this time-stretch (allowing for overlapping SFTs).
213  *
214  * NOTE: boundary-handling: the returned list of timestamps fall within the
215  * interval [tStart, tStart+Tspan),
216  * consistent with the convention defined in XLALCWGPSinRange().
217  * Assuming each SFT covers a stretch of data of length 'Tsft',
218  * the returned timestamps correspond to a set of SFTs that is guaranteed
219  * to *cover* all data between 'tStart' and 'tStart+Tspan'.
220  * This implies that, while the last timestamp returned will always be
221  * 'ret->data[numSFTs-1] < tStart+Tspan',
222  * the actual data coverage can extend up to 'Tsft' beyond 'tStart+duration'.
223  */
225 XLALMakeTimestamps( LIGOTimeGPS tStart, /**< GPS start-time */
226  REAL8 Tspan, /**< total duration to cover, in seconds */
227  REAL8 Tsft, /**< length of the SFT corresponding to each timestamp, in seconds */
228  REAL8 Toverlap /**< time to overlap successive SFTs by, in seconds */
229  )
230 {
234  XLAL_CHECK_NULL( Toverlap < Tsft, XLAL_EDOM ); // we must actually advance
235 
236  REAL8 Tstep = Tsft - Toverlap; // guaranteed > 0
237  UINT4 numSFTsMax = ceil( Tspan * fudge_down / Tstep ); /* >= 1 !*/
238  // now we might be covering the end-time several times, if using overlapping SFTs, so
239  // let's trim this back down so that end-time is covered exactly once
240  UINT4 numSFTs = numSFTsMax;
241  while ( ( numSFTs >= 2 ) && ( ( numSFTs - 2 ) * Tstep + Tsft >= Tspan ) ) {
242  numSFTs --;
243  }
244 
245  LIGOTimeGPSVector *ret;
247 
248  ret->deltaT = Tsft;
249 
250  LIGOTimeGPS tt = tStart; /* initialize to start-time */
251  for ( UINT4 i = 0; i < numSFTs; i++ ) {
252  ret->data[i] = tt;
253  /* get next time-stamp */
254  /* NOTE: we add the interval tStep successively (rounded correctly to ns each time!)
255  * instead of using iSFT*Tsft, in order to avoid possible ns-rounding problems
256  * with REAL8 intervals, which becomes critial from about 100days on...
257  */
258  XLAL_CHECK_NULL( XLALGPSAdd( &tt, Tstep ) != NULL, XLAL_EFUNC );
259 
260  } /* for i < numSFTs */
261 
262  return ret;
263 
264 } /* XLALMakeTimestamps() */
265 
266 
267 /**
268  * Same as XLALMakeTimestamps() just for several detectors,
269  * additionally specify the number of detectors.
270  */
272 XLALMakeMultiTimestamps( LIGOTimeGPS tStart, /**< GPS start-time */
273  REAL8 Tspan, /**< total duration to cover, in seconds */
274  REAL8 Tsft, /**< Tsft: SFT length of each timestamp, in seconds */
275  REAL8 Toverlap, /**< time to overlap successive SFTs by, in seconds */
276  UINT4 numDet /**< number of timestamps-vectors to generate */
277  )
278 {
280 
282  XLAL_CHECK_NULL( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) != NULL, XLAL_ENOMEM );
283  XLAL_CHECK_NULL( ( ret->data = XLALCalloc( numDet, sizeof( ret->data[0] ) ) ) != NULL, XLAL_ENOMEM );
284  ret->length = numDet;
285 
286  for ( UINT4 X = 0; X < numDet; X ++ ) {
287  XLAL_CHECK_NULL( ( ret->data[X] = XLALMakeTimestamps( tStart, Tspan, Tsft, Toverlap ) ) != NULL, XLAL_EFUNC );
288  } // for X < numDet
289 
290  return ret;
291 
292 } /* XLALMakeMultiTimestamps() */
293 
294 
295 /// backwards compatible wrapper to XLALReadTimestampsFileConstrained() without GPS-time constraints
298 {
299  return XLALReadTimestampsFileConstrained( fname, NULL, NULL );
300 }
301 
302 
303 /// backwards compatible wrapper to XLALReadMultiTimestampsFilesConstrained() without GPS-time constraints
306 {
307  return XLALReadMultiTimestampsFilesConstrained( fnames, NULL, NULL );
308 }
309 
310 
311 /**
312  * Load timestamps file 'fname' into LIGOTimeGPSVector struct, allocated here.
313  *
314  * The timestamps file must contain one GPS time per line, allowing for '%#' as comments, which are ignored.
315  * The constraints 'minGPS', 'maxGPS' are applied by returning only timestamps that fall within
316  * the range defined by XLALCWGPSinRange(gps, minGPS, maxGPS) == 0.
317  */
319 XLALReadTimestampsFileConstrained( const CHAR *fname, const LIGOTimeGPS *minGPS, const LIGOTimeGPS *maxGPS )
320 {
321  /** check input consistency */
322  XLAL_CHECK_NULL( fname != NULL, XLAL_EINVAL );
323 
324  /* read and parse timestamps-list file contents*/
325  LALParsedDataFile *flines = NULL;
326  XLAL_CHECK_NULL( XLALParseDataFile( &flines, fname ) == XLAL_SUCCESS, XLAL_EFUNC );
327 
328  UINT4 numTS = flines->lines->nTokens;
329  UINT4 numTSinRange = 0;
330 
331  /* allocate and initialized segment list */
334 
335  char buf[256];
336  for ( UINT4 iTS = 0; iTS < numTS; iTS ++ ) {
337  LIGOTimeGPS gps;
338  INT4 secs, ns;
339  char junk[11] = "";
340 
341  // first check if obsolete <sec ns> format is found on this line
342  if ( sscanf( flines->lines->tokens[iTS], "%" LAL_INT4_FORMAT " %" LAL_INT4_FORMAT "%10s\n", &secs, &ns, junk ) > 1 ) {
343  gps.gpsSeconds = secs;
344  gps.gpsNanoSeconds = ns;
345 
346  XLALPrintWarning( "Line %d: found obsolete 'sec ns' timestamps format '%s', use 'xx.yy[GPS|MJD]' instead: %s\n", iTS, flines->lines->tokens[iTS], XLALGPSToStr( buf, &gps ) );
347  if ( junk[0] != 0 ) {
349  XLALDestroyParsedDataFile( flines );
350  XLAL_ERROR_NULL( XLAL_EINVAL, "Unconverted trailing junk '%s' found: invalid\n", junk );
351  }
352  } // end: if old-style format 'sec ns' is found
353  else {
354  if ( XLALParseStringValueAsEPOCH( &gps, flines->lines->tokens[iTS] ) != XLAL_SUCCESS ) {
356  XLALDestroyParsedDataFile( flines );
357  XLAL_ERROR_NULL( XLAL_EINVAL, "Failed to parse line %d into epoch: '%s'\n", iTS, flines->lines->tokens[iTS] );
358  }
359  }
360 
361  if ( XLALCWGPSinRange( gps, minGPS, maxGPS ) == 0 ) {
362  timestamps->data[numTSinRange ++] = gps;
363  }
364 
365  } /* for iTS < numTS */
366 
367  /* free parsed segment file contents */
368  XLALDestroyParsedDataFile( flines );
369 
370  // adjust size of timestamps vector to those found within range
371  timestamps->length = numTSinRange;
372  timestamps->data = XLALRealloc( timestamps->data, numTSinRange * sizeof( timestamps->data[0] ) );
373 
374  return timestamps;
375 
376 } /* XLALReadTimestampsFileConstrained() */
377 
378 
379 /**
380  * Load several timestamps files, return a MultiLIGOTimeGPSVector struct, allocated here.
381  *
382  * The timestamps files must contain one GPS time per line, allowing for '%#' as comments, which are ignored.
383  * The constraints 'minGPS', 'maxGPS' are applied by returning only timestamps that fall within
384  * the range defined by XLALCWGPSinRange(gps, minGPS, maxGPS) == 0.
385  *
386  */
389 {
390  XLAL_CHECK_NULL( fnames != NULL, XLAL_EINVAL );
391  XLAL_CHECK_NULL( fnames->data != NULL, XLAL_EINVAL );
392  XLAL_CHECK_NULL( fnames->length > 0, XLAL_EDOM );
393 
394  UINT4 numDet = fnames->length;
395 
396  // ----- prepare output container
398  XLAL_CHECK_NULL( ( multiTS = XLALCalloc( 1, sizeof( *multiTS ) ) ) != NULL, XLAL_ENOMEM );
399  XLAL_CHECK_NULL( ( multiTS->data = XLALCalloc( numDet, sizeof( multiTS->data[0] ) ) ) != NULL, XLAL_ENOMEM );
400  multiTS->length = numDet;
401 
402  for ( UINT4 X = 0; X < numDet; X ++ ) {
403  XLAL_CHECK_NULL( fnames->data[X] != NULL, XLAL_EINVAL );
404  XLAL_CHECK_NULL( ( multiTS->data[X] = XLALReadTimestampsFileConstrained( fnames->data[X], minGPS, maxGPS ) ) != NULL, XLAL_EFUNC );
405  } // for X < numDet
406 
407  return multiTS;
408 
409 } // XLALReadMultiTimestampsFilesConstrained()
410 
411 
412 /**
413  * Extract timstamps-vector from the given SFTVector
414  */
416 XLALExtractTimestampsFromSFTs( const SFTVector *sfts ) /**< [in] input SFT-vector */
417 {
418  /* check input consistency */
419  if ( !sfts ) {
420  XLALPrintError( "%s: invalid NULL input 'sfts'\n", __func__ );
422  }
423 
424  UINT4 numSFTs = sfts->length;
425  /* create output vector */
426  LIGOTimeGPSVector *ret = NULL;
427  if ( ( ret = XLALCreateTimestampVector( numSFTs ) ) == NULL ) {
428  XLALPrintError( "%s: XLALCreateTimestampVector(%d) failed.\n", __func__, numSFTs );
430  }
431  ret->deltaT = TSFTfromDFreq( sfts->data[0].deltaF );
432 
433  UINT4 i;
434  for ( i = 0; i < numSFTs; i ++ ) {
435  ret->data[i] = sfts->data[i].epoch;
436  }
437 
438  /* done: return Ts-vector */
439  return ret;
440 
441 } /* XLALExtractTimestampsFromSFTs() */
442 
443 
444 /**
445  * Given a multi-SFT vector, return a MultiLIGOTimeGPSVector holding the
446  * SFT timestamps
447  */
450 {
451  /* check input consistency */
452  if ( !multiSFTs || multiSFTs->length == 0 ) {
453  XLALPrintError( "%s: illegal NULL or empty input 'multiSFTs'.\n", __func__ );
455  }
456  UINT4 numIFOs = multiSFTs->length;
457 
458  /* create output vector */
459  MultiLIGOTimeGPSVector *ret = NULL;
460  if ( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) == NULL ) {
461  XLALPrintError( "%s: failed to XLALCalloc ( 1, %zu ).\n", __func__, sizeof( *ret ) );
463  }
464 
465  if ( ( ret->data = XLALCalloc( numIFOs, sizeof( *ret->data ) ) ) == NULL ) {
466  XLALPrintError( "%s: failed to XLALCalloc ( %d, %zu ).\n", __func__, numIFOs, sizeof( ret->data[0] ) );
467  XLALFree( ret );
469  }
470  ret->length = numIFOs;
471 
472  /* now extract timestamps vector from each SFT-vector */
473  UINT4 X;
474  for ( X = 0; X < numIFOs; X ++ ) {
475  if ( ( ret->data[X] = XLALExtractTimestampsFromSFTs( multiSFTs->data[X] ) ) == NULL ) {
476  XLALPrintError( "%s: XLALExtractTimestampsFromSFTs() failed for X=%d\n", __func__, X );
479  }
480 
481  } /* for X < numIFOs */
482 
483  return ret;
484 
485 } /* XLALExtractMultiTimestampsFromSFTs() */
486 
487 
488 /**
489  * Extract timestamps-vector of *unique* timestamps from the given SFTCatalog
490  *
491  * NOTE: when dealing with catalogs of frequency-slided SFTs, each timestamp will appear in the
492  * catalog multiple times, depending on how many frequency slices have been read in.
493  * In such cases this function will return the list of *unique* timestamps.
494  *
495  * NOTE 2: This function will also enfore the multiplicity of each timestamp to be the
496  * same through the whole catalog, corresponding to the case of 'frequency-sliced' SFTs,
497  * while non-constant multiplicities would indicate a potential problem somewhere.
498  */
500 XLALTimestampsFromSFTCatalog( const SFTCatalog *catalog ) /**< [in] input SFT-catalog */
501 {
502  // check input consistency
503  XLAL_CHECK_NULL( catalog != NULL, XLAL_EINVAL );
504  XLAL_CHECK_NULL( catalog->length > 0, XLAL_EINVAL );
505 
506  UINT4 numEntries = catalog->length;
507 
508  // create output vector, assuming maximal length, realloc at the end
509  LIGOTimeGPSVector *ret;
510  XLAL_CHECK_NULL( ( ret = XLALCreateTimestampVector( numEntries ) ) != NULL, XLAL_EFUNC );
511 
512  REAL8 Tsft0 = 1.0 / catalog->data[0].header.deltaF;
513  if ( fabs( ( Tsft0 - round( Tsft0 ) ) ) / Tsft0 < 10 * LAL_REAL8_EPS ) { // 10-eps 'snap' to closest integer
514  ret->deltaT = round( Tsft0 );
515  } else {
516  ret->deltaT = Tsft0;
517  }
518 
519  // For dealing with SFTCatalogs corresponding to frequency-sliced input SFTs:
520  // Given the guaranteed GPS-ordering of XLALSFTDataFind(), we can rely on duplicate
521  // timestamps to all be found next to each other, and therefore can easily skip them
522  ret->data[0] = catalog->data[0].header.epoch;
523  UINT4 numUnique = 1;
524  UINT4 stride = 0;
525  for ( UINT4 i = 1; i < numEntries; i ++ ) {
526  UINT4 thisStride = 1;
527  const LIGOTimeGPS *ti = &( catalog->data[i].header.epoch );
528  const LIGOTimeGPS *tim1 = &( catalog->data[i - 1].header.epoch );
529  if ( XLALGPSCmp( ti, tim1 ) == 0 ) {
530  thisStride ++;
531  continue; // skip duplicates
532  }
533  ret->data[numUnique] = catalog->data[i].header.epoch;
534  numUnique ++;
535 
536  // keep track of stride, ensure that it's the same for every unique timestamp
537  if ( stride == 0 ) {
538  stride = thisStride;
539  } else {
540  XLAL_CHECK_NULL( stride == thisStride, XLAL_EINVAL, "Suspicious SFT Catalog with non-constant timestamps multiplicities '%u != %u'\n", stride, thisStride );
541  }
542  } // for i < numEntries
543 
544 
545  // now truncate output vector to actual length of unique timestamps
546  ret->length = numUnique;
547  XLAL_CHECK_NULL( ( ret->data = XLALRealloc( ret->data, numUnique * sizeof( ( *ret->data ) ) ) ) != NULL, XLAL_ENOMEM );
548 
549  // done: return Ts-vector
550  return ret;
551 
552 } /* XLALTimestampsFromSFTCatalog() */
553 
554 
555 /**
556  * Given a multi-SFTCatalogView, return a MultiLIGOTimeGPSVector holding the
557  * SFT timestamps
558  */
561 {
562  /* check input consistency */
563  XLAL_CHECK_NULL( multiView != NULL, XLAL_EINVAL );
564  XLAL_CHECK_NULL( multiView->length > 0, XLAL_EINVAL );
565 
566  UINT4 numIFOs = multiView->length;
567 
568  /* create output vector */
570  XLAL_CHECK_NULL( ( ret = XLALCalloc( 1, sizeof( *ret ) ) ) != NULL, XLAL_ENOMEM );
571  XLAL_CHECK_NULL( ( ret->data = XLALCalloc( numIFOs, sizeof( *( ret->data ) ) ) ) != NULL, XLAL_ENOMEM );
572  ret->length = numIFOs;
573 
574  /* now extract timestamps vector from each IFO's SFT-Catalog */
575  for ( UINT4 X = 0; X < numIFOs; X ++ ) {
576  XLAL_CHECK_NULL( ( ret->data[X] = XLALTimestampsFromSFTCatalog( &( multiView->data[X] ) ) ) != NULL, XLAL_EFUNC );
577  } /* for X < numIFOs */
578 
579  return ret;
580 
581 } /* XLALTimestampsFromMultiSFTCatalogView() */
582 
583 
584 /**
585  * Function to read a segment list from given filename, returns a *sorted* LALSegList
586  *
587  * The segment list file format is repeated lines (excluding comment lines beginning with
588  * <tt>\%</tt> or <tt>#</tt>) of one of the following forms:
589  * - <tt>startGPS endGPS</tt>
590  * - <tt>startGPS endGPS NumSFTs</tt> (NumSFTs must be a positive integer)
591  * - <tt>startGPS endGPS duration NumSFTs</tt> (\b DEPRECATED, duration is ignored)
592  *
593  * \note We (ab)use the integer \p id field in LALSeg to carry the total number of SFTs
594  * contained in that segment if <tt>NumSFTs</tt> was provided in the segment file.
595  * This can be used as a consistency check when loading SFTs for these segments.
596  */
597 LALSegList *
598 XLALReadSegmentsFromFile( const char *fname /**< name of file containing segment list */
599  )
600 {
601  LALSegList *segList = NULL;
602 
603  /* check input consistency */
604  XLAL_CHECK_NULL( fname != NULL, XLAL_EFAULT );
605 
606  /* read and parse segment-list file contents*/
607  LALParsedDataFile *flines = NULL;
608  XLAL_CHECK_NULL( XLALParseDataFile( &flines, fname ) == XLAL_SUCCESS, XLAL_EFUNC );
609  const UINT4 numSegments = flines->lines->nTokens;
610  XLAL_CHECK_NULL( numSegments > 0, XLAL_EINVAL, "%s: segment file '%s' does not contain any segments", __func__, fname );
611 
612  /* allocate and initialized segment list */
613  XLAL_CHECK_NULL( ( segList = XLALCalloc( 1, sizeof( *segList ) ) ) != NULL, XLAL_ENOMEM );
615 
616  /* determine number of columns */
617  int ncol = 0;
618  {
619  REAL8 col[4];
620  ncol = sscanf( flines->lines->tokens[0], "%lf %lf %lf %lf", &col[0], &col[1], &col[2], &col[3] );
621  switch ( ncol ) {
622  case 2:
623  case 3:
624  break;
625  case 4:
627  XLALPrintError( "\n%s: WARNING: segment file '%s' is in DEPRECATED 4-column format (startGPS endGPS duration NumSFTs, duration is ignored)\n", __func__, fname );
628  } else {
629  XLAL_ERROR_NULL( XLAL_EIO, "%s: segment file '%s' is in DEPRECATED 4-column format (startGPS endGPS duration NumSFTs)\n", __func__, fname );
630  }
631  break;
632  default:
633  XLAL_ERROR_NULL( XLAL_EIO, "%s: segment file '%s' contains an unknown %i-column format", __func__, fname, ncol );
634  }
635  }
636 
637  /* parse segment list */
638  for ( UINT4 iSeg = 0; iSeg < numSegments; iSeg ++ ) {
639 
640  /* parse line of segment file, depending on determined number of columns */
641  REAL8 start = 0, end = 0, duration = 0;
642  INT4 NumSFTs = 0;
643  int ret;
644  switch ( ncol ) {
645  case 2:
646  ret = sscanf( flines->lines->tokens[iSeg], "%lf %lf", &start, &end );
647  XLAL_CHECK_NULL( ret == 2, XLAL_EIO, "%s: number of columns in segment file '%s' is inconsistent (line 1: %i, line %u: %i)", __func__, fname, ncol, iSeg + 1, ret );
648  break;
649  case 3:
650  ret = sscanf( flines->lines->tokens[iSeg], "%lf %lf %i", &start, &end, &NumSFTs );
651  XLAL_CHECK_NULL( ret == 3, XLAL_EIO, "%s: number of columns in segment file '%s' is inconsistent (line 1: %i, line %u: %i)", __func__, fname, ncol, iSeg + 1, ret );
652  XLAL_CHECK_NULL( NumSFTs > 0, XLAL_EIO, "%s: number of SFTs (3rd column) in segment file '%s' must be a positive integer if given (line %u: %i)", __func__, fname, iSeg + 1, NumSFTs );
653  break;
654  case 4:
655  ret = sscanf( flines->lines->tokens[iSeg], "%lf %lf %lf %i", &start, &end, &duration, &NumSFTs );
656  XLAL_CHECK_NULL( ret == 4, XLAL_EIO, "%s: number of columns in segment file '%s' is inconsistent (line 1 = %i, line %u = %i)", __func__, fname, ncol, iSeg + 1, ret );
657  break;
658  default:
659  XLAL_ERROR_NULL( XLAL_EFAILED, "Unexpected error!" );
660  }
661 
662  /* set GPS start and end times */
663  LIGOTimeGPS startGPS, endGPS;
664  XLALGPSSetREAL8( &startGPS, start );
665  XLALGPSSetREAL8( &endGPS, end );
666 
667  /* create segment and append to list
668  - we set number of SFTs as 'id' field, as we have no other use for it */
669  LALSeg thisSeg;
670  XLAL_CHECK_NULL( XLALSegSet( &thisSeg, &startGPS, &endGPS, NumSFTs ) == XLAL_SUCCESS, XLAL_EFUNC );
672 
673  } /* for iSeg < numSegments */
674 
675  /* sort final segment list in increasing GPS start-times */
677 
678  /* free parsed segment file contents */
679  XLALDestroyParsedDataFile( flines );
680 
681  return segList;
682 
683 } /* XLALReadSegmentsFromFile() */
684 
685 
686 /**
687  * Extract timestamps-vector from a segment file, with functionality based on MakeSFTDAG
688  * The filename should point to a file containing <GPSstart GPSend> of segments or <GPSstart GPSend segLength numSFTs> where segLength is in hours.
689  * adjustSegExtraTime is used in MakeSFTDAG to maximize the number of SFTs in each segement by placing the SFTs in the middle of the segment.
690  * synchronize is used to force the start times of the SFTs to be integer multiples of Toverlap from the start time of the first SFT.
691  * adjustSegExtraTime and synchronize cannot be used concurrently (synchronize will be preferred if both values are non-zero).
692  */
694 XLALTimestampsFromSegmentFile( const char *filename, //!< filename: Input filename
695  REAL8 Tsft, //!< Tsft: SFT length of each timestamp, in seconds
696  REAL8 Toverlap, //!< Toverlap: time to overlap successive SFTs by, in seconds
697  BOOLEAN adjustSegExtraTime, //!< adjustSegExtraTime: remove the unused time from beginning and end of the segments (see MakeSFTDAG)
698  BOOLEAN synchronize //!< synchronize: synchronize SFT start times according to the start time of the first SFT. Start time of first SFT is shifted to next higher integer value of Tsft
699  )
700 {
702  XLAL_CHECK_NULL( !( adjustSegExtraTime && synchronize ), XLAL_EINVAL, "Must specify only one of adjustSegExtraTime or synchronize" );
703 
704  LALSegList *list = NULL;
706 
707  //Need to know the number of SFTs before creating the timestamps vector, so we have to do the same loop twice
708  INT4 numSFTs = 0;
709  REAL8 firstSFTstartTime = 0.0, overlapFraction = Toverlap / Tsft;
710 
711  for ( UINT4 i = 0; i < list->length; i++ ) {
712  INT4 numThisSeg = 0;
713  REAL8 analysisStartTime, analysisEndTime;
714  if ( adjustSegExtraTime && !synchronize ) {
715  REAL8 segStartTime = XLALGPSGetREAL8( &( list->segs[i].start ) );
716  REAL8 segEndTime = XLALGPSGetREAL8( &( list->segs[i].end ) );
717  REAL8 segExtraTime = fmod( ( segEndTime - segStartTime ), Tsft );
718  if ( overlapFraction != 0.0 ) {
719  if ( ( segEndTime - segStartTime ) > Tsft ) {
720  segExtraTime = fmod( ( segEndTime - segStartTime - Tsft ), ( ( 1.0 - overlapFraction ) * Tsft ) );
721  }
722  } else {
723  segExtraTime = fmod( ( segEndTime - segStartTime ), Tsft );
724  }
727  analysisStartTime = segStartTime + segExtraStart;
728  if ( analysisStartTime > segEndTime ) {
729  analysisStartTime = segEndTime;
730  }
731  analysisEndTime = segEndTime - segExtraEnd;
732  if ( analysisEndTime < segStartTime ) {
733  analysisEndTime = segStartTime;
734  }
735  } // if adjustSegExtraTime && !synchronize
736  else if ( synchronize ) {
737  REAL8 segStartTime = XLALGPSGetREAL8( &( list->segs[i].start ) );
738  REAL8 segEndTime = XLALGPSGetREAL8( &( list->segs[i].end ) );
739  if ( firstSFTstartTime == 0.0 ) {
740  firstSFTstartTime = ceil( segStartTime / Tsft ) * Tsft;
741  }
742  analysisStartTime = round( ceil( ( segStartTime - firstSFTstartTime ) / ( ( 1.0 - overlapFraction ) * Tsft ) ) * ( 1.0 - overlapFraction ) * Tsft ) + firstSFTstartTime;
743  if ( analysisStartTime > segEndTime ) {
744  analysisStartTime = segEndTime;
745  }
746  analysisEndTime = round( floor( ( segEndTime - analysisStartTime - Tsft ) / ( ( 1.0 - overlapFraction ) * Tsft ) ) * ( 1.0 - overlapFraction ) * Tsft ) + Tsft + analysisStartTime;
747  if ( analysisEndTime < segStartTime ) {
748  analysisEndTime = segStartTime;
749  }
750  } else {
751  analysisStartTime = XLALGPSGetREAL8( &( list->segs[i].start ) );
752  analysisEndTime = XLALGPSGetREAL8( &( list->segs[i].end ) );
753  }
754 
755  REAL8 endTime = analysisStartTime;
756  while ( endTime < analysisEndTime ) {
757  if ( numThisSeg == 0 ) {
758  endTime += Tsft;
759  } else {
760  endTime += ( 1.0 - overlapFraction ) * Tsft;
761  }
762  if ( endTime <= analysisEndTime ) {
763  numThisSeg++;
764  }
765  } // while endTime < analysisEndTime
766  numSFTs += numThisSeg;
767  } // for i < length
768 
769  LIGOTimeGPSVector *ret;
771 
772  ret->deltaT = Tsft;
773 
774  //Second time doing the same thing, but now we can set the times of the SFTs in the timestamps vector
775  firstSFTstartTime = 0.0;
776  UINT4 j = 0;
777  for ( UINT4 i = 0; i < list->length; i++ ) {
778  INT4 numThisSeg = 0;
779  REAL8 analysisStartTime, analysisEndTime;
780  if ( adjustSegExtraTime && !synchronize ) {
781  REAL8 segStartTime = XLALGPSGetREAL8( &( list->segs[i].start ) );
782  REAL8 segEndTime = XLALGPSGetREAL8( &( list->segs[i].end ) );
783  REAL8 segExtraTime = fmod( ( segEndTime - segStartTime ), Tsft );
784  if ( overlapFraction != 0.0 ) {
785  if ( ( segEndTime - segStartTime ) > Tsft ) {
786  segExtraTime = fmod( ( segEndTime - segStartTime - Tsft ), ( ( 1.0 - overlapFraction ) * Tsft ) );
787  }
788  } else {
789  segExtraTime = fmod( ( segEndTime - segStartTime ), Tsft );
790  }
793  analysisStartTime = segStartTime + segExtraStart;
794  if ( analysisStartTime > segEndTime ) {
795  analysisStartTime = segEndTime;
796  }
797  analysisEndTime = segEndTime - segExtraEnd;
798  if ( analysisEndTime < segStartTime ) {
799  analysisEndTime = segStartTime;
800  }
801  } // if adjustSegExtraTime && !synchronize
802  else if ( synchronize ) {
803  REAL8 segStartTime = XLALGPSGetREAL8( &( list->segs[i].start ) );
804  REAL8 segEndTime = XLALGPSGetREAL8( &( list->segs[i].end ) );
805  if ( firstSFTstartTime == 0.0 ) {
806  firstSFTstartTime = ceil( segStartTime / Tsft ) * Tsft;
807  }
808  analysisStartTime = round( ceil( ( segStartTime - firstSFTstartTime ) / ( ( 1.0 - overlapFraction ) * Tsft ) ) * ( 1.0 - overlapFraction ) * Tsft ) + firstSFTstartTime;
809  if ( analysisStartTime > segEndTime ) {
810  analysisStartTime = segEndTime;
811  }
812  analysisEndTime = round( floor( ( segEndTime - analysisStartTime - Tsft ) / ( ( 1.0 - overlapFraction ) * Tsft ) ) * ( 1.0 - overlapFraction ) * Tsft ) + Tsft + analysisStartTime;
813  if ( analysisEndTime < segStartTime ) {
814  analysisEndTime = segStartTime;
815  }
816  } else {
817  analysisStartTime = XLALGPSGetREAL8( &( list->segs[i].start ) );
818  analysisEndTime = XLALGPSGetREAL8( &( list->segs[i].end ) );
819  }
820 
821  REAL8 endTime = analysisStartTime;
822  while ( endTime < analysisEndTime ) {
823  if ( numThisSeg == 0 ) {
824  endTime += Tsft;
825  } else {
826  endTime += ( 1.0 - overlapFraction ) * Tsft;
827  }
828  if ( endTime <= analysisEndTime ) {
829  numThisSeg++;
830  LIGOTimeGPS sftStart;
831  XLALGPSSetREAL8( &sftStart, endTime - Tsft );
832  ret->data[j] = sftStart;
833  j++;
834  }
835  } // while ( endTime < analysisEndTime )
836  } // for i < length
837 
838  XLALSegListFree( list );
839 
840  /* done: return Ts-vector */
841  return ret;
842 
843 } // XLALTimestampsFromSegmentFile()
844 
845 /// @}
#define __func__
log an I/O error, i.e.
int j
Internal SFT types and functions.
static const REAL8 fudge_down
Definition: SFTinternal.h:64
int XLALReadSegmentsFromFile_support_4column_format
Definition: SFTtimestamps.c:38
LIGOTimeGPSVector * timestamps
int XLALParseDataFile(LALParsedDataFile **cfgdata, const CHAR *fname)
void XLALDestroyParsedDataFile(LALParsedDataFile *cfgdata)
#define LAL_GPS_FORMAT
char * XLALGPSToStr(char *s, const LIGOTimeGPS *t)
#define LAL_GPS_PRINT(gps)
#define LAL_REAL8_EPS
unsigned char BOOLEAN
double REAL8
char CHAR
uint32_t UINT4
int32_t INT4
void * XLALCalloc(size_t m, size_t n)
void * XLALMalloc(size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
#define LAL_INT4_FORMAT
LIGOTimeGPSVector * XLALMakeTimestamps(LIGOTimeGPS tStart, REAL8 Tspan, REAL8 Tsft, REAL8 Toverlap)
Given a start-time, Tspan, Tsft and Toverlap, returns a list of timestamps covering this time-stretch...
LIGOTimeGPSVector * XLALExtractTimestampsFromSFTs(const SFTVector *sfts)
Extract timstamps-vector from the given SFTVector.
MultiLIGOTimeGPSVector * XLALReadMultiTimestampsFilesConstrained(const LALStringVector *fnames, const LIGOTimeGPS *minGPS, const LIGOTimeGPS *maxGPS)
Load several timestamps files, return a MultiLIGOTimeGPSVector struct, allocated here.
MultiLIGOTimeGPSVector * XLALMakeMultiTimestamps(LIGOTimeGPS tStart, REAL8 Tspan, REAL8 Tsft, REAL8 Toverlap, UINT4 numDet)
Same as XLALMakeTimestamps() just for several detectors, additionally specify the number of detectors...
REAL8 TSFTfromDFreq(REAL8 dFreq)
Definition: SFTtypes.c:1144
int XLALFindTimesliceBounds(UINT4 *iStart, UINT4 *iEnd, const LIGOTimeGPSVector *timestamps, const LIGOTimeGPS *minStartGPS, const LIGOTimeGPS *maxStartGPS)
MultiLIGOTimeGPSVector * XLALTimestampsFromMultiSFTCatalogView(const MultiSFTCatalogView *multiView)
Given a multi-SFTCatalogView, return a MultiLIGOTimeGPSVector holding the SFT timestamps.
LALSegList * XLALReadSegmentsFromFile(const char *fname)
Function to read a segment list from given filename, returns a sorted LALSegList.
LIGOTimeGPSVector * XLALCreateTimestampVector(UINT4 len)
Allocate a LIGOTimeGPSVector.
Definition: SFTtimestamps.c:47
LIGOTimeGPSVector * XLALResizeTimestampVector(LIGOTimeGPSVector *vector, UINT4 length)
Resize a LIGOTimeGPSVector.
Definition: SFTtimestamps.c:85
LIGOTimeGPSVector * XLALTimestampsFromSegmentFile(const char *filename, REAL8 Tsft, REAL8 Toverlap, BOOLEAN adjustSegExtraTime, BOOLEAN synchronize)
Extract timestamps-vector from a segment file, with functionality based on MakeSFTDAG The filename sh...
MultiLIGOTimeGPSVector * XLALExtractMultiTimestampsFromSFTs(const MultiSFTVector *multiSFTs)
Given a multi-SFT vector, return a MultiLIGOTimeGPSVector holding the SFT timestamps.
LIGOTimeGPSVector * XLALReadTimestampsFile(const CHAR *fname)
backwards compatible wrapper to XLALReadTimestampsFileConstrained() without GPS-time constraints
int XLALCWGPSinRange(const LIGOTimeGPS gps, const LIGOTimeGPS *minGPS, const LIGOTimeGPS *maxGPS)
Defines the official CW convention for whether a GPS time is 'within' a given range,...
Definition: SFTtypes.c:52
void XLALDestroyMultiTimestamps(MultiLIGOTimeGPSVector *multiTS)
Destroy a MultiLIGOTimeGPSVector timestamps vector.
MultiLIGOTimeGPSVector * XLALCreateMultiLIGOTimeGPSVector(UINT4 numDetectors)
Simple creator function for MultiLIGOTimeGPSVector with numDetectors entries.
void XLALDestroyTimestampVector(LIGOTimeGPSVector *vect)
De-allocate a LIGOTimeGPSVector.
Definition: SFTtimestamps.c:69
MultiLIGOTimeGPSVector * XLALReadMultiTimestampsFiles(const LALStringVector *fnames)
backwards compatible wrapper to XLALReadMultiTimestampsFilesConstrained() without GPS-time constraint...
LIGOTimeGPSVector * XLALReadTimestampsFileConstrained(const CHAR *fname, const LIGOTimeGPS *minGPS, const LIGOTimeGPS *maxGPS)
Load timestamps file 'fname' into LIGOTimeGPSVector struct, allocated here.
LIGOTimeGPSVector * XLALTimestampsFromSFTCatalog(const SFTCatalog *catalog)
Extract timestamps-vector of unique timestamps from the given SFTCatalog.
int XLALSegListInit(LALSegList *seglist)
int XLALSegListSort(LALSegList *seglist)
int XLALSegListFree(LALSegList *seglist)
int XLALSegListAppend(LALSegList *seglist, const LALSeg *seg)
int XLALSegSet(LALSeg *seg, const LIGOTimeGPS *start, const LIGOTimeGPS *end, const INT4 id)
int XLALParseStringValueAsEPOCH(LIGOTimeGPS *gps, const char *valString)
#define XLAL_ERROR_NULL(...)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int int XLALPrintWarning(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EIO
XLAL_EINVAL
XLAL_EFAILED
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
LIGOTimeGPS * XLALGPSSetREAL8(LIGOTimeGPS *epoch, REAL8 t)
int XLALGPSCmp(const LIGOTimeGPS *t0, const LIGOTimeGPS *t1)
REAL8 XLALGPSGetREAL8(const LIGOTimeGPS *epoch)
end
out
fnames
int N
size_t numDetectors
A vector of COMPLEX8FrequencySeries.
COMPLEX8FrequencySeries * data
Pointer to the data array.
UINT4 length
Number of elements in array.
TokenList * lines
LIGOTimeGPS end
LIGOTimeGPS start
UINT4 length
LALSeg * segs
INT4 gpsNanoSeconds
A vector of 'timestamps' of type LIGOTimeGPS.
Definition: SFTfileIO.h:188
REAL8 deltaT
'length' of each timestamp (e.g.
Definition: SFTfileIO.h:194
LIGOTimeGPS * data
array of timestamps
Definition: SFTfileIO.h:193
UINT4 length
number of timestamps
Definition: SFTfileIO.h:192
A collection of (multi-IFO) LIGOTimeGPSVector time-stamps vectors.
Definition: SFTfileIO.h:198
UINT4 length
number of timestamps vectors or ifos
Definition: SFTfileIO.h:202
LIGOTimeGPSVector ** data
timestamps vector for each ifo
Definition: SFTfileIO.h:203
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
CHAR ** tokens
UINT4 nTokens