XTime.cc

Knödlseder Jürgen, 10/11/2014 09:10 PM

Download (30.3 KB)

 
1
//----------------------------------------------------------------------
2
//
3
//
4
//  File:        XTime.C
5
//  Programmer:  Arnold Rots  -  USRA/SAO
6
//  Date:        7 June 1999
7
//  Subsystem:   XFF
8
//  Library:     ObsCat
9
//  Description: Code for XTime, XTimeRange, XTRList classes
10
//
11
//----------------------------------------------------------------------
12
//
13

    
14
#include <string.h>
15
#include <ctype.h>
16
#include <unistd.h>
17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <math.h>
20
#include <iostream>
21
#include "XTime.h"
22
#define TAIUTC "tai-utc.dat"
23

    
24
using namespace std;
25

    
26
int          XTime::NUMOBJECTS  =       0       ; // Number of instantiated XTime objects
27
const double XTime::MJD0        = 2400000.5     ; // JD - MJD
28
const long   XTime::MJD1972     =   41317       ; // MJD at 1972
29
const double XTime::DAY2SEC     =   86400.0     ; // Seconds per day
30
const double XTime::SEC2DAY     = 1.0 / DAY2SEC ; // Inverse seconds per day
31
const long   XTime::MJDREFint   =   50814       ; // MJD at 1998.0
32
const double XTime::MJDREFfr    =       0.0     ; // MJD at 1998.0
33
const double XTime::REFLEAPS    =      31.0     ;  // Leap seconds at default MJDREF (1998.0 TT)
34
const double XTime::TAI2TT      =      32.184   ; // TT - TAI
35
int    XTime::NUMLEAPSECS = 0 ;      // Leap seconds: 1972 through 2009
36
long   XTime::LEAPSMJD[]  = {41317, 41499, 41683, 42048, 42413, 42778, 43144, 43509, 43874,
37
                             44239, 44786, 45151, 45516, 46247, 47161, 47892, 48257, 48804,
38
                             49169, 49534, 50083, 50630, 51179, 53736, 54832, 56109} ;
39
double XTime::LEAPSECS[]  = {10, 11, 12,13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
40
                             26, 27, 28, 29, 30, 31, 32, 33, 34, 35} ;
41
time_t XTime::WALLCLOCK0      ;      // Wallclock time when leap seconds were read
42

    
43
static int daymonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} ;
44
static const char*  const month[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
45
         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} ;
46
 
47
//
48
//   ------------------------
49
// -- XTime::setleaps (void) --
50
//   ------------------------
51
//
52

    
53
// Description:
54
// Function to set leap second table
55
// If it was more than abs(dt) seconds since the
56
// leap seconds were read, the leap second table
57
// is refreshed; if dt > 0, only additional leap
58
// seconds are added; if dt < 0, all leap seconds
59
// are refreshed.  The default is dt=5000000 (about
60
// two months).
61
// This is the private method; for the public method
62
// use void XTime::setLeaps (double dt).
63

    
64
void XTime::setleaps (double dt)
65
{
66
  // Increment the object counter:
67
  NUMOBJECTS++ ;
68

    
69
  // Now the business of the leap seconds
70
  int refresh = 0 ;
71
  int all = dt < 0.0 ;
72
  if ( all ) dt = -dt ;
73
  // If they were set before, check whether they expired
74
  if ( NUMLEAPSECS ) {
75
    time_t wallclock1 ;
76
    time (&wallclock1) ;
77
    if ( difftime (wallclock1, WALLCLOCK0) > dt )
78
      refresh = 1 ;
79
  }
80
  else
81
    refresh = 1 ;
82

    
83
  // Try to read the leap seconds file
84
  if ( refresh ) {
85
    char *filepath ;
86
    FILE *FF = NULL ;
87
    char lsfile[256] ;
88
    int nums = 0 ;
89

    
90
    // Did the user provide his/her own?
91
    if ( filepath = getenv("TIMING_DIR") ) {
92
      sprintf (lsfile, "%s/%s", filepath, TAIUTC) ;
93
      FF = fopen (lsfile, "r") ;
94
    }
95

    
96
    // Otherwise, the standard file
97
    if ( FF == NULL )
98
      if ( filepath = getenv ("ASC_DATA") ) {
99
        sprintf (lsfile, "%s/%s", filepath, TAIUTC) ;
100
        FF = fopen (lsfile, "r") ;
101
      }
102

    
103
    // If the file is found, read it (only post 1972)
104
    if ( FF ) {
105
      long leapsMD ;
106
      double leapsecs ;
107
      int i ;
108
      while ( fscanf (FF, "%d %*s  1 =JD 24%ld.5 %*s %lg S + (MJD - %*lg) X %*lg %*s",
109
                      &i, &leapsMD, &leapsecs) == 3 ) {
110
        if ( i > 1970 ) {
111
          // Only overwrite existing values when forced to do so
112
          if ( all || ( nums >= NUMLEAPSECS ) ) {
113
            LEAPSMJD[nums] = leapsMD ;
114
            LEAPSECS[nums] = leapsecs ;
115
            nums++ ;
116
          }
117
        }
118
      }
119
      int error = ferror (FF) ;
120
      fclose (FF) ;
121
      // If we got fewer leap seconds than before, there must have been an error
122
      if ( ( nums >= NUMLEAPSECS ) && !error ) {
123
        time (&WALLCLOCK0) ;
124
        NUMLEAPSECS = nums ;
125
      }
126
    }
127

    
128
    // File could not be found; use the ones we know about when coding
129
    else if ( !NUMLEAPSECS ) {
130
      nums = 26 ;                 // Leap seconds: 1972.0 through 2013.0
131
      NUMLEAPSECS = nums ;
132
    }
133

    
134
  }
135
  return ;
136
}
137
 
