LAL  7.5.0.1-bede9b2
Segments.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 Alexander Dietz, Jolien Creighton, Peter Shawhan
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19 
20 #include <stdlib.h>
21 #include <lal/LALStdlib.h>
22 #include <lal/Date.h>
23 #include <lal/Segments.h>
24 #include <lal/LALString.h>
25 
26 /**
27  * \addtogroup Segments_h
28  *
29  * ### Functions for handling segments ###
30  *
31  * The first few functions listed deal with \e segments:
32  *
33  * XLALSegSet(), XLALSegCreate(), XLALGPSInSeg(), XLALSegCmp()
34  *
35  * ### Functions for handling segment lists ###
36  *
37  * The rest of the functions listed deal with <em>segment lists</em>:
38  *
39  * XLALSegListInit(), XLALSegListClear(), XLALSegListAppend(), XLALSegListSort()
40  * XLALSegListCoalesce(), XLALSegListSearch()
41  *
42  * ### Error codes and return values ###
43  *
44  * Each XLAL function listed above, if it fails invokes the current XLAL error
45  * handler, sets \c xlalErrno to the appropriate XLAL error code, and
46  * returns a particular value as noted below:
47  *
48  * <ul>
49  * <li>
50  * Functions which return an integer status code (XLALSegSet(),
51  * XLALSegListInit(), XLALSegListClear(), XLALSegListAppend(), XLALSegListSort(),
52  * XLALSegListCoalesce() return XLAL_SUCCESS if successful
53  * or XLAL_FAILURE if an error occurs.</li>
54  * <li>
55  * XLALGPSInSeg() and XLALSegCmp() normally return a
56  * comparison value (negative, 0, or positive).</li>
57  * <li>
58  * XLALSegCreate() normally returns a pointer to the created
59  * segment. If an error occurs, it returns NULL.</li>
60  * <li>
61  * XLALSegListSearch() returns a pointer to a segment in the list which
62  * contains the time being searched for, or NULL if there is no such segment.
63  * If more than one segment in the list contains the time, then this function
64  * returns a pointer to \e one of the segments which contains it, not
65  * necessarily the first such segment in the list. (This is not an issue if
66  * the list is ``disjoint'', which guarantees that it has no overlapping
67  * segments.) If no segment in the list contains the time, then this function
68  * returns NULL; however, this is not really an error, use \c xlalErrno
69  * to differentiate between failure and non-failure.
70  * </li>
71  * </ul>
72  *
73  */
74 
75 
76 /*---------------------------------------------------------------------------*/
77 /**
78  * This function sets the start time, the end time, and the \a id of a segment.
79  * The \a id can be any integer and is
80  * solely for the use of the user, e.g. to store a segment ID code
81  * or an index into some array containing additional information about the
82  * segment. XLALSegSet() checks to make sure the segment is valid,
83  * i.e. the end time is later than or equal to the start time;
84  * an error occurs if this condition is not true.
85  */
86 int
87 XLALSegSet( LALSeg *seg, const LIGOTimeGPS *start, const LIGOTimeGPS *end,
88  const INT4 id )
89 {
90 
91  /* Make sure a non-null pointer was passed for the segment to be set */
92  if ( ! seg ) {
93  XLALPrintError( "NULL LALSeg pointer passed to %s\n", __func__ );
95  }
96 
97  /* Make sure non-null pointers were passed for the GPS times */
98  if ( ! start || ! end ) {
99  XLALPrintError( "NULL LIGOTimeGPS pointer passed to %s\n", __func__ );
101  }
102 
103  /* Check that segment end time is equal to or later than start time */
104  if ( XLALGPSCmp(start,end) > 0 ) {
105  XLALPrintError( "Inconsistent times passed to %s (%d.%09d > %d.%09d)\n",
106  __func__, start->gpsSeconds, start->gpsNanoSeconds,
107  end->gpsSeconds, end->gpsNanoSeconds );
109  }
110 
111  /* Store the times and the id */
112  seg->start = *start;
113  seg->end = *end;
114  seg->id = id;
115 
116  /* Return with success status code */
117  return XLAL_SUCCESS;
118 }
119 
120 
121 /*---------------------------------------------------------------------------*/
122 
123 /**
124  * This function is similar to XLALSegSet()
125  * except that it allocates memory for a new segment structure rather than setting
126  * the fields of an existing segment structure. It returns a pointer to the
127  * new \a LALSeg structure. When the structure is no longer needed, its
128  * pointer should be passed to XLALFree().
129  */
130 LALSeg *
131 XLALSegCreate( const LIGOTimeGPS *start, const LIGOTimeGPS *end,
132  const INT4 id )
133 {
134  LALSeg *segptr;
135 
136  /* Make sure non-null pointers were passed for the GPS times */
137  if ( ! start || ! end ) {
138  XLALPrintError( "NULL LIGOTimeGPS pointer passed to %s\n", __func__ );
140  }
141 
142  /* Check that segment end time is equal to or later than start time */
143  if ( XLALGPSCmp(start,end) > 0 ) {
144  XLALPrintError( "Inconsistent times passed to %s (%d.%09d > %d.%09d)\n",
145  __func__, start->gpsSeconds, start->gpsNanoSeconds,
146  end->gpsSeconds, end->gpsNanoSeconds );
148  }
149 
150  /* Allocate memory for the new LALSeg object */
151  segptr = (LALSeg *) LALMalloc( sizeof(LALSeg) );
152 
153  /* Check for a memory allocation failure */
154  if ( ! segptr ) {
156  }
157 
158  /* Store the times and the id */
159  segptr->start = *start;
160  segptr->end = *end;
161  segptr->id = id;
162 
163  /* Return a pointer to the newly-created segment */
164  return segptr;
165 }
166 
167 
168 /*---------------------------------------------------------------------------*/
169 
170 /**
171  * This is designed to be usable as a comparison function for
172  * <tt>bsearch()</tt> and therefore returns a negative value, 0, or a positive
173  * value depending on whether the GPS time (the first argument) is before the
174  * beginning of, within, or after the end of the segment (the second argument).
175  * Note that a segment is a half-open interval, so the GPS time is considered
176  * to be within the segment if it is equal to the start time of the segment
177  * but not if it is equal to the end time of the segment.
178  *
179  * Returns a comparison value (negative, 0, or positive).
180  */
181 int
182 XLALGPSInSeg( const void *pgps, const void *pseg )
183 {
184  XLAL_CHECK(pseg != NULL, XLAL_EFAULT);
185  const LIGOTimeGPS *gps = pgps;
186  const LALSeg *seg = pseg;
187 
188  /* if time is < start of segment, return -1 */
189  if ( XLALGPSCmp( gps, &seg->start ) < 0 )
190  return -1;
191  /* else if time is < end of segment, return 0 */
192  if ( XLALGPSCmp( gps, &seg->end ) < 0 )
193  return 0;
194  /* time is >= end of segment, return +1 */
195  return +1;
196 }
197 
198 
199 /*---------------------------------------------------------------------------*/
200 
201 /**
202  * This is designed to be usable as a comparison function for
203  * <tt>qsort()</tt> and therefore returns a negative value, 0, or a positive value
204  * depending on
205  * whether the first argument is less than, equal to, or greater than the second.
206  * The comparison is based on the start time of the segments, unless these are
207  * equal, in which case the end times are compared. Therefore, two segments
208  * are considered equal only if their start \e and end times are identical.
209  *
210  * Returns a comparison value (negative, 0, or positive).
211  */
212 int
213 XLALSegCmp( const void *pseg0, const void *pseg1 )
214 {
215  XLAL_CHECK(pseg0 != NULL && pseg1 != NULL, XLAL_EFAULT);
216  const LALSeg *seg0 = pseg0;
217  const LALSeg *seg1 = pseg1;
218  int result;
219 
220  /* If segment start times are different, comparison is based on that */
221  result = XLALGPSCmp( &seg0->start, &seg1->start );
222  if ( !result ) {
223  /* If we get here, then the segments have the same start time,
224  so use the end times to do the comparison */
225  result = XLALGPSCmp( &seg0->end, &seg1->end );
226  }
227 
228  return result;
229 }
230 
231 
232 /*---------------------------------------------------------------------------*/
233 
234 /**
235  * This function allocates memory for a new segment list structure,
236  * initializes the segment list, and returns a pointer to it.
237  */
238 LALSegList *
240 {
241  LALSegList *seglist = XLALMalloc(sizeof(*seglist));
242  XLAL_CHECK_NULL( seglist != NULL, XLAL_ENOMEM );
244  return seglist;
245 }
246 
247 
248 /*---------------------------------------------------------------------------*/
249 
250 /**
251  * This function must be called to initialize a segment
252  * list structure before that structure can be used.
253  */
254 int
256 {
257  /* Make sure a non-null pointer was passed for the segment list */
258  if ( ! seglist ) {
259  XLALPrintError( "NULL LALSegList pointer passed to %s\n", __func__ );
261  }
262 
263  /* Initialize values for this segment list */
264  seglist->segs = NULL;
265  seglist->arraySize = 0;
266  seglist->length = 0;
267 
268  /* So far, we do not need any decimal places to format GPS times */
269  seglist->dplaces = 0;
270 
271  /* An empty list can be considered sorted and disjoint */
272  seglist->sorted = 1;
273  seglist->disjoint = 1;
274 
275  /* No search has been performed yet */
276  seglist->lastFound = NULL;
277 
278  /* Store a distinctive integer value to serve as a check that initialization
279  was performed */
281 
282  /* Return with success status code */
283  return XLAL_SUCCESS;
284 }
285 
286 
287 /*---------------------------------------------------------------------------*/
288 
289 /**
290  * This function must be called when you are done
291  * with a segment list, in order to free memory that was allocated to store
292  * the segments in the list. (Strictly speaking, this is only necessary if the
293  * list contains one or more segments.)
294  * The function leaves the segment list in a valid
295  * state, but containing no segments. After calling XLALSegListClear(),
296  * it is OK to re-use the segment list structure (by using
297  * XLALSegListAppend() to add segments to it, etc.).
298  * You do not have to call XLALSegListInit() again before re-using it,
299  * but it is OK to do so. If you do call XLALSegListInit() again,
300  * you must do so \e after calling XLALSegListClear() !
301  */
302 int
304 {
305  /* Make sure a non-null pointer was passed for the segment list */
306  if ( ! seglist ) {
307  XLALPrintError( "NULL LALSegList pointer passed to %s\n", __func__ );
309  }
310 
311  /* Make sure the segment list has been properly initialized */
312  if ( seglist->initMagic != SEGMENTSH_INITMAGICVAL ) {
313  XLALPrintError( "Passed unintialized LALSegList structure to %s\n", __func__ );
315  }
316 
317  /* Clear the memory (if any) that has been allocated for segments */
318  if ( seglist->segs ) {
319  LALFree( seglist->segs );
320  }
321 
322  /* Clear values related to the segment list */
323  seglist->segs = NULL;
324  seglist->arraySize = 0;
325  seglist->length = 0;
326 
327  /* So far, we do not need any decimal places to format GPS times */
328  seglist->dplaces = 0;
329 
330  /* An empty list can be considered sorted and disjoint */
331  seglist->sorted = 1;
332  seglist->disjoint = 1;
333 
334  /* No search has been performed yet */
335  seglist->lastFound = NULL;
336 
337  /* Return with success status code */
338  return XLAL_SUCCESS;
339 }
340 
341 
342 /*---------------------------------------------------------------------------*/
343 
344 /**
345  * This function frees a segment list created with XLALSegListCreate().
346  */
347 int
349 {
350  if ( seglist ) {
352  XLALFree( seglist );
353  }
354  return XLAL_SUCCESS;
355 }
356 
357 
358 /*---------------------------------------------------------------------------*/
359 
360 /**
361  * This function appends a segment to a segment list.
362  * It first checks to make sure the segment is valid,
363  * i.e. the end time is later than or equal to the start time;
364  * an error occurs if this condition is not true.
365  * The input segment information is copied into an array of \c LALSeg
366  * structures maintained ``internally'' by the segment list. The function takes
367  * care of extending this array when necessary.
368  * It also checks whether the segment being appended preserves the ``sorted''
369  * and/or ``disjoint'' properties of the segment list. An empty segment list has
370  * the ``sorted'' and ``disjoint'' properties to start with, and as long as
371  * segments are appended in ascending time order and do not overlap, it retains
372  * those properties.
373  */
374 int
375 XLALSegListAppend( LALSegList *seglist, const LALSeg *seg )
376 {
377  LALSeg *segptr;
378  LALSeg *prev;
379  size_t newSize;
380  INT4 ns1, ns2;
381 
382  /* Make sure a non-null pointer was passed for the segment list */
383  if ( ! seglist ) {
384  XLALPrintError( "NULL LALSegList pointer passed to %s\n", __func__ );
386  }
387 
388  /* Make sure a non-null pointer was passed for the segment */
389  if ( ! seg ) {
390  XLALPrintError( "NULL LALSeg pointer passed to %s\n", __func__ );
392  }
393 
394  /* Make sure the segment list has been properly initialized */
395  if ( seglist->initMagic != SEGMENTSH_INITMAGICVAL ) {
396  XLALPrintError( "Passed unintialized LALSegList structure to %s\n", __func__ );
398  }
399 
400  /* Check that segment end time is equal to or later than start time */
401  if ( XLALGPSCmp(&(seg->start),&(seg->end)) > 0 ) {
402  XLALPrintError( "Invalid segment passed to %s (%d.%09d > %d.%09d)\n",
403  __func__, seg->start.gpsSeconds, seg->start.gpsNanoSeconds,
404  seg->end.gpsSeconds, seg->end.gpsNanoSeconds );
406  }
407 
408  /* See whether we need to extend (or create) the segment array */
409  if ( seglist->length == seglist->arraySize ) {
410 
411  if ( seglist->arraySize < 6*SEGMENTSH_ALLOCBLOCK ) {
412  newSize = seglist->arraySize + SEGMENTSH_ALLOCBLOCK;
413  } else {
414  newSize = (seglist->arraySize * 6) / 5 ;
415  }
416 
417  if ( seglist->arraySize ) {
418  /* Extend the array */
419  segptr = (LALSeg *) LALRealloc( seglist->segs, newSize*sizeof(LALSeg) );
420  } else {
421  /* Allocate the first block of memory for the array */
422  segptr = (LALSeg *) LALMalloc( newSize*sizeof(LALSeg) );
423  }
424 
425  /* Check for a memory allocation failure */
426  if ( ! segptr ) {
428  }
429 
430  /* If we get here, then the memory allocation succeeded */
431  seglist->segs = segptr;
432  seglist->arraySize = newSize;
433 
434  }
435 
436  /* Copy the segment information into the array */
437  seglist->segs[seglist->length] = *seg ;
438  seglist->length++;
439 
440  /* See whether more decimal places are needed to represent these times than
441  were needed for segments already in the list. Work with 0, 3, 6, or 9
442  decimal places. */
443  ns1 = seg->start.gpsNanoSeconds;
444  ns2 = seg->end.gpsNanoSeconds;
445  if ( seglist->dplaces < 9 ) {
446  if ( ns1 % 1000 || ns2 % 1000 ) {
447  /* 6 decimal places are not enough */
448  seglist->dplaces = 9;
449  } else if ( seglist->dplaces < 6 ) {
450  if ( ns1 % 1000000 || ns2 % 1000000 ) {
451  /* 3 decimal places are not enough */
452  seglist->dplaces = 6;
453  } else if ( seglist->dplaces < 3 ) {
454  if ( ns1 || ns2 ) {
455  /* At least one of the times does have a decimal part */
456  seglist->dplaces = 3;
457  }
458  }
459  }
460  }
461 
462  /* See whether the "disjoint" and/or "sorted" properties still hold */
463  if ( seglist->length > 1 ) {
464  prev = seglist->segs + seglist->length - 2 ;
465 
466  if ( seglist->disjoint && XLALGPSCmp(&(prev->end),&(seg->start)) > 0 ) {
467  /* Segments overlap, so segment list is no longer disjoint */
468  seglist->disjoint = 0;
469  }
470 
471  if ( seglist->sorted && XLALSegCmp(prev,seg) > 0 ) {
472  /* Segments are no longer in ascending order */
473  seglist->sorted = 0;
474  }
475 
476  }
477 
478  /* Return with success status code */
479  return XLAL_SUCCESS;
480 }
481 
482 
483 /*---------------------------------------------------------------------------*/
484 
485 /**
486  * This function sorts the segments in a segment list
487  * into forward time order. If the list is already sorted, then this function
488  * returns promptly.
489  */
490 int
492 {
493  /* Make sure a non-null pointer was passed for the segment list */
494  if ( ! seglist ) {
495  XLALPrintError( "NULL LALSegList pointer passed to %s\n", __func__ );
497  }
498 
499  /* Make sure the segment list has been properly initialized */
500  if ( seglist->initMagic != SEGMENTSH_INITMAGICVAL ) {
501  XLALPrintError( "Passed unintialized LALSegList structure to %s\n", __func__ );
503  }
504 
505  /* If segment list is known to be sorted already, just return */
506  if ( seglist->sorted ) {
507  return XLAL_SUCCESS;
508  }
509 
510  /* Sort the segment list in place */
511  /* This function call produces a compiler warning, because XLALSegCmp takes
512  pointers to LALSeg objects, whereas qsort expects the comparison function
513  passed to it to take void pointers as arguments. Oh well. */
514  qsort( (void *) seglist->segs, seglist->length, sizeof(LALSeg), XLALSegCmp );
515 
516  /* Now we can set the "sorted" flag */
517  seglist->sorted = 1;
518 
519  /* Reset the 'lastFound' value, since the array has changed */
520  seglist->lastFound = NULL;
521 
522  /* Return with success status code */
523  return XLAL_SUCCESS;
524 }
525 
526 
527 /*---------------------------------------------------------------------------*/
528 
529 /**
530  * The function XLALSegListCoalesce() first sorts the segments in a
531  * segment list (if not already sorted) and then joins together segments which
532  * overlap or touch (i.e. share endpoints).
533  * The result is a segment list which is sorted and is guaranteed
534  * to not have any overlapping segments; thus it is ``disjoint''.
535  * (Note, however, that a disjoint segment list is not necessarily coalesced,
536  * since segments which touch at an endpoint are considered disjoint but will
537  * be joined by XLALSegListCoalesce().)
538  * If the list has the ``disjoint'' property to begin with,
539  * then this function returns promptly. Each segment in the output list is
540  * assigned the \c id value taken from the first segment in the input list
541  * (after it has been sorted) among those which were joined to make it.
542  */
543 int
545 {
546  LALSeg *rp, *wp; /* Read and write pointers for stepping through array */
547  size_t newLength;
548  LALSeg *segptr;
549 
550  /* Make sure a non-null pointer was passed for the segment list */
551  if ( ! seglist ) {
552  XLALPrintError( "NULL LALSegList pointer passed to %s\n", __func__ );
554  }
555 
556  /* Make sure the segment list has been properly initialized */
557  if ( seglist->initMagic != SEGMENTSH_INITMAGICVAL ) {
558  XLALPrintError( "Passed unintialized LALSegList structure to %s\n", __func__ );
560  }
561 
562  /* If segment list is empty or has only one segment, just return */
563  if ( seglist->length <= 1 ) {
564  return XLAL_SUCCESS;
565  }
566 
567  /* Make sure the segment list is sorted */
568  XLALSegListSort( seglist );
569 
570  /* Step through the segment list with read and write pointers */
571  wp = seglist->segs;
572  newLength = 1;
573  for ( rp = seglist->segs+1; rp < seglist->segs+seglist->length; rp++ ) {
574  if ( XLALGPSCmp(&(wp->end),&(rp->start)) < 0 ) {
575  /* Segment at read pointer does NOT overlap segment at write pointer */
576  wp++;
577  *wp = *rp;
578  newLength++;
579  } else {
580  /* Segment at read pointer touches or overlaps segment at write pointer*/
581  /* So extend the segment at the write pointer if necessary */
582  if ( XLALGPSCmp(&(wp->end),&(rp->end)) < 0 ) {
583  wp->end = rp->end;
584  }
585  }
586  }
587 
588  /* Update the array length */
589  seglist->length = (UINT4) newLength;
590 
591  /* Reduce the memory allocation for the array, if possible */
592  if ( newLength < seglist->arraySize ) {
593  /* Contract the array */
594  segptr = (LALSeg *) LALRealloc( seglist->segs, newLength*sizeof(LALSeg) );
595 
596  /* Check for a memory allocation failure */
597  if ( ! segptr ) {
599  }
600 
601  /* If we get here, then the memory reallocation succeeded */
602  seglist->segs = segptr;
603  seglist->arraySize = newLength;
604  }
605 
606  /* Now we can set the "disjoint" flag */
607  seglist->disjoint = 1;
608 
609  /* Reset the 'lastFound' value, since the array has changed */
610  seglist->lastFound = NULL;
611 
612  /* Return with success status code */
613  return XLAL_SUCCESS;
614 }
615 
616 
617 /*---------------------------------------------------------------------------*/
618 
619 /**
620  * The function XLALSegListRange() returns the start and end GPS times of the
621  * segment list. These may \e not be the first and last GPS times in the segment
622  * list, for example if the segment list is not sorted.
623  */
624 int
626 
627  // Check input
628  XLAL_CHECK(seglist != NULL, XLAL_EFAULT);
629  XLAL_CHECK(seglist->segs != NULL, XLAL_EINVAL);
631  XLAL_CHECK(seglist->length > 0, XLAL_EINVAL);
632  XLAL_CHECK(start != NULL, XLAL_EFAULT);
633  XLAL_CHECK(end != NULL, XLAL_EFAULT);
634 
635  // Set 'start' and 'end' to first and list GPS times in the segment list
636  *start = seglist->segs[0].start;
637  *end = seglist->segs[seglist->length-1].end;
638 
639  // If segment list is sorted, we're done
640  if (seglist->sorted) {
641  return XLAL_SUCCESS;
642  }
643 
644  // Find 'start' and 'end' to lowest/highest values of segments 'start' and 'end'
645  for (size_t i = 0; i < seglist->length; ++i) {
646  if (XLALGPSCmp(&seglist->segs[i].start, start) < 0) {
647  *start = seglist->segs[i].start;
648  }
649  if (XLALGPSCmp(&seglist->segs[i].end, end) > 0) {
650  *end = seglist->segs[i].end;
651  }
652  }
653 
654  return XLAL_SUCCESS;
655 
656 }
657 
658 
659 /*---------------------------------------------------------------------------*/
660 
661 /**
662  * The function XLALSegListSearch() determines which segment in the
663  * list, if any, contains the GPS time passed to this function. It returns
664  * a pointer to a segment containing the time, if there is one, otherwise
665  * it returns NULL. If more than one segment
666  * in the list contains the time, then this function returns a pointer
667  * to \e one of the segments which contains it, not necessarily the first
668  * such segment in the list. (This is not an issue if the list is ``disjoint'',
669  * which guarantees that it has no overlapping segments.)
670  * The following code shows how the XLALSegListSearch() function
671  * might be used:
672  * \code
673  * LALSegList mylist;
674  * LIGOTimeGPS tgps, startgps;
675  * LALSeg *segp;
676  * ...
677  * /\* (Fill the segment list 'mylist' with segments here) *\/
678  * /\* (Set the gps time, 'tgps', to search for) *\/
679  * ...
680  * segp = XLALSegListSearch( &mylist, &tgps );
681  * if ( segp ) {
682  * startgps = segp->start;
683  * printf( "That time is within a segment which starts at GPS time %d.%09d\n",
684  * startgps.gpsSecconds, startgps.gpsNanoSeconds );
685  * } else {
686  * printf( "That time is not within any segment in the list\n" );
687  * }
688  * \endcode
689  * The search algorithm used by the XLALSegListSearch() function
690  * depends on whether the segment list is ``sorted'' and/or ``disjoint''. If
691  * the segment list has both of these properties, then the function can use
692  * a binary search to locate the segment containing the time, or to determine
693  * that there is no such segment. (Therefore, it is a good idea to pass
694  * a segment list to XLALSegListCoalesce() before using it with
695  * XLALSegListSearch(), unless segment list ordering or distinct
696  * segments which touch/overlap are meaningful for what you are doing,
697  * which is sometimes the case.) Otherwise, it must use a linear search,
698  * although a ``sorted'' list can still be searched slightly more efficiently than
699  * an un-sorted list. In all cases, XLALSegListSearch() first checks
700  * whether the segment found by the last successful search contains the
701  * specified time, and returns that promptly if so.
702  *
703  * \return a pointer to a segment in the list which
704  * contains the time being searched for, or NULL if there is no such segment.
705  * If more than one segment in the list contains the time, then this function
706  * returns a pointer to \e one of the segments which contains it, not
707  * necessarily the first such segment in the list. (This is not an issue if
708  * the list is ``disjoint'', which guarantees that it has no overlapping
709  * segments.) If no segment in the list contains the time, then this function
710  * returns NULL; however, this is not really an error, use \c xlalErrno
711  * to differentiate between failure and non-failure.
712  */
713 LALSeg *
714 XLALSegListSearch( LALSegList *seglist, const LIGOTimeGPS *gps )
715 {
716  int cmp;
717  LALSeg *bstart = NULL;
718  size_t bcount = 0;
719  LALSeg *l1start=NULL, *l1end=NULL, *l2start=NULL, *l2end=NULL;
720  LALSeg *segp;
721 
722  /* Make sure a non-null pointer was passed for the segment list */
723  if ( ! seglist ) {
724  XLALPrintError( "NULL LALSegList pointer passed to %s\n", __func__ );
726  }
727 
728  /* Make sure a non-null pointer was passed for the GPS time */
729  if ( ! gps ) {
730  XLALPrintError( "NULL LIGOTimeGPS pointer passed to %s\n", __func__ );
732  }
733 
734  /* Make sure the segment list has been properly initialized */
735  if ( seglist->initMagic != SEGMENTSH_INITMAGICVAL ) {
736  XLALPrintError( "Passed unintialized LALSegList structure to %s\n", __func__ );
738  }
739 
740  /* If the segment list is empty, simply return */
741  if ( seglist->length == 0 ) {
742  return NULL;
743  }
744 
745  /* Do one or two quick checks based on the last segment found in a search,
746  which might match this time too. If we're not so lucky, then plan out
747  the search strategy, depending on the segment list's 'disjoint' property.
748  If the segment list is disjoint, then we will do a binary search;
749  otherwise, we will do a linear search, possibly wrapping around from the
750  end of the list to the beginning, in which case we set two pairs of
751  search limits. */
752 
753  if ( seglist->disjoint ) {
754 
755  if ( ! seglist->lastFound ) {
756 
757  /* Do a binary search on the whole list */
758  bstart = seglist->segs;
759  bcount = seglist->length;
760 
761  } else {
762 
763  /* Check whether the time lies within the last segment found */
764  cmp = XLALGPSInSeg( gps, seglist->lastFound );
765 
766  if ( cmp == 0 ) {
767  return seglist->lastFound;
768 
769  } else if ( cmp < 0 ) {
770  /* Do a binary search from the beginning of the list up to here */
771  bstart = seglist->segs;
772  bcount = ( seglist->lastFound - seglist->segs );
773  /* If there are no earlier segments, just return */
774  if ( bcount == 0 ) {
775  return NULL;
776  }
777 
778  } else {
779  /* The time is later than the last segment found */
780 
781  /* If there are no later segments, just return */
782  if ( seglist->lastFound == seglist->segs + seglist->length - 1 ) {
783  return NULL;
784  }
785 
786  /* Check whether the time lies within the next later segment */
787  cmp = XLALGPSInSeg( gps, seglist->lastFound+1 );
788  if ( cmp == 0 ) {
789  /* We found a match, so update lastFound and return */
790  seglist->lastFound++;
791  return seglist->lastFound;
792  } else if ( cmp < 0 ) {
793  /* The time lies between the two segments */
794  return NULL;
795  } else {
796  /* The time is later than this segment, so search to end of list */
797  bstart = seglist->lastFound+2;
798  bcount = ( seglist->segs - seglist->lastFound
799  + seglist->length-2 );
800  /* If there are no later segments, just return */
801  if ( bcount == 0 ) {
802  return NULL;
803  }
804  }
805 
806  }
807 
808  }
809 
810  } else {
811 
812  /* The search limits are chosen the same for sorted vs. unsorted lists,
813  but the actual search will behave differently for given limits */
814 
815  if ( ! seglist->lastFound ) {
816 
817  /* Do a single linear search on the whole list */
818  l1start = seglist->segs;
819  l1end = seglist->segs + seglist->length;
820  l2start = l2end = NULL;
821 
822  } else {
823 
824  /* Check whether the time lies within the last segment found */
825  cmp = XLALGPSInSeg( gps, seglist->lastFound );
826 
827  if ( cmp == 0 ) {
828  return seglist->lastFound;
829 
830  } else if ( cmp < 0 ) {
831  /* Do a linear search, starting from the beginning of the list.
832  If the list is sorted, then we already know that we only have to
833  search up to the lastFound segment, but the actual search is
834  guaranteed to bail out at that point, so we can go ahead and set
835  the search parameters as if the whole list would be searched. */
836  l1start = seglist->segs;
837  l1end = seglist->segs + seglist->length;
838  l2start = l2end = NULL;
839 
840  } else {
841  /* First search from here to the end of the list, then wrap around
842  and search from the beginning of the list up to here */
843  l1start = seglist->lastFound + 1;
844  l1end = seglist->segs + seglist->length;
845  l2start = seglist->segs;
846  l2end = seglist->lastFound;
847 
848  }
849 
850  }
851 
852  }
853 
854  /* If we get here, then we have to do one or more searches */
855 
856  if ( seglist->disjoint ) {
857 
858  /* Do a binary search */
859  /* This function call produces a compiler warning, because XLALGPSInSeg
860  takes a pointer to a LIGOTimeGPS and a pointer to a LALSeg, whereas
861  bsearch expects the comparison function passed to it to take void
862  pointers as arguments. Oh well. */
863  segp = bsearch( (const void *) gps, (const void *) bstart,
864  bcount, sizeof(LALSeg), XLALGPSInSeg );
865  /* If we found a match, update lastFound and return the pointer.
866  Otherwise, return NULL. */
867  if ( segp ) {
868  seglist->lastFound = segp;
869  return segp;
870  } else {
871  return NULL;
872  }
873 
874  } else if ( seglist->sorted ) {
875 
876  /* Do a linear search, but bail out if we reach a segment whose start time
877  is later than the target time */
878  for ( segp=l1start; segp<l1end; segp++ ) {
879  cmp = XLALGPSInSeg( gps, segp );
880  if ( cmp == 0 ) {
881  seglist->lastFound = segp;
882  return segp;
883  } else if ( cmp < 0 ) {
884  /* This segment is beyond the target time, so we can bail out */
885  break;
886  }
887  }
888  /* Set the lastFound pointer to the last segment which is not beyond the
889  target time, or the last segment in the list */
890  seglist->lastFound = segp - 1;
891 
892  /* If necessary, do a second linear search, starting from the beginning
893  of the list and going up to lastFound. In this case, we know that the
894  comparison value will never be negative. */
895  for ( segp=l2start; segp<l2end; segp++ ) {
896  if ( XLALGPSInSeg(gps,segp) == 0 ) {
897  seglist->lastFound = segp;
898  return segp;
899  }
900  }
901 
902  /* If we get here, then we didn't find a match.
903  Continue to the end of the function. */
904 
905  } else {
906 
907  /* Do a linear search, looking for a match */
908  for ( segp=l1start; segp<l1end; segp++ ) {
909  if ( XLALGPSInSeg(gps,segp) == 0 ) {
910  seglist->lastFound = segp;
911  return segp;
912  }
913  }
914 
915  /* If necessary, do a second linear search, starting from the beginning
916  of the list and going up to lastFound. */
917  for ( segp=l2start; segp<l2end; segp++ ) {
918  if ( XLALGPSInSeg(gps,segp) == 0 ) {
919  seglist->lastFound = segp;
920  return segp;
921  }
922  }
923 
924  /* If we get here, then we didn't find a match.
925  Continue to the end of the function. */
926 
927  }
928 
929  /* If we get here, then we didn't find a match, so return NULL */
930  return NULL;
931 }
932 
933 
934 
935 /*---------------------------------------------------------------------------*/
936 /**
937  * UNDOCUMENTED
938  */
939 int
940 XLALSegListShift( LALSegList *seglist, const LIGOTimeGPS *shift )
941 {
942  unsigned i;
943 
944  /* Make sure a non-null pointer was passed for the segment list */
945  if ( ! seglist ) {
946  XLALPrintError( "NULL LALSegList pointer passed to %s\n", __func__ );
948  }
949 
950  /* Make sure a non-null pointer was passed for the GPS time */
951  if ( ! shift ) {
952  XLALPrintError( "NULL LIGOTimeGPS pointer passed to %s\n", __func__ );
954  }
955 
956  /* Make sure the segment list has been properly initialized */
957  if ( seglist->initMagic != SEGMENTSH_INITMAGICVAL ) {
958  XLALPrintError( "Passed unintialized LALSegList structure to %s\n", __func__ );
960  }
961 
962  /* time shift each segment in this list */
963  for (i=0; i<seglist->length; i++) {
964  XLALGPSAddGPS( &seglist->segs[i].start, shift);
965  XLALGPSAddGPS( &seglist->segs[i].end, shift);
966  }
967 
968  /* done */
969  return 0;
970 }
971 
972 
973 /**
974  * UNDOCUMENTED
975  */
976 int
977 XLALSegListKeep( LALSegList *seglist, const LIGOTimeGPS *start, const LIGOTimeGPS *end )
978 {
979  LALSegList workspace;
980  unsigned i;
981  INT8 startNS, endNS;
982 
983  /* Make sure a non-null pointer was passed for the segment list */
984  if ( ! seglist ) {
985  XLALPrintError( "%s(): NULL LALSegList\n", __func__ );
987  }
988 
989  /* Make sure a non-null pointer was passed for the GPS time */
990  if ( !start || !end ) {
991  XLALPrintError( "%s(): NULL boundaries\n", __func__ );
993  }
994 
995  /* Make sure the segment list has been properly initialized */
996  if ( seglist->initMagic != SEGMENTSH_INITMAGICVAL ) {
997  XLALPrintError( "%s(): unintialized LALSegList\n", __func__ );
999  }
1000 
1001  /* init the temporary list */
1002  XLALSegListInit( &workspace );
1003 
1004  /* convert the start and stop times to nanoseconds */
1005  startNS = XLALGPSToINT8NS( start );
1006  endNS = XLALGPSToINT8NS( end );
1007  if ( startNS >= endNS ) {
1008  XLALPrintError( "%s(): zero-length or improper interval\n", __func__ );
1010  }
1011 
1012  /* loop over all segments in this list */
1013  for (i=0; i<seglist->length; i++) {
1014  LALSeg newSeg;
1015  INT8 segStart = XLALGPSToINT8NS( &seglist->segs[i].start );
1016  INT8 segEnd = XLALGPSToINT8NS( &seglist->segs[i].end );
1017 
1018  /* if segment lies entirely outside interval, discard */
1019  if ( segEnd <= startNS || segStart >= endNS )
1020  continue;
1021 
1022  /* intersect */
1023  if ( segStart < startNS )
1024  segStart = startNS;
1025  if ( segEnd > endNS )
1026  segEnd = endNS;
1027 
1028  /* store in new list */
1029  XLALINT8NSToGPS( &newSeg.start, segStart );
1030  XLALINT8NSToGPS( &newSeg.end, segEnd );
1031  newSeg.id = seglist->segs[i].id;
1032  XLALSegListAppend( &workspace, &newSeg );
1033  }
1034 
1035  /* clear the old list */
1036  XLALSegListClear( seglist );
1037 
1038  /* put the new segments into the old lsit */
1039  for ( i = 0; i < workspace.length; i++ )
1040  XLALSegListAppend( seglist, &workspace.segs[i] );
1041 
1042  /* clear the work space */
1043  XLALSegListClear( &workspace );
1044 
1045  /* done */
1046  return 0;
1047 }
1048 
1049 /**
1050  * Simple method to check whether a LALSegList is in an initialized state.
1051  *
1052  * Avoid the user having to deal with LALSegList internal 'magic'.
1053  */
1054 int
1056 {
1057  XLAL_CHECK ( seglist != NULL, XLAL_EINVAL, "Invalid NULL input 'seglist'\n");
1058 
1059  return (seglist->initMagic == SEGMENTSH_INITMAGICVAL);
1060 
1061 } /* XLALSegListIsInitialized() */
1062 
1063 /**
1064  * (Re-)Initialize a segment list with Nseg 'simple' segments of length 'Tseg',
1065  * starting at t0 = startTime, ie
1066  * { [t0, t0+Tseg), [t0+Tseg, t0+2*Tseg), ... [t0+(N-1)*Tseg, t0+N*Tseg) }
1067  *
1068  * Note: accepts un-initialized segments list, as well as existing segment-lists.
1069  * The latter will be properly cleared before re-use.
1070  *
1071  * The 'Id' field of segment k is set to 'k'
1072  */
1073 int
1075 {
1076  XLAL_CHECK ( seglist != NULL, XLAL_EINVAL, "Invalid NULL input 'seglist'\n" );
1077  XLAL_CHECK ( Tseg > 0, XLAL_EDOM, "Invalid non-positive input 'Tseg=%g'\n", Tseg );
1078 
1079  if ( XLALSegListIsInitialized ( seglist ) )
1080  XLALSegListClear ( seglist );
1081  else
1082  XLALSegListInit ( seglist );
1083 
1084  for ( UINT4 k = 0; k < Nseg; k ++ )
1085  {
1086  LALSeg seg_k;
1087 
1088  LIGOTimeGPS start_k = startTime;
1089  XLALGPSAdd( &start_k, k * Tseg ); // t0_k = t0 + k * Tseg
1090  LIGOTimeGPS end_k = startTime;
1091  XLALGPSAdd( &end_k, (k+1) * Tseg ); // t1_k = t0 + (k+1) * Tseg
1092 
1093  XLAL_CHECK ( XLALSegSet ( &seg_k, &start_k, &end_k, k ) == XLAL_SUCCESS, XLAL_EFUNC );
1094 
1095  XLAL_CHECK ( XLALSegListAppend ( seglist, &seg_k ) == XLAL_SUCCESS, XLAL_EFUNC );
1096 
1097  } // for k < Nseg
1098 
1099  return XLAL_SUCCESS;
1100 
1101 } /* XLALSegListInitSimpleSegments() */
1102 
1103 
1104 /**
1105  * Output an (octave) formatting of 'seglist' as a string
1106  */
1107 char *
1108 XLALSegList2String ( const LALSegList *seglist )
1109 {
1110  XLAL_CHECK_NULL ( seglist != NULL, XLAL_EINVAL, "Invalid NULL input 'seglist'\n" );
1111  XLAL_CHECK_NULL ( XLALSegListIsInitialized ( seglist ), XLAL_EINVAL, "Got invalid un-initialized seglist\n" );
1112 
1113  char *ret = NULL;
1114  XLAL_CHECK_NULL ( (ret = XLALStringAppend ( ret, "[ " )) != NULL, XLAL_ENOMEM, "Failed to ret=XLALStringAppend()\n" );
1115 
1116  char segfmt[64];
1117  sprintf ( segfmt, "%%.%df, %%.%df, %%d; ", seglist->dplaces, seglist->dplaces ); // seglist tells us output precision for GPS times to use
1118 
1119  UINT4 Nseg = seglist->length;
1120  for ( UINT4 k = 0; k < Nseg; k ++ )
1121  {
1122  char seg_buf[512];
1123  REAL8 t0_k = XLALGPSGetREAL8 ( &(seglist->segs[k].start) );
1124  REAL8 t1_k = XLALGPSGetREAL8 ( &(seglist->segs[k].end) );
1125  sprintf ( seg_buf, segfmt, t0_k, t1_k, seglist->segs[k].id );
1126 
1127  XLAL_CHECK_NULL ( (ret = XLALStringAppend ( ret, seg_buf ) ) != NULL, XLAL_ENOMEM, "Failed to ret=XLALStringAppend() for segment %d/%d\n", k+1, Nseg );
1128 
1129  } // for k < Nseg
1130 
1131  XLAL_CHECK_NULL ( (ret = XLALStringAppend ( ret, "]" ) ) != NULL, XLAL_ENOMEM, "Failed to ret=XLALStringAppend()" );
1132 
1133  return ret;
1134 
1135 } /* XLALSegList2String() */
1136 
1137 /*---------------------------------------------------------------------------*/
1138 /**
1139  * Get a copy of the segment at indx in the internal array. If the segment is
1140  * beyond the bounds of the array, return NULL.
1141  */
1142 LALSeg *
1144 {
1145  if( indx >= seglist->length ){
1146  return NULL;
1147  }
1148  LALSeg* tmp = LALMalloc(sizeof(LALSeg));
1149  memcpy(tmp, &seglist->segs[indx], sizeof(LALSeg));
1150  return tmp;
1151 
1152 } /* XLALSegListGet() */
#define LALRealloc(p, n)
Definition: LALMalloc.h:95
#define LALMalloc(n)
Definition: LALMalloc.h:93
#define LALFree(p)
Definition: LALMalloc.h:96
static int cmp(REAL4Sequence *a, REAL4Sequence *b)
Definition: SequenceTest.c:62
int XLALPrintError(const char *fmt,...)
Definition: XLALError.c:68
double REAL8
Double precision real floating-point number (8 bytes).
int64_t INT8
Eight-byte signed integer; on some platforms this is equivalent to long int instead.
uint32_t UINT4
Four-byte unsigned integer.
int32_t INT4
Four-byte signed integer.
#define XLALMalloc(n)
Definition: LALMalloc.h:44
#define XLALFree(p)
Definition: LALMalloc.h:47
char * XLALStringAppend(char *s, const char *append)
Like strcat but dynamically reallocates string with LALRealloc.
Definition: LALString.c:50
LALSeg * XLALSegCreate(const LIGOTimeGPS *start, const LIGOTimeGPS *end, const INT4 id)
This function is similar to XLALSegSet() except that it allocates memory for a new segment structure ...
Definition: Segments.c:131
int XLALSegListInit(LALSegList *seglist)
This function must be called to initialize a segment list structure before that structure can be used...
Definition: Segments.c:255
int XLALSegListClear(LALSegList *seglist)
This function must be called when you are done with a segment list, in order to free memory that was ...
Definition: Segments.c:303
int XLALSegCmp(const void *pseg0, const void *pseg1)
This is designed to be usable as a comparison function for qsort() and therefore returns a negative v...
Definition: Segments.c:213
#define SEGMENTSH_INITMAGICVAL
Distinctive value set in the 'initMagic' field to provide a check that the structure was properly ini...
Definition: Segments.h:150
int XLALSegListInitSimpleSegments(LALSegList *seglist, LIGOTimeGPS startTime, UINT4 Nseg, REAL8 Tseg)
(Re-)Initialize a segment list with Nseg 'simple' segments of length 'Tseg', starting at t0 = startTi...
Definition: Segments.c:1074
int XLALSegListCoalesce(LALSegList *seglist)
The function XLALSegListCoalesce() first sorts the segments in a segment list (if not already sorted)...
Definition: Segments.c:544
int XLALSegListSort(LALSegList *seglist)
This function sorts the segments in a segment list into forward time order.
Definition: Segments.c:491
int XLALSegListFree(LALSegList *seglist)
This function frees a segment list created with XLALSegListCreate().
Definition: Segments.c:348
int XLALSegListShift(LALSegList *seglist, const LIGOTimeGPS *shift)
UNDOCUMENTED.
Definition: Segments.c:940
char * XLALSegList2String(const LALSegList *seglist)
Output an (octave) formatting of 'seglist' as a string.
Definition: Segments.c:1108
int XLALSegListIsInitialized(const LALSegList *seglist)
Simple method to check whether a LALSegList is in an initialized state.
Definition: Segments.c:1055
int XLALSegListKeep(LALSegList *seglist, const LIGOTimeGPS *start, const LIGOTimeGPS *end)
UNDOCUMENTED.
Definition: Segments.c:977
int XLALSegListAppend(LALSegList *seglist, const LALSeg *seg)
This function appends a segment to a segment list.
Definition: Segments.c:375
LALSegList * XLALSegListCreate(void)
This function allocates memory for a new segment list structure, initializes the segment list,...
Definition: Segments.c:239
int XLALSegSet(LALSeg *seg, const LIGOTimeGPS *start, const LIGOTimeGPS *end, const INT4 id)
This function sets the start time, the end time, and the id of a segment.
Definition: Segments.c:87
LALSeg * XLALSegListGet(LALSegList *seglist, UINT4 indx)
Get a copy of the segment at indx in the internal array.
Definition: Segments.c:1143
LALSeg * XLALSegListSearch(LALSegList *seglist, const LIGOTimeGPS *gps)
The function XLALSegListSearch() determines which segment in the list, if any, contains the GPS time ...
Definition: Segments.c:714
int XLALGPSInSeg(const void *pgps, const void *pseg)
This is designed to be usable as a comparison function for bsearch() and therefore returns a negative...
Definition: Segments.c:182
#define SEGMENTSH_ALLOCBLOCK
Initial number of LALSeg spaces to allocate in memory at one time; this is intended to reduce the num...
Definition: Segments.h:141
int XLALSegListRange(const LALSegList *seglist, LIGOTimeGPS *start, LIGOTimeGPS *end)
The function XLALSegListRange() returns the start and end GPS times of the segment list.
Definition: Segments.c:625
#define XLAL_ERROR_NULL(...)
Macro to invoke a failure from a XLAL routine returning a pointer.
Definition: XLALError.h:713
#define XLAL_ERROR(...)
Macro to invoke a failure from a XLAL routine returning an integer.
Definition: XLALError.h:700
#define XLAL_CHECK(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns an integ...
Definition: XLALError.h:810
#define XLAL_CHECK_NULL(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns a pointe...
Definition: XLALError.h:825
@ XLAL_ENOMEM
Memory allocation error.
Definition: XLALError.h:407
@ XLAL_SUCCESS
Success return value (not an error number)
Definition: XLALError.h:401
@ XLAL_EFAULT
Invalid pointer.
Definition: XLALError.h:408
@ XLAL_EFUNC
Internal function call failed bit: "or" this with existing error number.
Definition: XLALError.h:462
@ XLAL_EDOM
Input domain error.
Definition: XLALError.h:410
@ XLAL_EINVAL
Invalid argument.
Definition: XLALError.h:409
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
Adds a double to a GPS time.
Definition: XLALTime.c:131
LIGOTimeGPS * XLALGPSAddGPS(LIGOTimeGPS *epoch, const LIGOTimeGPS *dt)
Adds two GPS times.
Definition: XLALTime.c:117
int XLALGPSCmp(const LIGOTimeGPS *t0, const LIGOTimeGPS *t1)
Compares two GPS times.
Definition: XLALTime.c:174
REAL8 XLALGPSGetREAL8(const LIGOTimeGPS *epoch)
Returns the GPS time as a REAL8.
Definition: XLALTime.c:91
LIGOTimeGPS * XLALINT8NSToGPS(LIGOTimeGPS *epoch, INT8 ns)
Converts nano seconds stored as an INT8 to GPS time.
Definition: XLALTime.c:46
INT8 XLALGPSToINT8NS(const LIGOTimeGPS *epoch)
Converts GPS time to nano seconds stored as an INT8.
Definition: XLALTime.c:36
Struct holding a single segment.
Definition: Segments.h:162
LIGOTimeGPS end
Ending time of the segment.
Definition: Segments.h:164
INT4 id
Identifier (segment ID, array index, etc.) for user.
Definition: Segments.h:165
LIGOTimeGPS start
Beginning time of the segment.
Definition: Segments.h:163
Struct holding a segment list.
Definition: Segments.h:175
LALSeg * lastFound
Internal record of last segment found by a search.
Definition: Segments.h:186
UINT4 length
Number of segments in this segment list.
Definition: Segments.h:181
LALSeg * segs
Pointer to array of segments (LALSeg structures)
Definition: Segments.h:179
UINT4 sorted
Flag to indicate whether segment list is sorted.
Definition: Segments.h:183
UINT4 initMagic
Internal value to help ensure list was initialized.
Definition: Segments.h:185
UINT4 dplaces
Decimal places (0,3,6,9) to format GPS times.
Definition: Segments.h:182
size_t arraySize
Size of array for which memory is allocated.
Definition: Segments.h:180
UINT4 disjoint
Flag to indicate whether segment list is disjoint.
Definition: Segments.h:184
Epoch relative to GPS epoch, see LIGOTimeGPS type for more details.
Definition: LALDatatypes.h:458
INT4 gpsSeconds
Seconds since 0h UTC 6 Jan 1980.
Definition: LALDatatypes.h:459
INT4 gpsNanoSeconds
Residual nanoseconds.
Definition: LALDatatypes.h:460