Loading [MathJax]/extensions/TeX/AMSsymbols.js
LAL 7.7.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 */
86int
87XLALSegSet( 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 */
130LALSeg *
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 */
181int
182XLALGPSInSeg( 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 */
212int
213XLALSegCmp( 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 */
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 */
254int
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 */
302int
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 */
347int
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 */
374int
375XLALSegListAppend( 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 */
490int
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 */
543int
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 */
624int
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 */
713LALSeg *
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 */
939int
940XLALSegListShift( 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 */
976int
977XLALSegListKeep( 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 */
1054int
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 */
1073int
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 */
1107char *
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 */
1142LALSeg *
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
char * XLALSegList2String(const LALSegList *seglist)
Output an (octave) formatting of 'seglist' as a string.
Definition: Segments.c:1108
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
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
#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
LALSegList * XLALSegListCreate(void)
This function allocates memory for a new segment list structure, initializes the segment list,...
Definition: Segments.c:239
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
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
LALSeg * XLALSegListGet(LALSegList *seglist, UINT4 indx)
Get a copy of the segment at indx in the internal array.
Definition: Segments.c:1143
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
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
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 * XLALGPSAddGPS(LIGOTimeGPS *epoch, const LIGOTimeGPS *dt)
Adds two GPS times.
Definition: XLALTime.c:117
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