138
//
139
//   -------------------------------------------------------------
140
// -- XTime::setmyleaps (double *leapval, long mjdi, double mjdf) --
141
//   -------------------------------------------------------------
142
//
143

    
144
// Description:
145
// Set the number of leap seconds for time mjdi+mjdf (TT) in leapval.
146
// mjdf should include timeZero, if applicable.
147
// Return 1 if mjdi+mjdf falls during a leap second; otherwise 0.
148
int XTime::setmyleaps (double *leapval, long mjdi, double mjdf)
149
{
150
  int i = NUMLEAPSECS - 1 ;
151
  int m = 0 ;
152
  double x = (double) mjdi + mjdf - TAI2TT * SEC2DAY ;
153
  long j = (long) x ;
154
  while ( ( j < LEAPSMJD[i] ) && i )
155
    i-- ;
156
  if ( ( (x - LEAPSECS[i]*SEC2DAY) < LEAPSMJD[i] ) && i ) {
157
    i-- ;
158
    if ( (LEAPSMJD[i+1] - x) <= SEC2DAY )
159
      m = 1 ;
160
  }
161
  *leapval = LEAPSECS[i] ;
162
  return m ;
163
}
164

    
165
//
166
//   ---------------------------------------------------------------------------
167
// -- XTime::set (double tt, TimeSys ts, TimeFormat tf, long mjdi, double mjdf) --
168
//   ---------------------------------------------------------------------------
169
//
170

    
171
// Description:
172
// General set function; tt sets time in SECS, MJD, or JD, as
173
// specified by ts and tf.  Allows for setting MJDREF
174
// (mjdi+mjdf); the default is 50814.0 (1998.0 TT).  The default
175
// for ts is MET, for tf SECS.  The defaults for mjdi and mjdf
176
// are 0 and 0.0.  Note that if a new MJDref is specified
177
// (non-zero), it will be assumed to be in Time System ts.
178
// I.e., set (x, UTC, SECS) is not the same as set
179
// (x, UTC, SECS, 50814)
180
// This method calls
181
// XTime::set (long, double, TimeSys, TimeFormat, long, double)
182
void XTime::set (double tt, TimeSys ts, TimeFormat tf,
183
                 long mjdi, double mjdf)
184
{
185
  double x ;
186
  long k ;
187

    
188
  k = (long) tt ;
189
  x = tt - k ;
190
  set (k, x, ts, tf, mjdi, mjdf) ;
191

    
192
  return ;
193
}
194

    
195
//
196
//   --------------------------------------------------------------------------------------
197
// -- XTime::set (long tti, double ttf, TimeSys ts, TimeFormat tf, long mjdi, double mjdf) --
198
//   --------------------------------------------------------------------------------------
199
//
200

    
201
// Description:
202
// Most general set function.  tti+ttf sets time in SECS, MJD, or
203
// JD, as specified by ts and tf.  Allows for setting MJDREF
204
// (mjdi+mjdf); the default is 50814.0 (1998.0 TT).
205
// The default for ts is TT, for tf MJD.  The defaults for mjdi
206
// and mjdf are 0 and 0.0.
207
// Note that if a new MJDref is specified (non-zero), it will be
208
// assumed to be in Time System ts.
209
// I.e., set (k, x, UTC, SECS) is not the same as
210
// set (k, x, UTC, SECS, 50814)
211
void XTime::set (long tti, double ttf, TimeSys ts, TimeFormat tf,
212
                 long mjdi, double mjdf)
213
{
214
  double total, x ;
215
  long j=0, k ;
216
  int i ;
217
  leapflag = 0 ;
218

    
219
  // First, set the MJDREF, if specified
220
  if ( mjdi > 1 ) {
221
    switch (ts) {
222
    case UTC: {
223
      XTime mt (mjdi, mjdf, ts) ;
224
      mt.mjd (&mjdi, &mjdf) ;
225
      break ;
226
    }
227
    case TAI:
228
      mjdf += TAI2TT * SEC2DAY ;
229
      if ( mjdf < 0.0 ) {
230
        mjdf++ ;
231
        mjdi-- ;
232
      }
233
      break ;
234
    }
235
    MJDrefint = mjdi ;
236
    MJDreffr = mjdf ;
237
    setmyleaps (&refLeaps, mjdi, mjdf) ;
238
  }
239

    
240
  // total contains the corrections wrt to TT in seconds
241
  total = 0.0 ;
242

    
243
  // Convert the format to MJD (TT); store in k and x
244
  switch (tf) {
245

    
246
    // First JD and MJD
247
  case JD:
248
    tti -= (long) MJD0 ;
249
    ttf -= 0.5 ;
250
  case MJD:
251
    k = tti ;
252
    x = ttf ;
253

    
254
    // Build up the corrections to TT, depending on ts
255
    switch (ts) {
256
    case UTC:
257
      i = NUMLEAPSECS - 1 ;
258
      while ( ( k < LEAPSMJD[i] ) && i ) {
259
        i-- ;
260
      }
261
      if ( ( i < NUMLEAPSECS-1 ) && ( k+1 == LEAPSMJD[i+1] ) &&
262
          ( (LEAPSMJD[i+1] - k + x + timeZero) < SEC2DAY  ) && i ) {
263
        i-- ;
264
        leapflag = 1 ;
265
      }
266
      total += LEAPSECS[i] ;
267
      myLeaps = LEAPSECS[i] ;
268
    case TAI:
269
      total += TAI2TT ;
270
    case TT:
271
    case MET:
272
      break ;
273
    default:                //  Error in ts; do nothing
274
      return ;
275
    }
276
    break ;
277

    
278
    // Seconds is slightly different since it's relative
279
    // Be careful about precision
280
  case SECS:
281
    k = (long) ((double) tti * SEC2DAY) ;
282
    x = (double) tti * SEC2DAY - k ;
283
    x += ttf * SEC2DAY + MJDreffr ;
284
    k += MJDrefint ;
285
    // Corrections are only needed for UTC, since the reference is now TT
286
    switch (ts) {
287
    case UTC:
288
      // First, subtract the leap seconds for the reference
289
      total -= refLeaps ;
290
      // Then add the leap seconds for the time itself
291
      i = NUMLEAPSECS - 1 ;
292
      j = (long) (k + x + timeZero) ;
293
      while ( ( j < LEAPSMJD[i] ) && i ) {
294
        i-- ;
295
      }
296
      if ( ( (k + x + timeZero - LEAPSMJD[i]) < SEC2DAY  ) && i ) {
297
        i-- ;
298
        leapflag = 1 ;
299
      }
300
      total += LEAPSECS[i] ;
301
      myLeaps = LEAPSECS[i] ;
302
    case TAI:
303
    case TT:
304
    case MET:
305
      break ;
306
    default:                //  Error in ts; do nothing
307
      return ;
308
    }
309
    break ;
310
  default:                //  Error in tf; do nothing
311
    return ;
312
  }
313

    
314
  // Now we are ready to set the time
315
  x += total * SEC2DAY ;
316
  j = (long) x ;
317
  MJDint = k + j ;
318
  MJDfr = x - j ;
319
  if ( MJDfr < 0.0 ) {
320
    MJDfr++ ;
321
    MJDint-- ;
322
  }
323
  // The leap seconds value and flag have already been set for UTC
324
  if ( ts != UTC )
325
    leapflag = setmyleaps (&myLeaps, MJDint, MJDfr+timeZero) ;
326

    
327
  return ;
328
}
329
 
