Show the file size of the files in the tmp_dir on the LCD.
[ruwai.git] / software / c++ / ruwaicom / src / libmseed / tracelist.c
blob930981ce3c2dd5b8176765299965dd6a6687eae8
1 /***************************************************************************
2 * tracelist.c:
4 * Routines to handle TraceList and related structures.
6 * Written by Chad Trabant, IRIS Data Management Center
8 * modified: 2015.108
9 ***************************************************************************/
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <time.h>
16 #include "libmseed.h"
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 /***************************************************************************
25 * mstl_init:
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 ***************************************************************************/
33 MSTraceList *
34 mstl_init ( MSTraceList *mstl )
36 if ( mstl )
38 mstl_free (&mstl, 1);
41 mstl = (MSTraceList *) malloc (sizeof(MSTraceList));
43 if ( mstl == NULL )
45 ms_log (2, "mstl_init(): Cannot allocate memory\n");
46 return NULL;
49 memset (mstl, 0, sizeof (MSTraceList));
51 return mstl;
52 } /* End of mstl_init() */
55 /***************************************************************************
56 * mstl_free:
58 * Free all memory associated with a MSTraceList struct and set the
59 * pointer to 0.
61 * If the freeprvtptr flag is true any private pointer data will also
62 * be freed when present.
63 ***************************************************************************/
64 void
65 mstl_free ( MSTraceList **ppmstl, flag freeprvtptr )
67 MSTraceID *id = 0;
68 MSTraceID *nextid = 0;
69 MSTraceSeg *seg = 0;
70 MSTraceSeg *nextseg = 0;
72 if ( ! ppmstl )
73 return;
75 if ( *ppmstl )
77 /* Free any associated traces */
78 id = (*ppmstl)->traces;
79 while ( id )
81 nextid = id->next;
83 /* Free any associated trace segments */
84 seg = id->first;
85 while ( seg )
87 nextseg = seg->next;
89 /* Free private pointer data if present and requested*/
90 if ( freeprvtptr && seg->prvtptr )
91 free (seg->prvtptr);
93 /* Free data array if allocated */
94 if ( seg->datasamples )
95 free (seg->datasamples);
97 free (seg);
98 seg = nextseg;
101 /* Free private pointer data if present and requested*/
102 if ( freeprvtptr && id->prvtptr )
103 free (id->prvtptr);
105 free (id);
106 id = nextid;
109 free (*ppmstl);
111 *ppmstl = NULL;
114 return;
115 } /* End of mstl_free() */
118 /***************************************************************************
119 * mstl_addmsr:
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
131 * will be freed.
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 ***************************************************************************/
139 MSTraceSeg *
140 mstl_addmsr ( MSTraceList *mstl, MSRecord *msr, flag dataquality,
141 flag autoheal, double timetol, double sampratetol )
143 MSTraceID *id = 0;
144 MSTraceID *searchid = 0;
145 MSTraceID *ltid = 0;
147 MSTraceSeg *seg = 0;
148 MSTraceSeg *searchseg = 0;
149 MSTraceSeg *segbefore = 0;
150 MSTraceSeg *segafter = 0;
151 MSTraceSeg *followseg = 0;
153 hptime_t endtime;
154 hptime_t pregap;
155 hptime_t postgap;
156 hptime_t lastgap;
157 hptime_t firstgap;
158 hptime_t hpdelta;
159 hptime_t hptimetol = 0;
160 hptime_t nhptimetol = 0;
162 char srcname[45];
163 char *s1, *s2;
164 flag whence;
165 flag lastratecheck;
166 flag firstratecheck;
167 int mag;
168 int cmp;
169 int ltmag;
170 int ltcmp;
172 if ( ! mstl || ! msr )
173 return 0;
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");
179 return 0;
182 /* Generate source name string */
183 if ( ! msr_srcname (msr, srcname, dataquality) )
185 ms_log (2, "mstl_addmsr(): Error generating srcname for MSRecord\n");
186 return 0;
189 /* Search for matching trace ID starting with last accessed ID and
190 then looping through the trace ID list. */
191 if ( mstl->last )
193 s1 = mstl->last->srcname;
194 s2 = srcname;
195 while ( *s1 == *s2++ )
197 if ( *s1++ == '\0' )
198 break;
200 cmp = (*s1 - *--s2);
202 if ( ! cmp )
204 id = mstl->last;
206 else
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;
212 ltcmp = 0;
213 ltmag = 0;
214 while ( searchid )
216 /* Compare source names */
217 s1 = searchid->srcname;
218 s2 = srcname;
219 mag = 0;
220 while ( *s1 == *s2++ )
222 mag++;
223 if ( *s1++ == '\0' )
224 break;
226 cmp = (*s1 - *--s2);
228 /* If source names did not match track closest "less than" value
229 * and continue searching. */
230 if ( cmp != 0 )
232 if ( cmp < 0 )
234 if ( (ltcmp == 0 || cmp >= ltcmp) && mag >= ltmag )
236 ltcmp = cmp;
237 ltmag = mag;
238 ltid = searchid;
240 else if ( mag > ltmag )
242 ltcmp = cmp;
243 ltmag = mag;
244 ltid = searchid;
248 searchid = searchid->next;
249 continue;
252 /* If we made it this far we found a match */
253 id = searchid;
254 break;
257 } /* Done searching for match in trace ID list */
259 /* If no matching ID was found create new MSTraceID and MSTraceSeg entries */
260 if ( ! id )
262 if ( ! (id = (MSTraceID *) calloc (1, sizeof(MSTraceID))) )
264 ms_log (2, "mstl_addmsr(): Error allocating memory\n");
265 return 0;
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;
278 id->numsegments = 1;
280 if ( ! (seg = mstl_msr2seg (msr, endtime)) )
282 return 0;
284 id->first = id->last = seg;
286 /* Add new MSTraceID to MSTraceList */
287 if ( ! mstl->traces || ! ltid )
289 id->next = mstl->traces;
290 mstl->traces = id;
292 else
294 id->next = ltid->next;
295 ltid->next = id;
298 mstl->numtraces++;
300 /* Add data coverage to the matching MSTraceID */
301 else
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);
329 else
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) )
348 return 0;
350 seg = id->last;
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)) )
359 return 0;
361 /* Add to end of list */
362 id->last->next = seg;
363 seg->prev = id->last;
364 id->last = seg;
365 id->numsegments++;
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)) )
374 return 0;
376 /* Add to beginning of list */
377 id->first->prev = seg;
378 seg->next = id->first;
379 id->first = seg;
380 id->numsegments++;
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) )
389 return 0;
391 seg = id->first;
393 if ( msr->starttime < id->earliest )
394 id->earliest = msr->starttime;
396 /* Search complete segment list for matches */
397 else
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 */
403 while ( searchseg )
405 if ( msr->starttime > searchseg->starttime )
406 followseg = searchseg;
408 whence = 0;
410 postgap = msr->starttime - searchseg->endtime - hpdelta;
411 if ( ! segbefore && postgap <= hptimetol && postgap >= nhptimetol )
412 whence = 1;
414 pregap = searchseg->starttime - endtime - hpdelta;
415 if ( ! segafter && pregap <= hptimetol && pregap >= nhptimetol )
416 whence = 2;
418 if ( ! whence )
420 searchseg = searchseg->next;
421 continue;
424 if ( sampratetol == -1.0 )
426 if ( ! MS_ISRATETOLERABLE (msr->samprate, searchseg->samprate) )
428 searchseg = searchseg->next;
429 continue;
432 else
434 if ( ms_dabs (msr->samprate - searchseg->samprate) > sampratetol )
436 searchseg = searchseg->next;
437 continue;
441 if ( whence == 1 )
442 segbefore = searchseg;
443 else
444 segafter = searchseg;
446 /* Done searching if not autohealing */
447 if ( ! autoheal )
448 break;
450 /* Done searching if both before and after segments are found */
451 if ( segbefore && segafter )
452 break;
454 searchseg = searchseg->next;
455 } /* Done looping through segments */
457 /* Add MSRecord coverage to end of segment before */
458 if ( segbefore )
460 if ( ! mstl_addmsrtoseg (segbefore, msr, endtime, 1) )
462 return 0;
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) )
471 return 0;
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);
491 free (segafter);
494 seg = segbefore;
496 /* Add MSRecord coverage to beginning of segment after */
497 else if ( segafter )
499 if ( ! mstl_addmsrtoseg (segafter, msr, endtime, 2) )
501 return 0;
504 seg = segafter;
506 /* Add MSRecord coverage to new segment */
507 else
509 /* Create new segment */
510 if ( ! (seg = mstl_msr2seg (msr, endtime)) )
512 return 0;
515 /* Add new segment as first in list */
516 if ( ! followseg )
518 seg->next = id->first;
519 if ( id->first )
520 id->first->prev = seg;
522 id->first = seg;
524 /* Add new segment after the followseg segment */
525 else
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 )
534 id->last = seg;
537 id->numsegments++;
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;
556 if ( seg->prev )
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 )
572 id->last = seg;
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;
580 if ( seg->next )
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 )
593 id->first = seg;
595 if ( id->last == seg )
596 id->last = segbefore;
599 /* Set MSTraceID as last accessed */
600 mstl->last = id;
602 return seg;
603 } /* End of mstl_addmsr() */
606 /***************************************************************************
607 * mstl_msr2seg:
609 * Create an MSTraceSeg structure from an MSRecord structure.
611 * Return a pointer to a MSTraceSeg otherwise 0 on error.
612 ***************************************************************************/
613 MSTraceSeg *
614 mstl_msr2seg (MSRecord *msr, hptime_t endtime)
616 MSTraceSeg *seg = 0;
617 int samplesize;
619 if ( ! (seg = (MSTraceSeg *) calloc (1, sizeof(MSTraceSeg))) )
621 ms_log (2, "mstl_addmsr(): Error allocating memory\n");
622 return 0;
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");
641 return 0;
644 /* Copy data samples from MSRecord to MSTraceSeg */
645 memcpy (seg->datasamples, msr->datasamples, (size_t) (samplesize * msr->numsamples));
648 return seg;
649 } /* End of mstl_msr2seg() */
652 /***************************************************************************
653 * mstl_addmsrtoseg:
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 ***************************************************************************/
664 MSTraceSeg *
665 mstl_addmsrtoseg (MSTraceSeg *seg, MSRecord *msr, hptime_t endtime, flag whence)
667 int samplesize = 0;
668 void *newdatasamples;
670 if ( ! seg || ! msr )
671 return 0;
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);
680 return 0;
683 if ( ! (samplesize = ms_samplesize (msr->sampletype)) )
685 ms_log (2, "mstl_addmsrtoseg(): Unknown sample size for sample type: %c\n", msr->sampletype);
686 return 0;
689 if ( ! (newdatasamples = realloc (seg->datasamples, (size_t) ((seg->numsamples + msr->numsamples) * samplesize))) )
691 ms_log (2, "mstl_addmsrtoseg(): Error allocating memory\n");
692 return 0;
695 seg->datasamples = newdatasamples;
698 /* Add coverage to end of segment */
699 if ( whence == 1 )
701 seg->endtime = endtime;
702 seg->samplecnt += msr->samplecnt;
704 if ( msr->datasamples && msr->numsamples > 0 )
706 memcpy ((char *)seg->datasamples + (seg->numsamples * samplesize),
707 msr->datasamples,
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),
722 seg->datasamples,
723 (size_t) (seg->numsamples * samplesize));
725 memcpy (seg->datasamples,
726 msr->datasamples,
727 (size_t) (msr->numsamples * samplesize));
729 seg->numsamples += msr->numsamples;
732 else
734 ms_log (2, "mstl_addmsrtoseg(): unrecognized whence value: %d\n", whence);
735 return 0;
738 return seg;
739 } /* End of mstl_addmsrtoseg() */
742 /***************************************************************************
743 * mstl_addsegtoseg:
745 * Add data coverage from seg2 to seg1.
747 * Return a pointer to a seg1 otherwise 0 on error.
748 ***************************************************************************/
749 MSTraceSeg *
750 mstl_addsegtoseg (MSTraceSeg *seg1, MSTraceSeg *seg2)
752 int samplesize = 0;
753 void *newdatasamples;
755 if ( ! seg1 || ! seg2 )
756 return 0;
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);
765 return 0;
768 if ( ! (samplesize = ms_samplesize (seg1->sampletype)) )
770 ms_log (2, "mstl_addsegtoseg(): Unknown sample size for sample type: %c\n", seg1->sampletype);
771 return 0;
774 if ( ! (newdatasamples = realloc (seg1->datasamples, (size_t) ((seg1->numsamples + seg2->numsamples) * samplesize))) )
776 ms_log (2, "mstl_addsegtoseg(): Error allocating memory\n");
777 return 0;
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),
790 seg2->datasamples,
791 (size_t) (seg2->numsamples * samplesize));
793 seg1->numsamples += seg2->numsamples;
796 return seg1;
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
814 * error is returned.
816 * Returns 0 on success, and -1 on failure.
817 ***************************************************************************/
819 mstl_convertsamples ( MSTraceSeg *seg, char type, flag truncate )
821 int32_t *idata;
822 float *fdata;
823 double *ddata;
824 int64_t idx;
826 if ( ! seg )
827 return -1;
829 /* No conversion necessary, report success */
830 if ( seg->sampletype == type )
831 return 0;
833 if ( seg->sampletype == 'a' || type == 'a' )
835 ms_log (2, "mstl_convertsamples: cannot convert ASCII samples to/from numeric type\n");
836 return -1;
839 idata = (int32_t *) seg->datasamples;
840 fdata = (float *) seg->datasamples;
841 ddata = (double *) seg->datasamples;
843 /* Convert to 32-bit integers */
844 if ( type == 'i' )
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]));
855 return -1;
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]));
870 return -1;
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");
880 return -1;
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");
904 return -1;
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");
917 return -1;
920 if ( seg->sampletype == 'i' ) /* Convert integers to doubles */
922 for (idx = 0; idx < seg->numsamples; idx++)
923 ddata[idx] = (double) idata[idx];
925 free (idata);
927 else if ( seg->sampletype == 'f' ) /* Convert floats to doubles */
929 for (idx = 0; idx < seg->numsamples; idx++)
930 ddata[idx] = (double) fdata[idx];
932 free (fdata);
935 seg->datasamples = ddata;
936 seg->sampletype = 'd';
937 } /* Done converting to 64-bit doubles */
939 return 0;
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
953 * current trace.
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 ***************************************************************************/
960 void
961 mstl_printtracelist ( MSTraceList *mstl, flag timeformat,
962 flag details, flag gaps )
964 MSTraceID *id = 0;
965 MSTraceSeg *seg = 0;
966 char stime[30];
967 char etime[30];
968 char gapstr[20];
969 flag nogap;
970 double gap;
971 double delta;
972 int tracecnt = 0;
973 int segcnt = 0;
975 if ( ! mstl )
977 return;
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");
987 else
988 ms_log (0, " Source Start sample End sample\n");
990 /* Loop through trace list */
991 id = mstl->traces;
992 while ( id )
994 /* Loop through segment list */
995 seg = id->first;
996 while ( seg )
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);
1012 else
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 */
1022 if ( gaps > 0 )
1024 gap = 0.0;
1025 nogap = 0;
1027 if ( seg->prev )
1028 gap = (double) (seg->starttime - seg->prev->endtime) / HPTMODULUS;
1029 else
1030 nogap = 1;
1032 /* Check that any overlap is not larger than the trace coverage */
1033 if ( gap < 0.0 )
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 */
1042 if ( nogap )
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 ");
1050 else
1051 snprintf (gapstr, sizeof(gapstr), "%-4.4g", gap);
1053 if ( details <= 0 )
1054 ms_log (0, "%-17s %-24s %-24s %-4s\n",
1055 id->srcname, stime, etime, gapstr);
1056 else
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);
1063 else
1064 ms_log (0, "%-17s %-24s %-24s\n", id->srcname, stime, etime);
1066 segcnt++;
1067 seg = seg->next;
1070 tracecnt++;
1071 id = id->next;
1074 if ( tracecnt != mstl->numtraces )
1075 ms_log (2, "mstl_printtracelist(): number of traces in trace list is inconsistent\n");
1077 if ( details > 0 )
1078 ms_log (0, "Total: %d trace(s) with %d segment(s)\n", tracecnt, segcnt);
1080 return;
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
1094 * integer seconds.
1096 ***************************************************************************/
1097 void
1098 mstl_printsynclist ( MSTraceList *mstl, char *dccid, flag subsecond )
1100 MSTraceID *id = 0;
1101 MSTraceSeg *seg = 0;
1102 char starttime[30];
1103 char endtime[30];
1104 char yearday[10];
1105 time_t now;
1106 struct tm *nt;
1108 if ( ! mstl )
1110 return;
1113 /* Generate current time stamp */
1114 now = time (NULL);
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 */
1122 id = mstl->traces;
1123 while ( id )
1125 /* Loop through segment list */
1126 seg = id->first;
1127 while ( seg )
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,
1136 yearday);
1138 seg = seg->next;
1141 id = id->next;
1144 return;
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 ***************************************************************************/
1162 void
1163 mstl_printgaplist (MSTraceList *mstl, flag timeformat,
1164 double *mingap, double *maxgap)
1166 MSTraceID *id = 0;
1167 MSTraceSeg *seg = 0;
1169 char time1[30], time2[30];
1170 char gapstr[30];
1171 double gap;
1172 double delta;
1173 double nsamples;
1174 flag printflag;
1175 int gapcnt = 0;
1177 if ( ! mstl )
1178 return;
1180 if ( ! mstl->traces )
1181 return;
1183 ms_log (0, " Source Last Sample Next Sample Gap Samples\n");
1185 id = mstl->traces;
1186 while ( id )
1188 seg = id->first;
1189 while ( seg->next )
1191 /* Skip segments with 0 sample rate, usually from SOH records */
1192 if ( seg->samprate == 0.0 )
1194 seg = seg->next;
1195 continue;
1198 gap = (double) (seg->next->starttime - seg->endtime) / HPTMODULUS;
1200 /* Check that any overlap is not larger than the trace coverage */
1201 if ( gap < 0.0 )
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);
1209 printflag = 1;
1211 /* Check gap/overlap criteria */
1212 if ( mingap )
1213 if ( gap < *mingap )
1214 printflag = 0;
1216 if ( maxgap )
1217 if ( gap > *maxgap )
1218 printflag = 0;
1220 if ( printflag )
1222 nsamples = ms_dabs(gap) * seg->samprate;
1224 if ( gap > 0.0 )
1225 nsamples -= 1.0;
1226 else
1227 nsamples += 1.0;
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 ");
1236 else
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);
1253 else
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);
1265 gapcnt++;
1268 seg = seg->next;
1271 id = id->next;
1274 ms_log (0, "Total: %d gap(s)\n", gapcnt);
1276 return;
1277 } /* End of mstl_printgaplist() */