1 /***************************************************************************
4 * Routines to handle TraceList and related structures.
6 * Written by Chad Trabant, IRIS Data Management Center
9 ***************************************************************************/
19 MSTraceSeg
*mstl_msr2seg (MSRecord
*msr
, hptime_t endtime
);
20 MSTraceSeg
*mstl_addmsrtoseg (MSTraceSeg
*seg
, MSRecord
*msr
, hptime_t endtime
, flag whence
);
21 MSTraceSeg
*mstl_addsegtoseg (MSTraceSeg
*seg1
, MSTraceSeg
*seg2
);
24 /***************************************************************************
27 * Initialize and return a MSTraceList struct, allocating memory if
28 * needed. If the supplied MSTraceList is not NULL any associated
29 * memory it will be freed including data at prvtptr pointers.
31 * Returns a pointer to a MSTraceList struct on success or NULL on error.
32 ***************************************************************************/
34 mstl_init ( MSTraceList
*mstl
)
41 mstl
= (MSTraceList
*) malloc (sizeof(MSTraceList
));
45 ms_log (2, "mstl_init(): Cannot allocate memory\n");
49 memset (mstl
, 0, sizeof (MSTraceList
));
52 } /* End of mstl_init() */
55 /***************************************************************************
58 * Free all memory associated with a MSTraceList struct and set the
61 * If the freeprvtptr flag is true any private pointer data will also
62 * be freed when present.
63 ***************************************************************************/
65 mstl_free ( MSTraceList
**ppmstl
, flag freeprvtptr
)
68 MSTraceID
*nextid
= 0;
70 MSTraceSeg
*nextseg
= 0;
77 /* Free any associated traces */
78 id
= (*ppmstl
)->traces
;
83 /* Free any associated trace segments */
89 /* Free private pointer data if present and requested*/
90 if ( freeprvtptr
&& seg
->prvtptr
)
93 /* Free data array if allocated */
94 if ( seg
->datasamples
)
95 free (seg
->datasamples
);
101 /* Free private pointer data if present and requested*/
102 if ( freeprvtptr
&& id
->prvtptr
)
115 } /* End of mstl_free() */
118 /***************************************************************************
121 * Add data coverage from an MSRecord to a MSTraceList by searching the
122 * list for the appropriate MSTraceID and MSTraceSeg and either adding
123 * data to it or creating a new MStraceID and/or MSTraceSeg if needed.
125 * If the dataquality flag is true the data quality bytes must also
126 * match otherwise they are ignored.
128 * If the autoheal flag is true extra processing is invoked to conjoin
129 * trace segments that fit together after the MSRecord coverage is
130 * added. For segments that are removed, any memory at the prvtptr
133 * An MSTraceList is always maintained with the MSTraceIDs in
134 * descending alphanumeric order. MSTraceIDs are always maintained
135 * with MSTraceSegs in data time time order.
137 * Return a pointer to the MSTraceSeg updated or 0 on error.
138 ***************************************************************************/
140 mstl_addmsr ( MSTraceList
*mstl
, MSRecord
*msr
, flag dataquality
,
141 flag autoheal
, double timetol
, double sampratetol
)
144 MSTraceID
*searchid
= 0;
148 MSTraceSeg
*searchseg
= 0;
149 MSTraceSeg
*segbefore
= 0;
150 MSTraceSeg
*segafter
= 0;
151 MSTraceSeg
*followseg
= 0;
159 hptime_t hptimetol
= 0;
160 hptime_t nhptimetol
= 0;
172 if ( ! mstl
|| ! msr
)
175 /* Calculate end time for MSRecord */
176 if ( (endtime
= msr_endtime (msr
)) == HPTERROR
)
178 ms_log (2, "mstl_addmsr(): Error calculating record end time\n");
182 /* Generate source name string */
183 if ( ! msr_srcname (msr
, srcname
, dataquality
) )
185 ms_log (2, "mstl_addmsr(): Error generating srcname for MSRecord\n");
189 /* Search for matching trace ID starting with last accessed ID and
190 then looping through the trace ID list. */
193 s1
= mstl
->last
->srcname
;
195 while ( *s1
== *s2
++ )
208 /* Loop through trace ID list searching for a match, simultaneously
209 * track the source name which is closest but less than the MSRecord
210 * to allow for later insertion with sort order. */
211 searchid
= mstl
->traces
;
216 /* Compare source names */
217 s1
= searchid
->srcname
;
220 while ( *s1
== *s2
++ )
228 /* If source names did not match track closest "less than" value
229 * and continue searching. */
234 if ( (ltcmp
== 0 || cmp
>= ltcmp
) && mag
>= ltmag
)
240 else if ( mag
> ltmag
)
248 searchid
= searchid
->next
;
252 /* If we made it this far we found a match */
257 } /* Done searching for match in trace ID list */
259 /* If no matching ID was found create new MSTraceID and MSTraceSeg entries */
262 if ( ! (id
= (MSTraceID
*) calloc (1, sizeof(MSTraceID
))) )
264 ms_log (2, "mstl_addmsr(): Error allocating memory\n");
268 /* Populate MSTraceID */
269 strcpy (id
->network
, msr
->network
);
270 strcpy (id
->station
, msr
->station
);
271 strcpy (id
->location
, msr
->location
);
272 strcpy (id
->channel
, msr
->channel
);
273 id
->dataquality
= msr
->dataquality
;
274 strcpy (id
->srcname
, srcname
);
276 id
->earliest
= msr
->starttime
;
277 id
->latest
= endtime
;
280 if ( ! (seg
= mstl_msr2seg (msr
, endtime
)) )
284 id
->first
= id
->last
= seg
;
286 /* Add new MSTraceID to MSTraceList */
287 if ( ! mstl
->traces
|| ! ltid
)
289 id
->next
= mstl
->traces
;
294 id
->next
= ltid
->next
;
300 /* Add data coverage to the matching MSTraceID */
303 /* Calculate high-precision sample period */
304 hpdelta
= (hptime_t
) (( msr
->samprate
) ? (HPTMODULUS
/ msr
->samprate
) : 0.0);
306 /* Calculate high-precision time tolerance */
307 if ( timetol
== -1.0 )
308 hptimetol
= (hptime_t
) (0.5 * hpdelta
); /* Default time tolerance is 1/2 sample period */
309 else if ( timetol
>= 0.0 )
310 hptimetol
= (hptime_t
) (timetol
* HPTMODULUS
);
312 nhptimetol
= ( hptimetol
) ? -hptimetol
: 0;
314 /* last/firstgap are negative when the record overlaps the trace
315 * segment and positive when there is a time gap. */
317 /* Gap relative to the last segment */
318 lastgap
= msr
->starttime
- id
->last
->endtime
- hpdelta
;
320 /* Gap relative to the first segment */
321 firstgap
= id
->first
->starttime
- endtime
- hpdelta
;
323 /* Sample rate tolerance checks for first and last segments */
324 if ( sampratetol
== -1.0 )
326 lastratecheck
= MS_ISRATETOLERABLE (msr
->samprate
, id
->last
->samprate
);
327 firstratecheck
= MS_ISRATETOLERABLE (msr
->samprate
, id
->first
->samprate
);
331 lastratecheck
= (ms_dabs (msr
->samprate
- id
->last
->samprate
) > sampratetol
) ? 0 : 1;
332 firstratecheck
= (ms_dabs (msr
->samprate
- id
->first
->samprate
) > sampratetol
) ? 0 : 1;
335 /* Search first for the simple scenarios in order of likelihood:
336 * - Record fits at end of last segment
337 * - Record fits after all coverage
338 * - Record fits before all coverage
339 * - Record fits at beginning of first segment
341 * If none of those scenarios are true search the complete segment list.
344 /* Record coverage fits at end of last segment */
345 if ( lastgap
<= hptimetol
&& lastgap
>= nhptimetol
&& lastratecheck
)
347 if ( ! mstl_addmsrtoseg (id
->last
, msr
, endtime
, 1) )
352 if ( endtime
> id
->latest
)
353 id
->latest
= endtime
;
355 /* Record coverage is after all other coverage */
356 else if ( (msr
->starttime
- hpdelta
- hptimetol
) > id
->latest
)
358 if ( ! (seg
= mstl_msr2seg (msr
, endtime
)) )
361 /* Add to end of list */
362 id
->last
->next
= seg
;
363 seg
->prev
= id
->last
;
367 if ( endtime
> id
->latest
)
368 id
->latest
= endtime
;
370 /* Record coverage is before all other coverage */
371 else if ( (endtime
+ hpdelta
+ hptimetol
) < id
->earliest
)
373 if ( ! (seg
= mstl_msr2seg (msr
, endtime
)) )
376 /* Add to beginning of list */
377 id
->first
->prev
= seg
;
378 seg
->next
= id
->first
;
382 if ( msr
->starttime
< id
->earliest
)
383 id
->earliest
= msr
->starttime
;
385 /* Record coverage fits at beginning of first segment */
386 else if ( firstgap
<= hptimetol
&& firstgap
>= nhptimetol
&& firstratecheck
)
388 if ( ! mstl_addmsrtoseg (id
->first
, msr
, endtime
, 2) )
393 if ( msr
->starttime
< id
->earliest
)
394 id
->earliest
= msr
->starttime
;
396 /* Search complete segment list for matches */
399 searchseg
= id
->first
;
400 segbefore
= 0; /* Find segment that record fits before */
401 segafter
= 0; /* Find segment that record fits after */
402 followseg
= 0; /* Track segment that record follows in time order */
405 if ( msr
->starttime
> searchseg
->starttime
)
406 followseg
= searchseg
;
410 postgap
= msr
->starttime
- searchseg
->endtime
- hpdelta
;
411 if ( ! segbefore
&& postgap
<= hptimetol
&& postgap
>= nhptimetol
)
414 pregap
= searchseg
->starttime
- endtime
- hpdelta
;
415 if ( ! segafter
&& pregap
<= hptimetol
&& pregap
>= nhptimetol
)
420 searchseg
= searchseg
->next
;
424 if ( sampratetol
== -1.0 )
426 if ( ! MS_ISRATETOLERABLE (msr
->samprate
, searchseg
->samprate
) )
428 searchseg
= searchseg
->next
;
434 if ( ms_dabs (msr
->samprate
- searchseg
->samprate
) > sampratetol
)
436 searchseg
= searchseg
->next
;
442 segbefore
= searchseg
;
444 segafter
= searchseg
;
446 /* Done searching if not autohealing */
450 /* Done searching if both before and after segments are found */
451 if ( segbefore
&& segafter
)
454 searchseg
= searchseg
->next
;
455 } /* Done looping through segments */
457 /* Add MSRecord coverage to end of segment before */
460 if ( ! mstl_addmsrtoseg (segbefore
, msr
, endtime
, 1) )
465 /* Merge two segments that now fit if autohealing */
466 if ( autoheal
&& segafter
&& segbefore
!= segafter
)
468 /* Add segafter coverage to segbefore */
469 if ( ! mstl_addsegtoseg (segbefore
, segafter
) )
474 /* Shift last segment pointer if it's going to be removed */
475 if ( segafter
== id
->last
)
476 id
->last
= id
->last
->prev
;
478 /* Remove segafter from list */
479 if ( segafter
->prev
)
480 segafter
->prev
->next
= segafter
->next
;
481 if ( segafter
->next
)
482 segafter
->next
->prev
= segafter
->prev
;
484 /* Free data samples, private data and segment structure */
485 if (segafter
->datasamples
)
486 free (segafter
->datasamples
);
488 if (segafter
->prvtptr
)
489 free (segafter
->prvtptr
);
496 /* Add MSRecord coverage to beginning of segment after */
499 if ( ! mstl_addmsrtoseg (segafter
, msr
, endtime
, 2) )
506 /* Add MSRecord coverage to new segment */
509 /* Create new segment */
510 if ( ! (seg
= mstl_msr2seg (msr
, endtime
)) )
515 /* Add new segment as first in list */
518 seg
->next
= id
->first
;
520 id
->first
->prev
= seg
;
524 /* Add new segment after the followseg segment */
527 seg
->next
= followseg
->next
;
528 seg
->prev
= followseg
;
529 if ( followseg
->next
)
530 followseg
->next
->prev
= seg
;
531 followseg
->next
= seg
;
533 if ( followseg
== id
->last
)
540 /* Track earliest and latest times */
541 if ( msr
->starttime
< id
->earliest
)
542 id
->earliest
= msr
->starttime
;
544 if ( endtime
> id
->latest
)
545 id
->latest
= endtime
;
546 } /* End of searching segment list */
547 } /* End of adding coverage to matching ID */
549 /* Sort modified segment into place, logic above should limit these to few shifts if any */
550 while ( seg
->next
&& ( seg
->starttime
> seg
->next
->starttime
||
551 (seg
->starttime
== seg
->next
->starttime
&& seg
->endtime
< seg
->next
->endtime
) ) )
553 /* Move segment down list, swap seg and seg->next */
554 segafter
= seg
->next
;
557 seg
->prev
->next
= segafter
;
559 if ( segafter
->next
)
560 segafter
->next
->prev
= seg
;
562 segafter
->prev
= seg
->prev
;
563 seg
->prev
= segafter
;
564 seg
->next
= segafter
->next
;
565 segafter
->next
= seg
;
567 /* Reset first and last segment pointers if replaced */
568 if ( id
->first
== seg
)
569 id
->first
= segafter
;
571 if ( id
->last
== segafter
)
574 while ( seg
->prev
&& ( seg
->starttime
< seg
->prev
->starttime
||
575 (seg
->starttime
== seg
->prev
->starttime
&& seg
->endtime
> seg
->prev
->endtime
) ) )
577 /* Move segment up list, swap seg and seg->prev */
578 segbefore
= seg
->prev
;
581 seg
->next
->prev
= segbefore
;
583 if ( segbefore
->prev
)
584 segbefore
->prev
->next
= seg
;
586 segbefore
->next
= seg
->next
;
587 seg
->next
= segbefore
;
588 seg
->prev
= segbefore
->prev
;
589 segbefore
->prev
= seg
;
591 /* Reset first and last segment pointers if replaced */
592 if ( id
->first
== segbefore
)
595 if ( id
->last
== seg
)
596 id
->last
= segbefore
;
599 /* Set MSTraceID as last accessed */
603 } /* End of mstl_addmsr() */
606 /***************************************************************************
609 * Create an MSTraceSeg structure from an MSRecord structure.
611 * Return a pointer to a MSTraceSeg otherwise 0 on error.
612 ***************************************************************************/
614 mstl_msr2seg (MSRecord
*msr
, hptime_t endtime
)
619 if ( ! (seg
= (MSTraceSeg
*) calloc (1, sizeof(MSTraceSeg
))) )
621 ms_log (2, "mstl_addmsr(): Error allocating memory\n");
625 /* Populate MSTraceSeg */
626 seg
->starttime
= msr
->starttime
;
627 seg
->endtime
= endtime
;
628 seg
->samprate
= msr
->samprate
;
629 seg
->samplecnt
= msr
->samplecnt
;
630 seg
->sampletype
= msr
->sampletype
;
631 seg
->numsamples
= msr
->numsamples
;
633 /* Allocate space for and copy datasamples */
634 if ( msr
->datasamples
&& msr
->numsamples
)
636 samplesize
= ms_samplesize (msr
->sampletype
);
638 if ( ! (seg
->datasamples
= malloc ((size_t) (samplesize
* msr
->numsamples
))) )
640 ms_log (2, "mstl_msr2seg(): Error allocating memory\n");
644 /* Copy data samples from MSRecord to MSTraceSeg */
645 memcpy (seg
->datasamples
, msr
->datasamples
, (size_t) (samplesize
* msr
->numsamples
));
649 } /* End of mstl_msr2seg() */
652 /***************************************************************************
655 * Add data coverage from a MSRecord structure to a MSTraceSeg structure.
657 * Data coverage is added to the beginning or end of MSTraceSeg
658 * according to the whence flag:
659 * 1 : add coverage to the end
660 * 2 : add coverage to the beginninig
662 * Return a pointer to a MSTraceSeg otherwise 0 on error.
663 ***************************************************************************/
665 mstl_addmsrtoseg (MSTraceSeg
*seg
, MSRecord
*msr
, hptime_t endtime
, flag whence
)
668 void *newdatasamples
;
670 if ( ! seg
|| ! msr
)
673 /* Allocate more memory for data samples if included */
674 if ( msr
->datasamples
&& msr
->numsamples
> 0 )
676 if ( msr
->sampletype
!= seg
->sampletype
)
678 ms_log (2, "mstl_addmsrtoseg(): MSRecord sample type (%c) does not match segment sample type (%c)\n",
679 msr
->sampletype
, seg
->sampletype
);
683 if ( ! (samplesize
= ms_samplesize (msr
->sampletype
)) )
685 ms_log (2, "mstl_addmsrtoseg(): Unknown sample size for sample type: %c\n", msr
->sampletype
);
689 if ( ! (newdatasamples
= realloc (seg
->datasamples
, (size_t) ((seg
->numsamples
+ msr
->numsamples
) * samplesize
))) )
691 ms_log (2, "mstl_addmsrtoseg(): Error allocating memory\n");
695 seg
->datasamples
= newdatasamples
;
698 /* Add coverage to end of segment */
701 seg
->endtime
= endtime
;
702 seg
->samplecnt
+= msr
->samplecnt
;
704 if ( msr
->datasamples
&& msr
->numsamples
> 0 )
706 memcpy ((char *)seg
->datasamples
+ (seg
->numsamples
* samplesize
),
708 (size_t) (msr
->numsamples
* samplesize
));
710 seg
->numsamples
+= msr
->numsamples
;
713 /* Add coverage to beginning of segment */
714 else if ( whence
== 2 )
716 seg
->starttime
= msr
->starttime
;
717 seg
->samplecnt
+= msr
->samplecnt
;
719 if ( msr
->datasamples
&& msr
->numsamples
> 0 )
721 memmove ((char *)seg
->datasamples
+ (msr
->numsamples
* samplesize
),
723 (size_t) (seg
->numsamples
* samplesize
));
725 memcpy (seg
->datasamples
,
727 (size_t) (msr
->numsamples
* samplesize
));
729 seg
->numsamples
+= msr
->numsamples
;
734 ms_log (2, "mstl_addmsrtoseg(): unrecognized whence value: %d\n", whence
);
739 } /* End of mstl_addmsrtoseg() */
742 /***************************************************************************
745 * Add data coverage from seg2 to seg1.
747 * Return a pointer to a seg1 otherwise 0 on error.
748 ***************************************************************************/
750 mstl_addsegtoseg (MSTraceSeg
*seg1
, MSTraceSeg
*seg2
)
753 void *newdatasamples
;
755 if ( ! seg1
|| ! seg2
)
758 /* Allocate more memory for data samples if included */
759 if ( seg2
->datasamples
&& seg2
->numsamples
> 0 )
761 if ( seg2
->sampletype
!= seg1
->sampletype
)
763 ms_log (2, "mstl_addsegtoseg(): MSTraceSeg sample types do not match (%c and %c)\n",
764 seg1
->sampletype
, seg2
->sampletype
);
768 if ( ! (samplesize
= ms_samplesize (seg1
->sampletype
)) )
770 ms_log (2, "mstl_addsegtoseg(): Unknown sample size for sample type: %c\n", seg1
->sampletype
);
774 if ( ! (newdatasamples
= realloc (seg1
->datasamples
, (size_t) ((seg1
->numsamples
+ seg2
->numsamples
) * samplesize
))) )
776 ms_log (2, "mstl_addsegtoseg(): Error allocating memory\n");
780 seg1
->datasamples
= newdatasamples
;
783 /* Add seg2 coverage to end of seg1 */
784 seg1
->endtime
= seg2
->endtime
;
785 seg1
->samplecnt
+= seg2
->samplecnt
;
787 if ( seg2
->datasamples
&& seg2
->numsamples
> 0 )
789 memcpy ((char *)seg1
->datasamples
+ (seg1
->numsamples
* samplesize
),
791 (size_t) (seg2
->numsamples
* samplesize
));
793 seg1
->numsamples
+= seg2
->numsamples
;
797 } /* End of mstl_addsegtoseg() */
800 /***************************************************************************
801 * mstl_convertsamples:
803 * Convert the data samples associated with an MSTraceSeg to another
804 * data type. ASCII data samples cannot be converted, if supplied or
805 * requested an error will be returned.
807 * When converting float & double sample types to integer type a
808 * simple rounding is applied by adding 0.5 to the sample value before
809 * converting (truncating) to integer.
811 * If the truncate flag is true data samples will be truncated to
812 * integers even if loss of sample precision is detected. If the
813 * truncate flag is false (0) and loss of precision is detected an
816 * Returns 0 on success, and -1 on failure.
817 ***************************************************************************/
819 mstl_convertsamples ( MSTraceSeg
*seg
, char type
, flag truncate
)
829 /* No conversion necessary, report success */
830 if ( seg
->sampletype
== type
)
833 if ( seg
->sampletype
== 'a' || type
== 'a' )
835 ms_log (2, "mstl_convertsamples: cannot convert ASCII samples to/from numeric type\n");
839 idata
= (int32_t *) seg
->datasamples
;
840 fdata
= (float *) seg
->datasamples
;
841 ddata
= (double *) seg
->datasamples
;
843 /* Convert to 32-bit integers */
846 if ( seg
->sampletype
== 'f' ) /* Convert floats to integers with simple rounding */
848 for (idx
= 0; idx
< seg
->numsamples
; idx
++)
850 /* Check for loss of sub-integer */
851 if ( ! truncate
&& (fdata
[idx
] - (int32_t)fdata
[idx
]) > 0.000001 )
853 ms_log (1, "mstl_convertsamples: Warning, loss of precision when converting floats to integers, loss: %g\n",
854 (fdata
[idx
] - (int32_t)fdata
[idx
]));
858 idata
[idx
] = (int32_t) (fdata
[idx
] + 0.5);
861 else if ( seg
->sampletype
== 'd' ) /* Convert doubles to integers with simple rounding */
863 for (idx
= 0; idx
< seg
->numsamples
; idx
++)
865 /* Check for loss of sub-integer */
866 if ( ! truncate
&& (ddata
[idx
] - (int32_t)ddata
[idx
]) > 0.000001 )
868 ms_log (1, "mstl_convertsamples: Warning, loss of precision when converting doubles to integers, loss: %g\n",
869 (ddata
[idx
] - (int32_t)ddata
[idx
]));
873 idata
[idx
] = (int32_t) (ddata
[idx
] + 0.5);
876 /* Reallocate buffer for reduced size needed */
877 if ( ! (seg
->datasamples
= realloc (seg
->datasamples
, (size_t) (seg
->numsamples
* sizeof(int32_t)))) )
879 ms_log (2, "mstl_convertsamples: cannot re-allocate buffer for sample conversion\n");
884 seg
->sampletype
= 'i';
885 } /* Done converting to 32-bit integers */
887 /* Convert to 32-bit floats */
888 else if ( type
== 'f' )
890 if ( seg
->sampletype
== 'i' ) /* Convert integers to floats */
892 for (idx
= 0; idx
< seg
->numsamples
; idx
++)
893 fdata
[idx
] = (float) idata
[idx
];
895 else if ( seg
->sampletype
== 'd' ) /* Convert doubles to floats */
897 for (idx
= 0; idx
< seg
->numsamples
; idx
++)
898 fdata
[idx
] = (float) ddata
[idx
];
900 /* Reallocate buffer for reduced size needed */
901 if ( ! (seg
->datasamples
= realloc (seg
->datasamples
, (size_t) (seg
->numsamples
* sizeof(float)))) )
903 ms_log (2, "mstl_convertsamples: cannot re-allocate buffer after sample conversion\n");
908 seg
->sampletype
= 'f';
909 } /* Done converting to 32-bit floats */
911 /* Convert to 64-bit doubles */
912 else if ( type
== 'd' )
914 if ( ! (ddata
= (double *) malloc ((size_t) (seg
->numsamples
* sizeof(double)))) )
916 ms_log (2, "mstl_convertsamples: cannot allocate buffer for sample conversion to doubles\n");
920 if ( seg
->sampletype
== 'i' ) /* Convert integers to doubles */
922 for (idx
= 0; idx
< seg
->numsamples
; idx
++)
923 ddata
[idx
] = (double) idata
[idx
];
927 else if ( seg
->sampletype
== 'f' ) /* Convert floats to doubles */
929 for (idx
= 0; idx
< seg
->numsamples
; idx
++)
930 ddata
[idx
] = (double) fdata
[idx
];
935 seg
->datasamples
= ddata
;
936 seg
->sampletype
= 'd';
937 } /* Done converting to 64-bit doubles */
940 } /* End of mstl_convertsamples() */
943 /***************************************************************************
944 * mstl_printtracelist:
946 * Print trace list summary information for the specified MSTraceList.
948 * By default only print the srcname, starttime and endtime for each
949 * trace. If details is greater than 0 include the sample rate,
950 * number of samples and a total trace count. If gaps is greater than
951 * 0 and the previous trace matches (srcname & samprate) include the
952 * gap between the endtime of the last trace and the starttime of the
955 * The timeformat flag can either be:
956 * 0 : SEED time format (year, day-of-year, hour, min, sec)
957 * 1 : ISO time format (year, month, day, hour, min, sec)
958 * 2 : Epoch time, seconds since the epoch
959 ***************************************************************************/
961 mstl_printtracelist ( MSTraceList
*mstl
, flag timeformat
,
962 flag details
, flag gaps
)
980 /* Print out the appropriate header */
981 if ( details
> 0 && gaps
> 0 )
982 ms_log (0, " Source Start sample End sample Gap Hz Samples\n");
983 else if ( details
<= 0 && gaps
> 0 )
984 ms_log (0, " Source Start sample End sample Gap\n");
985 else if ( details
> 0 && gaps
<= 0 )
986 ms_log (0, " Source Start sample End sample Hz Samples\n");
988 ms_log (0, " Source Start sample End sample\n");
990 /* Loop through trace list */
994 /* Loop through segment list */
998 /* Create formatted time strings */
999 if ( timeformat
== 2 )
1001 snprintf (stime
, sizeof(stime
), "%.6f", (double) MS_HPTIME2EPOCH(seg
->starttime
) );
1002 snprintf (etime
, sizeof(etime
), "%.6f", (double) MS_HPTIME2EPOCH(seg
->endtime
) );
1004 else if ( timeformat
== 1 )
1006 if ( ms_hptime2isotimestr (seg
->starttime
, stime
, 1) == NULL
)
1007 ms_log (2, "Cannot convert trace start time for %s\n", id
->srcname
);
1009 if ( ms_hptime2isotimestr (seg
->endtime
, etime
, 1) == NULL
)
1010 ms_log (2, "Cannot convert trace end time for %s\n", id
->srcname
);
1014 if ( ms_hptime2seedtimestr (seg
->starttime
, stime
, 1) == NULL
)
1015 ms_log (2, "Cannot convert trace start time for %s\n", id
->srcname
);
1017 if ( ms_hptime2seedtimestr (seg
->endtime
, etime
, 1) == NULL
)
1018 ms_log (2, "Cannot convert trace end time for %s\n", id
->srcname
);
1021 /* Print segment info at varying levels */
1028 gap
= (double) (seg
->starttime
- seg
->prev
->endtime
) / HPTMODULUS
;
1032 /* Check that any overlap is not larger than the trace coverage */
1035 delta
= ( seg
->samprate
) ? (1.0 / seg
->samprate
) : 0.0;
1037 if ( (gap
* -1.0) > (((double)(seg
->endtime
- seg
->starttime
)/HPTMODULUS
) + delta
) )
1038 gap
= -(((double)(seg
->endtime
- seg
->starttime
)/HPTMODULUS
) + delta
);
1041 /* Fix up gap display */
1043 snprintf (gapstr
, sizeof(gapstr
), " == ");
1044 else if ( gap
>= 86400.0 || gap
<= -86400.0 )
1045 snprintf (gapstr
, sizeof(gapstr
), "%-3.1fd", (gap
/ 86400));
1046 else if ( gap
>= 3600.0 || gap
<= -3600.0 )
1047 snprintf (gapstr
, sizeof(gapstr
), "%-3.1fh", (gap
/ 3600));
1048 else if ( gap
== 0.0 )
1049 snprintf (gapstr
, sizeof(gapstr
), "-0 ");
1051 snprintf (gapstr
, sizeof(gapstr
), "%-4.4g", gap
);
1054 ms_log (0, "%-17s %-24s %-24s %-4s\n",
1055 id
->srcname
, stime
, etime
, gapstr
);
1057 ms_log (0, "%-17s %-24s %-24s %-s %-3.3g %-"PRId64
"\n",
1058 id
->srcname
, stime
, etime
, gapstr
, seg
->samprate
, seg
->samplecnt
);
1060 else if ( details
> 0 && gaps
<= 0 )
1061 ms_log (0, "%-17s %-24s %-24s %-3.3g %-"PRId64
"\n",
1062 id
->srcname
, stime
, etime
, seg
->samprate
, seg
->samplecnt
);
1064 ms_log (0, "%-17s %-24s %-24s\n", id
->srcname
, stime
, etime
);
1074 if ( tracecnt
!= mstl
->numtraces
)
1075 ms_log (2, "mstl_printtracelist(): number of traces in trace list is inconsistent\n");
1078 ms_log (0, "Total: %d trace(s) with %d segment(s)\n", tracecnt
, segcnt
);
1081 } /* End of mstl_printtracelist() */
1084 /***************************************************************************
1085 * mstl_printsynclist:
1087 * Print SYNC trace list summary information for the specified MSTraceList.
1089 * The SYNC header line will be created using the supplied dccid, if
1090 * the pointer is NULL the string "DCC" will be used instead.
1092 * If the subsecond flag is true the segment start and end times will
1093 * include subsecond precision, otherwise they will be truncated to
1096 ***************************************************************************/
1098 mstl_printsynclist ( MSTraceList
*mstl
, char *dccid
, flag subsecond
)
1101 MSTraceSeg
*seg
= 0;
1113 /* Generate current time stamp */
1115 nt
= localtime ( &now
); nt
->tm_year
+= 1900; nt
->tm_yday
+= 1;
1116 snprintf ( yearday
, sizeof(yearday
), "%04d,%03d", nt
->tm_year
, nt
->tm_yday
);
1118 /* Print SYNC header line */
1119 ms_log (0, "%s|%s\n", (dccid
)?dccid
:"DCC", yearday
);
1121 /* Loop through trace list */
1125 /* Loop through segment list */
1129 ms_hptime2seedtimestr (seg
->starttime
, starttime
, subsecond
);
1130 ms_hptime2seedtimestr (seg
->endtime
, endtime
, subsecond
);
1132 /* Print SYNC line */
1133 ms_log (0, "%s|%s|%s|%s|%s|%s||%.10g|%"PRId64
"|||||||%s\n",
1134 id
->network
, id
->station
, id
->location
, id
->channel
,
1135 starttime
, endtime
, seg
->samprate
, seg
->samplecnt
,
1145 } /* End of mstl_printsynclist() */
1148 /***************************************************************************
1149 * mstl_printgaplist:
1151 * Print gap/overlap list summary information for the specified
1152 * MSTraceList. Overlaps are printed as negative gaps.
1154 * If mingap and maxgap are not NULL their values will be enforced and
1155 * only gaps/overlaps matching their implied criteria will be printed.
1157 * The timeformat flag can either be:
1158 * 0 : SEED time format (year, day-of-year, hour, min, sec)
1159 * 1 : ISO time format (year, month, day, hour, min, sec)
1160 * 2 : Epoch time, seconds since the epoch
1161 ***************************************************************************/
1163 mstl_printgaplist (MSTraceList
*mstl
, flag timeformat
,
1164 double *mingap
, double *maxgap
)
1167 MSTraceSeg
*seg
= 0;
1169 char time1
[30], time2
[30];
1180 if ( ! mstl
->traces
)
1183 ms_log (0, " Source Last Sample Next Sample Gap Samples\n");
1191 /* Skip segments with 0 sample rate, usually from SOH records */
1192 if ( seg
->samprate
== 0.0 )
1198 gap
= (double) (seg
->next
->starttime
- seg
->endtime
) / HPTMODULUS
;
1200 /* Check that any overlap is not larger than the trace coverage */
1203 delta
= ( seg
->next
->samprate
) ? (1.0 / seg
->next
->samprate
) : 0.0;
1205 if ( (gap
* -1.0) > (((double)(seg
->next
->endtime
- seg
->next
->starttime
)/HPTMODULUS
) + delta
) )
1206 gap
= -(((double)(seg
->next
->endtime
- seg
->next
->starttime
)/HPTMODULUS
) + delta
);
1211 /* Check gap/overlap criteria */
1213 if ( gap
< *mingap
)
1217 if ( gap
> *maxgap
)
1222 nsamples
= ms_dabs(gap
) * seg
->samprate
;
1229 /* Fix up gap display */
1230 if ( gap
>= 86400.0 || gap
<= -86400.0 )
1231 snprintf (gapstr
, sizeof(gapstr
), "%-3.1fd", (gap
/ 86400));
1232 else if ( gap
>= 3600.0 || gap
<= -3600.0 )
1233 snprintf (gapstr
, sizeof(gapstr
), "%-3.1fh", (gap
/ 3600));
1234 else if ( gap
== 0.0 )
1235 snprintf (gapstr
, sizeof(gapstr
), "-0 ");
1237 snprintf (gapstr
, sizeof(gapstr
), "%-4.4g", gap
);
1239 /* Create formatted time strings */
1240 if ( timeformat
== 2 )
1242 snprintf (time1
, sizeof(time1
), "%.6f", (double) MS_HPTIME2EPOCH(seg
->endtime
) );
1243 snprintf (time2
, sizeof(time2
), "%.6f", (double) MS_HPTIME2EPOCH(seg
->next
->starttime
) );
1245 else if ( timeformat
== 1 )
1247 if ( ms_hptime2isotimestr (seg
->endtime
, time1
, 1) == NULL
)
1248 ms_log (2, "Cannot convert trace end time for %s\n", id
->srcname
);
1250 if ( ms_hptime2isotimestr (seg
->next
->starttime
, time2
, 1) == NULL
)
1251 ms_log (2, "Cannot convert next trace start time for %s\n", id
->srcname
);
1255 if ( ms_hptime2seedtimestr (seg
->endtime
, time1
, 1) == NULL
)
1256 ms_log (2, "Cannot convert trace end time for %s\n", id
->srcname
);
1258 if ( ms_hptime2seedtimestr (seg
->next
->starttime
, time2
, 1) == NULL
)
1259 ms_log (2, "Cannot convert next trace start time for %s\n", id
->srcname
);
1262 ms_log (0, "%-17s %-24s %-24s %-4s %-.8g\n",
1263 id
->srcname
, time1
, time2
, gapstr
, nsamples
);
1274 ms_log (0, "Total: %d gap(s)\n", gapcnt
);
1277 } /* End of mstl_printgaplist() */