330
//
331
//   ----------------------------------------------------------------------------
332
// -- XTime::set (char* date, TimeSys ts, TimeFormat tf, long mjdi, double mjdf) --
333
//   ----------------------------------------------------------------------------
334
//
335

    
336
// Description:
337
// General set function from a date string.
338
// Allows specification of DATE, CALDATE, or FITS formats.
339
// The defaults for ts, tf, and dec are UTC, DATE, and 0.
340
// This method calls
341
// XTime::set (long, double, TimeSys, TimeFormat, long, double)
342
void XTime::set (const char* date, TimeSys ts, TimeFormat tf,
343
                 long mjdi, double mjdf)
344
{
345
  long year=0, day=0, hour=0, minute=0 ;
346
  double second=0.0 ;
347
  int n ;
348
  int m = 0 ;
349
  char mn[4] ;
350

    
351
  switch (tf) {
352
  case DATE:
353
    n = sscanf (date, "%ld:%ld:%ld:%ld:%lg", &year, &day, &hour, &minute, &second) ;
354
    if ( n != 5 )
355
      return ;
356
    break ;
357
  case CALDATE:
358
    n = sscanf (date, "%ld%c%c%c%ld at %ld:%ld:%lg",
359
    &year, mn, mn+1, mn+2, &day, &hour, &minute, &second) ;
360
    if ( n != 8 )
361
      return ;
362
    if ( year%4 )
363
      daymonth[1] = 28 ;
364
    else
365
      daymonth[1] = 29 ;
366
    mn[0] = toupper(mn[0]) ;
367
    mn[1] = tolower(mn[1]) ;
368
    mn[2] = tolower(mn[2]) ;
369
    mn[3] = 0 ;
370
    while ( strcmp(mn, month[m]) ) {
371
      if ( m > 11 )
372
        return ;
373
      day += daymonth[m++] ;
374
    }
375
    break ;
376
  case FITS: {
377
    n = sscanf (date, "%ld-%d-%ldT%ld:%ld:%lg",
378
                &year, &m, &day, &hour, &minute, &second) ;
379
    if ( ( n != 6 ) && ( n != 3 ) )
380
      return ;
381
    if ( year%4 )
382
      daymonth[1] = 28 ;
383
    else
384
      daymonth[1] = 29 ;
385
    m-- ;
386
    for (int i=0; i<m; i++)
387
      day += daymonth[i] ;
388
    break ;
389
  }
390
  default:
391
    return ;
392
  }
393

    
394
  day += (year - 1972) * 365 - 1 ;
395
  day += (year - 1969) / 4 ;
396
  day += MJD1972 ;
397
  second += (double) hour * 3600 + minute * 60 ;
398
  second *= SEC2DAY ;
399

    
400
  set (day, second, ts, MJD, mjdi, mjdf) ;
401

    
402
  return ;
403
}
404
 
405
//
406
//   -------------------------------------------------
407
// -- XTime::monDay (const char* date, TimeFormat tf) --
408
//   -------------------------------------------------
409
//
410

    
411
// Description:
412
// Convert UTC or TT date string to calendar date string
413
const char* XTime::monDay (const char* date, TimeFormat tf) {
414
  char d[32] ;
415
  int year, day ;
416
  int m = 0 ;
417

    
418
  strcpy (d, date) ;
419
  sscanf (d, "%d:%d", &year, &day) ;
420
  if ( year%4 )
421
    daymonth[1] = 28 ;
422
  else
423
    daymonth[1] = 29 ;
424

    
425
  while ( day > daymonth[m] ) {
426
    day -= daymonth[m] ;
427
    m++ ;
428
  }
429
  if ( tf == CALDATE ) {
430
    sprintf (tdate, "%04d%s%02d at ", year, month[m], day) ;
431
    strcpy (tdate+13, d+9) ;
432
  }
433
  else if ( tf == FITS ) {
434
    sprintf (tdate, "%04d-%02d-%02dT", year, m+1, day) ;
435
    strcpy (tdate+11, d+9) ;
436
  }
437

    
438
  return ( tdate ) ;
439
}
440
 
441
//
442
//   ----------------------------------------
443
// -- XTime::get (TimeSys ts, TimeFormat tf) --
444
//   ----------------------------------------
445
//
446

    
447
// Description:
448
// Generalized time return function; returns SECS
449
// (relative to current MJDref), MJD, or JD, as
450
// specified by ts and tf.
451
// Default for ts is TT, for tf SECS.
452
double XTime::get (TimeSys ts, TimeFormat tf) const {
453
  double tt=timeZero ;
454
  
455
  switch (tf) {
456
  case SECS:
457
    switch (ts) {
458
    case UTC:
459
      tt = getUTC () ;
460
      break ;
461
    case TT:
462
      tt = getTT () ;
463
      break ;
464
    case TAI:
465
      tt = getTAI () ;
466
      break ;
467
    case MET:
468
      tt = getMET () ;
469
      break ;
470
    }
471
    break ;
472
  case JD:
473
    tt += MJD0 ;
474
  case MJD:
475
    switch (ts) {
476
    case UTC:
477
      tt -= myLeaps * SEC2DAY ;
478
    case TAI:
479
      tt -= TAI2TT * SEC2DAY ;
480
    case MET:
481
    case TT:
482
      tt += MJDint + MJDfr ;
483
      break ;
484
    }
485
  }
486
  return tt ;
487
}
488
 
489
//
490
//   ---------------------------------------------------
491
// -- XTime::mjd (long *mjdi, double *mjdf, TimeSys ts) --
492
//   ---------------------------------------------------
493
//
494

    
495
// Description:
496
// Return MJD (*mjdi+*mjdf) and put integer and fractional parts
497
// in arguments, for TimeSys ts (default: TT).
498
double XTime::mjd (long *mjdi, double *mjdf, TimeSys ts) const {
499

    
500
  switch (ts) {
501
  case TT:
502
    return TTmjd (mjdi, mjdf) ;
503
  case TAI:
504
    return TAImjd (mjdi, mjdf) ;
505
  case UTC:
506
    return UTmjd (mjdi, mjdf) ;
507
  }
508
  return 0.0;
509
}
510

    
511
//
512
//   -----------------------------------------
513
// -- XTime::UTmjd (long *mjdi, double *mjdf) --
514
//   -----------------------------------------
515
//
516

    
517
// Description:
518
// Return UTC MJD and put integer and fractional parts in
519
// arguments.
520
double XTime::UTmjd (long *mjdi, double *mjdf) const {
521
  long k = MJDint ;
522
  double x = MJDfr + timeZero - (TAI2TT+myLeaps)*SEC2DAY ;
523

    
524
  if ( x < 0.0 ) {
525
    x++ ;
526
    k-- ;
527
  }
528
  else if ( x >= 1.0 ) {
529
    x-- ;
530
    k++ ;
531
  }
532

    
533
  *mjdi = k ;
534
  *mjdf = x ;
535
  double tt = k + x ;
536

    
537
  return tt ;
538
}
539
 
540
//
541
//   -----------------------------------------------------
542
// -- XTime::getDate (TimeSys ts, TimeFormat tf, int dec) --
543
//   -----------------------------------------------------
544
//
545

    
546
// Description:
547
// Generalized date string return function.
548
// Allows specification of DATE, CALDATE, or FITS formats
549
// and the number of decimals in the seconds field.
550
// The defaults for ts, tf, and dec are UTC, DATE, and 0.
551
const char* XTime::getDate (TimeSys ts, TimeFormat tf, int dec) {
552
  long k ;
553
  double x ;
554

    
555
  // Get MJD representation
556
  mjd (&k, &x, ts) ;
557
  if ( ( ts == UTC ) && leapflag )
558
    x -= SEC2DAY ;
559
  while ( x < 0.0 ) {
560
    x++ ;
561
    k-- ;
562
  }
563
  while ( x >= 1.0 ) {
564
    x-- ;
565
    k++ ;
566
  }
567

    
568
  // Divide into year/day/hour/minute/second
569
  int year, day, hour, minute ;
570
  double second ;
571
  double dsec ;
572
  dsec = 0.5 * pow(10.0, (double) -dec) ;
573

    
574
  // First add dsec; later subtract it; this is to avoid rounding 59.9999 to 60.0
575
  day = k - MJD1972 ;
576
  second = x * DAY2SEC + dsec ;
577
  int i = 0 ;
578
  year = 1972 ;
579
  if ( ( ts == UTC ) && leapflag ) {
580
    second++ ;
581
    hour = (int) second / 3600 ;
582
    if ( hour > 23 ) hour-- ;
583
    second -= hour * 3600.0 ;
584
    minute = (int) second / 60 ;
585
    if ( minute > 59 ) minute-- ;
586
    second -= minute * 60.0 ;
587
  }
588
  else {
589
    hour = (int) second / 3600 ;
590
    second -= hour * 3600.0 ;
591
    minute = (int) second / 60 ;
592
    second -= minute * 60.0 ;
593
  }
594
  if ( hour > 23 ) {
595
    hour -= 24 ;
596
    day++ ;
597
  }
598
  second -= dsec ;
599
  if ( second < 0.0 ) second = 0.0 ;
600
  day++ ;
601
  while ( day > 365 ) {
602
    if ( !i ) {
603
      if ( day == 366 )
604
        break ;
605
      else
606
        day-- ;
607
    }
608
    day -= 365 ;
609
    year++ ;
610
    i = (i+1)%4 ;
611
  }
612

    
613
  char formt[32], f2[10] ;
614
  if ( dec ) {
615
    strcpy (formt, "%4d:%03d:%02d:%02d:%0") ;
616
    sprintf (f2, "%d.%df", dec+3, dec) ;
617
    strcat (formt, f2) ;
618
  }
619
  else
620
    strcpy (formt, "%4d:%03d:%02d:%02d:%02.0f") ;
621
  sprintf (tdate, formt,
622
           year, day, hour, minute, second) ;
623
  /*
624
  switch (ts) {
625
  case TT:
626
    strcat (tdate, "TT") ;
627
    break ;
628
  case UTC:
629
    strcat (tdate, "UTC") ;
630
    break ;
631
  case MET:
632
    strcat (tdate, "MET") ;
633
    break ;
634
  default:
635
    break ;
636
  }
637
  */
638
  if ( ( tf == CALDATE ) || ( tf == FITS ) )
639
    return ( monDay (tdate, tf) ) ;
640
  else
641
    return tdate ;
642
}
643
 
644
//
645
//   -------------------------
646
// -- XTimeRange::setEmpty () --
647
//   -------------------------
648
//
649

    
650
// Description:
651
// Determine whether range is empty
652
void XTimeRange::setEmpty (void) {
653
  double t1=start.getMET() ;
654
  double t2=stop.getMET() ;
655
  if ( ( t1 >= t2 ) || ( t1 <= 0.0 ) || ( t2 <= 0.0 ) )
656
    empty = 1 ;
657
  else
658
    empty = 0 ;
659
  return ;
660
}
661

    
662
//
663
//   ---------------------------
664
// -- XTimeRange::printRange () --
665
//   ---------------------------
666
//
667

    
668
// Description:
669
// A two-liner in UTC date format
670
void XTimeRange::printRange (void) {
671
  cout << "---XTimeRange - Empty: " << empty
672
       << ", Start: " << start.getMET() << " (" << UTStartDate () << ")\n"
673
       << "                       "
674
       << "  Stop:  " << stop.getMET() << " (" << UTStopDate () << ")\n" ;
675
  return ;
676
}
677
//
678
//   ------------------------------
679
// -- XTimeRange::printRangeCal () --
680
//   ------------------------------
681
//
682

    
683
// Description:
684
// A two-liner in UTC calendar date format
685
void XTimeRange::printRangeCal (void) {
686
  cout << "---XTimeRange - Empty: " << empty
687
       << ", Start: " << start.getMET() << " (" << start.UTCalDate () << ")\n"
688
       << "                       "
689
       << "  Stop:  " << stop.getMET() << " (" << stop.UTCalDate () << ")\n" ;
690
  return ;
691
}
692
 
693
//
694
//   -----------------------
695
// -- XTRList::printList () --
696
//   -----------------------
697
//
698

    
699
// Description:
700
// Print list contents in UTC calendar date format
701
void XTRList::printList (void) {
702
  cout << "\nXTRList - Empty: " << empty << ", Number of ranges:: " << numXTRs
703
       << ", List range:\n" ;
704
  listRange.printRange () ;
705
  if ( numXTRs ) {
706
    cout << "Member ranges:\n" ;
707
    for (int i=0;i<numXTRs;i++)
708
      tr[i].printRange () ;
709
  }
710
  return ;
711
}
712

    
713
//
714
//   --------------------------
715
// -- XTRList::printListCal () --
716
//   --------------------------
717
//
718

    
719
// Description:
720
// Print list contents in UTC calendar date format
721
void XTRList::printListCal (void) {
722
  cout << "\nXTRList - Empty: " << empty << ", Number of ranges:: " << numXTRs
723
       << ", List range:\n" ;
724
  listRange.printRangeCal () ;
725
  if ( numXTRs ) {
726
    cout << "Member ranges:\n" ;
727
    for (int i=0;i<numXTRs;i++)
728
      tr[i].printRangeCal () ;
729
  }
730
  return ;
731
}
732
 
733
//
734
//   ----------------------------
735
// -- XTRList::XTRList (XTRList) --
736
//   ----------------------------
737
//
738

    
739
// Description:
740
// Copy constructor for a new TR list
741
XTRList::XTRList (const XTRList &trl)
742
{
743
  numXTRs = trl.numXTRs ;
744
  listRange = trl.listRange ;
745
  empty = trl.empty ;
746
  tr = new XTimeRange[numXTRs] ;
747
  for (int i=0; i<numXTRs; i++)
748
    tr[i] = trl.tr[i] ;
749
  return ;
750
}
751

    
752
//
753
//   ------------------------------
754
// -- XTRList::operator= (XTRList) --
755
//   ------------------------------
756
//
757

    
758
// Description:
759
// Copy operator for a TR list
760
XTRList& XTRList::operator= (const XTRList &trl)
761
{
762
  delete [] tr ;
763
  numXTRs = trl.numXTRs ;
764
  listRange = trl.listRange ;
765
  empty = trl.empty ;
766
  tr = new XTimeRange[numXTRs] ;
767
  for (int i=0; i<numXTRs; i++)
768
    tr[i] = trl.tr[i] ;
769
  return *this ;
770
}
771

    
772
 
773
//
774
//   -------------------------------------
775
// -- XTRList::XTRList (XTRList, XTRList) --
776
//   -------------------------------------
777
//
778

    
779
// Description:
780
// Construct a new TR list by "AND"ing two existing lists
781
XTRList::XTRList (const XTRList &trl1, const XTRList &trl2)
782
  : numXTRs (1), empty (1), tr (0) {
783

    
784
//  Trivial cases: if one of them is empty, the result is empty
785

    
786
  if ( trl1.isEmpty() || trl2.isEmpty() ) {
787
    numXTRs = 1 ;
788
    empty = 1 ;
789
    tr = new XTimeRange () ;
790
    listRange = *tr ;
791
    return ;
792
  }
793

    
794
//  To minimize work, make sure the second one is the shortest
795

    
796
  const XTRList* list1 = &trl1 ;
797
  const XTRList* list2 = &trl2 ;
798
  int nlist1 = list1->numXTRs ;
799
  int nlist2 = list2->numXTRs ;
800
  if ( nlist1 < nlist2 ) {
801
    int i = nlist2 ;
802
    nlist2 = nlist1 ;
803
    nlist1 = i ;
804
    list1 = list2 ;
805
    list2 = &trl1 ;
806
  }
807

    
808
//  Simple case: second list has only one member
809

    
810
  if ( nlist2 == 1 ) {
811
    XTRList scratchlist (*list1) ;
812
    scratchlist.andRange ( list2->tr[0] ) ;
813
    numXTRs = scratchlist.numXTRs ;
814
    listRange = scratchlist.listRange ;
815
    empty = scratchlist.empty ;
816
    tr = new XTimeRange[numXTRs] ;
817
    for (int i=0; i<numXTRs; i++)
818
      tr[i] = scratchlist.tr[i] ;
819
    return ;
820
  }
821

    
822
//  The full works: AND each range in list2 with all of list1
823
//                  OR the resulting lists
824

    
825
  XTRList buildlist ;
826
  int i ;
827
  for (i=0;i<nlist2;i++) {
828
    XTRList scratchlist (*list1) ;
829
    scratchlist.andRange ( list2->tr[i] ) ;
830
    buildlist.orList (scratchlist) ;
831
  }
832
  numXTRs = buildlist.numXTRs ;
833
  listRange = buildlist.listRange ;
834
  empty = buildlist.empty ;
835
  tr = new XTimeRange[numXTRs] ;
836
  for (i=0; i<numXTRs; i++)
837
    tr[i] = buildlist.tr[i] ;
838
  return ;
839
}
840
 
841
//
842
//   -----------------------------
843
// -- XTRList::isInRange (XTime&) --
844
//   -----------------------------
845
//
846

    
847
// Description:
848
// Return 0 if in range
849
int XTRList::isInRange (const XTime &T) const {
850
  for (int i=0;i<numXTRs;i++)
851
    if ( !tr[i].isInRange (T) )
852
      return 0 ;
853
  return 1 ;
854
}
855

    
856
//
857
//   -----------------------------
858
// -- XTRList::isInRange (double) --
859
//   -----------------------------
860
//
861

    
862
// Description:
863
// Return 0 if in range
864
int XTRList::isInRange (double t) const {
865
  for (int i=0;i<numXTRs;i++)
866
    if ( !tr[i].isInRange (t) )
867
      return 0 ;
868
  return 1 ;
869
}
870

    
871
//
872
//   ----------------------------
873
// -- XTRList::getRange (XTime&) --
874
//   ----------------------------
875
//
876

    
877
// Description:
878
// Return range in which XTime object <T> falls
879
const XTimeRange* XTRList::getRange (const XTime &T) const {
880
  for (int i=0;i<numXTRs;i++)
881
    if ( !tr[i].isInRange (T) )
882
      return tr+i ;
883
  return NULL ;
884
}
885

    
886
//
887
//   ----------------------------
888
// -- XTRList::getRange (double) --
889
//   ----------------------------
890
//
891

    
892
// Description:
893
// Return range in which MET time <t> falls
894
const XTimeRange* XTRList::getRange (double t) const {
895
  for (int i=0;i<numXTRs;i++)
896
    if ( !tr[i].isInRange (t) )
897
      return tr+i ;
898
  return NULL ;
899
}
900

    
901
//
902
//   -----------------------
903
// -- XTRList::totalTime () --
904
//   -----------------------
905
//
906

    
907
// Description:
908
// Return total time (in seconds), covered by the list
909
double XTRList::totalTime (void) const {
910
  double tt = 0.0 ;
911
  if ( !empty )
912
    for (int i=0;i<numXTRs;i++)
913
      tt += tr[i].totalTime () ;
914
  return tt ;
915
}
916
 
917
//
918
//   -----------------
919
// -- XTRList::orList --
920
//   -----------------
921
//
922

    
923
// Description:
924
// "OR" in another XTime Range List
925
void XTRList::orList (const XTRList &trl) {
926

    
927
//  Do nothing if trl is empty
928

    
929
  if ( trl.empty )
930
    return ;
931

    
932
//  If *this is empty, replace it by trl
933

    
934
  if ( empty ) {
935
    delete [] tr ;
936
    numXTRs = trl.numXTRs ;
937
    listRange = trl.listRange ;
938
    empty = trl.empty ;
939
    tr = new XTimeRange[numXTRs] ;
940
    for (int i=0; i<numXTRs; i++)
941
      tr[i] = trl.tr[i] ;
942
  }
943

    
944
//  Do the full thing
945

    
946
  else {
947
    int n = trl.numXTRs ;
948
    for (int i=0;i<n;i++)
949
      orRange ( trl.tr[i] ) ;
950
  }
951
  return ;
952
}
953

    
954
//
955
//   ------------------
956
// -- XTRList::notList --
957
//   ------------------
958
//
959

    
960
// Description:
961
// Negate a XTime Range List over a specified time range
962
void XTRList::notList (const XTimeRange &T) {
963

    
964
//  If the list was empty, the answer is just T ...
965

    
966
  if ( empty ) {
967

    
968
//  ... unless, of course, T was empty, too, in which case nothing changes
969

    
970
    if ( !T.isEmpty() ) {
971
      *tr = T ;
972
      listRange = T ;
973
      numXTRs = 1 ;
974
      empty = 0 ;
975
    }
976
  }
977

    
978
//  "Regular" case
979

    
980
  else {
981
    XTimeRange* ntr = new XTimeRange[numXTRs+1] ;
982
    ntr[0].setStart(1000.0) ;
983
    for (int i=0; i<numXTRs; i++) {
984
      ntr[i].setStop(tr[i].TStart()) ;
985
      ntr[i+1].setStart(tr[i].TStop()) ;
986
    }
987
    ntr[numXTRs].setStop(1.0e20) ;
988
    numXTRs++ ;
989
    delete [] tr ;
990
    tr = ntr ;
991
    setListRange () ;
992
    andRange (T) ;
993
  }
994
  return ;
995
}
996

    
997
 
998
//
999
//   -------------------
1000
// -- XTRList::andRange --
1001
//   -------------------
1002
//
1003

    
1004
// Description:
1005
// "AND" in an extra XTime Range
1006
void XTRList::andRange (const XTimeRange &T) {
1007
  int startin=0, stopin=0 ;
1008
  int startafter=0, stopafter=0 ;
1009
  int zap=0 ;
1010
  int istart, istop ;
1011
  int i ;
1012
  double tstart = T.METStart () ;
1013
  double tstop = T.METStop () ;
1014
//
1015
//  First the trivial cases
1016
//
1017
  if ( empty )
1018
    return ;
1019
  else if ( T.isEmpty () )
1020
    zap = 1 ;
1021
  else if ( ( tstart <= listRange.METStart () ) &&
1022
      ( tstop >= listRange.METStop () ) )
1023
    return ;
1024
  else if ( tstop < listRange.METStart () )
1025
    zap = 1 ;
1026
  else if ( tstart > listRange.METStop () )
1027
    zap = 1 ;
1028
//
1029
//  See where the start and stop times fall in the existing list
1030
//  (add 1 to the indices)
1031
  else {
1032
    for (i=0;i<numXTRs;i++) {
1033
      if ( !startin ) {
1034
        istart = tr[i].isInRange (tstart) ;
1035
        if ( !istart )
1036
          startin = i + 1 ;
1037
        else if ( istart > 0 )
1038
          startafter = i + 1 ;
1039
      }
1040
      if ( !stopin ) {
1041
        istop = tr[i].isInRange (tstop) ;
1042
        if ( !istop )
1043
          stopin = i + 1 ;
1044
        else if ( istop > 0 )
1045
          stopafter = i + 1 ;
1046
      }
1047
    }
1048
//
1049
//  Now figure out what to do
1050
//    Which range do we start in?
1051
//
1052
    if ( startin ) {
1053
      startin -- ;                     // Correct the index
1054
      tr[startin].setStart (tstart) ;  // Adjust the time
1055
    }
1056

    
1057
//      In between
1058
    else if ( !stopin && ( startafter == stopafter ) )
1059
      zap = 1 ;
1060

    
1061
//      Start after
1062
    else
1063
      startin = startafter ;
1064

    
1065
//    Which range do we stop in?
1066
    if ( !zap ) {
1067
      if ( stopin ) {
1068
        stopin-- ;
1069
        tr[stopin].setStop (tstop) ;
1070
      }
1071

    
1072
//      Stop after
1073
      else
1074
        stopin = stopafter - 1 ;
1075
    }
1076
  }
1077

    
1078
//
1079
//  Calculate the new length
1080
  int newNumXTRs ;
1081
  if ( zap ) {
1082
    newNumXTRs = 1 ;
1083
    empty = 1 ;
1084
  }
1085
  else
1086
    newNumXTRs = stopin - startin + 1 ;
1087

    
1088
//  No change in number of ranges: done
1089
  if ( numXTRs == newNumXTRs ) {
1090
    if ( zap )
1091
      tr->resetRange (0.0, 0.0) ;
1092
    setListRange () ;
1093
    return ;
1094
  }
1095

    
1096
//
1097
//  Make a new set of ranges
1098
  XTimeRange* newXTR = new XTimeRange[newNumXTRs] ;
1099

    
1100
//
1101
//    Rearrange the ranges
1102
  if ( !zap ) {
1103
//      Now copy the remaining ones
1104
    int j=0 ;
1105
    for (i=startin;i<=stopin;i++,j++)
1106
      newXTR[j] = tr[i] ;
1107
  }
1108
  else
1109
    newXTR->resetRange (0.0, 0.0) ;
1110

    
1111
//
1112
//  Exchange the two lists
1113
  delete [] tr ;
1114
  tr = newXTR ;
1115
  numXTRs = newNumXTRs ;
1116
  setListRange () ;
1117

    
1118
  return ;
1119
}
1120
 
1121
//
1122
//   ------------------
1123
// -- XTRList::orRange --
1124
//   ------------------
1125
//
1126

    
1127
// Description:
1128
// "OR" in an extra XTime Range
1129
void XTRList::orRange (const XTimeRange &T) {
1130
  int startin=0, stopin=0 ;
1131
  int startafter=0, stopafter=0 ;
1132
  int before=0, after=0, between=0, straddle=0 ;
1133
  int istart, istop ;
1134
  int i ;
1135
  double tstart = T.METStart () ;
1136
  double tstop = T.METStop () ;
1137

    
1138
//
1139
//  Handle the empties first
1140
//
1141
  if ( T.isEmpty () )
1142
    return ;
1143
  if ( empty ) {
1144
    numXTRs = 1 ;
1145
    empty = 0 ;
1146
    tr[0] = T ;
1147
    listRange = T ;
1148
    return ;
1149
  }
1150

    
1151
//
1152
//  First the trivial cases
1153
//
1154
  if ( ( tstart <= listRange.METStart () ) &&
1155
      ( tstop >= listRange.METStop () ) )
1156
    straddle = 1 ;
1157
  else if ( tstop < listRange.METStart () )
1158
    before = 1 ;
1159
  else if ( tstart > listRange.METStop () )
1160
    after = 1 ;
1161

    
1162
//
1163
//  See where the start and stop times fall in the existing list
1164
//  (add 1 to the indices)
1165
  else {
1166
    for (i=0;i<numXTRs;i++) {
1167
      if ( !startin ) {
1168
        istart = tr[i].isInRange (tstart) ;
1169
        if ( !istart )
1170
          startin = i + 1 ;
1171
        else if ( istart > 0 )
1172
          startafter = i + 1 ;
1173
      }
1174
      if ( !stopin ) {
1175
        istop = tr[i].isInRange (tstop) ;
1176
        if ( !istop )
1177
          stopin = i + 1 ;
1178
        else if ( istop > 0 )
1179
          stopafter = i + 1 ;
1180
      }
1181
    }
1182
//
1183
//  Now figure out what to do
1184
//    Which range do we start in?
1185
//
1186
    if ( startin ) {
1187
      if ( startin == stopin )  // If we're stopping in the same one, return
1188
        return ;
1189
      startin -- ;              // Correct the index
1190
    }
1191

    
1192
//      In between
1193
    else if ( !stopin && ( startafter == stopafter ) )
1194
      between = stopafter ;
1195

    
1196
//      Somebody's start time needs to be adjusted
1197
    else {
1198
      startin = startafter ;
1199
      tr[startin].setStart (tstart) ;
1200
    }
1201

    
1202
//    Which range do we stop in?
1203
    if ( stopin )
1204
      stopin-- ;
1205
//      Somebody's stop time needs to be adjusted
1206
    else
1207
      if ( stopafter ) {
1208
        stopin = stopafter - 1 ;
1209
        tr[stopin].setStop (tstop) ;
1210
      }
1211
  }
1212

    
1213
//
1214
//  The range list must now be non-empty
1215
  empty = 0 ;
1216

    
1217
//
1218
//  Calculate the new length
1219
  int newNumXTRs ;
1220
  if ( before + after + between )
1221
    newNumXTRs = numXTRs + 1 ;
1222
  else if ( straddle )
1223
    newNumXTRs =  1;
1224
  else
1225
    newNumXTRs = numXTRs - stopin + startin ;
1226

    
1227
//  No change in number of ranges: done
1228
  if ( numXTRs == newNumXTRs ) {
1229
    if ( straddle )
1230
      tr[0] = T ;
1231
    setListRange () ;
1232
    return ;
1233
  }
1234

    
1235
//
1236
//  Make a new set of ranges
1237
  XTimeRange* newXTR = new XTimeRange[newNumXTRs] ;
1238

    
1239
//
1240
//    Extra range before
1241
  if ( before ) {
1242
    newXTR[0] = T ;
1243
    for (i=0;i<numXTRs;i++)
1244
      newXTR[i+1] = tr[i] ;
1245
  }
1246

    
1247
//
1248
//    Extra range after
1249
  else if ( after ) {
1250
    for (i=0;i<numXTRs;i++)
1251
      newXTR[i] = tr[i] ;
1252
    newXTR[numXTRs] = T ;
1253
  }
1254

    
1255
//
1256
//    Straddling range
1257
  else if ( straddle )
1258
    newXTR[0] = T ;
1259

    
1260
//
1261
//    Extra range in between
1262
  else if ( between ) {
1263
    for (i=0;i<between;i++)
1264
      newXTR[i] = tr[i] ;
1265
    newXTR[between] = T ;
1266
    for (i=between;i<numXTRs;i++)
1267
      newXTR[i+1] = tr[i] ;
1268
  }
1269

    
1270
//
1271
//    Rearrange the ranges
1272
  else {
1273
//      Cover the new part in a single range
1274
    tr[stopin].setStart (tr[startin].METStart()) ;
1275
//      Now copy the remaining ones
1276
    int j=0 ;
1277
    for (i=0;i<startin;i++,j++)
1278
      newXTR[j] = tr[i] ;
1279
    for (i=stopin;i<numXTRs;i++,j++)
1280
      newXTR[j] = tr[i] ;
1281
  }
1282

    
1283
//
1284
//  Exchange the two lists
1285
  delete [] tr ;
1286
  tr = newXTR ;
1287
  numXTRs = newNumXTRs ;
1288
  setListRange () ;
1289

    
1290
  return ;
1291
}
1292
 
1293
//
1294
//   -----------------------
1295
// -- XTRList::setListRange --
1296
//   -----------------------
1297
//
1298

    
1299
// Description:
1300
// Update the list range
1301
void XTRList::setListRange (void) {
1302
  int i, j, remove=0 ;
1303

    
1304
  if ( numXTRs )
1305
    empty = 0 ;
1306
  for (i=0; i<numXTRs; i++)
1307
    if ( tr[i].isEmpty() )
1308
      remove++ ;
1309
  if ( remove ) {
1310
    if ( remove >= numXTRs ) {
1311
      numXTRs = 0 ;
1312
      empty = 1 ;
1313
    }
1314
    else {
1315
      XTimeRange* newXTR = new XTimeRange[numXTRs - remove] ;
1316
      for (i=0, j=0; i<numXTRs; i++)
1317
        if ( !tr[i].isEmpty() )
1318
          newXTR[j++] = tr[i] ;
1319
      delete [] tr ;
1320
      tr = newXTR ;
1321
      numXTRs -= remove ;
1322
      empty = 0 ;
1323
    }
1324
  }
1325

    
1326
  if ( !empty )
1327
    listRange.resetRange (tr[0].METStart(), tr[numXTRs-1].METStop()) ;
1328
  else
1329
    listRange.resetRange (0.0, -1.0) ;
1330
}