Main Page Class Hierarchy Compound List File List Compound Members File Members

# gseputaway.c

Go to the documentation of this file.

    00001 /******************************************************************
    00002  * gseputaway.c - routines to enable GSE data to be stored from
    00003  *                Earthworm
    00004  *
    00005  * S. Flower, Feb 2001
    00006  *
    00007  * Modified 11 Oct 2001 - instead of writing direct to the GSE
    00008  * file we write to a temporary file and rename it when it is
    00009  * complete - this ensures that the file can be read OK as soon
    00010  * as it is available.
    00011  *
    00012  * Modified 11 Oct 2001 - removed the check that all requested
    00013  * channels had been written - GSE can cope if there are missing
    00014  * channels and the check was deleting files if all channels were
    00015  * not present.
    00016  *
    00017  * Modified 26 Oct 2001 - fixed bug that puts gaps at wrong end
    00018  * of output traces
    00019  *
    00020  * Modified 31st Jan 2002 - new routines to make dealing with
    00021  * earthworm data structures easier to follow (pa_find_data())
    00022  ******************************************************************/
    00023
    00024 #include <stdio.h>
    00025 #include <time.h>
    00026 #include <stdlib.h>
    00027 #include <string.h>
    00028 #include <errno.h>
    00029 #include <math.h>
    00030 #if defined (_WINNT)
    00031 #include <process.h>
    00032 #include <io.h>
    00033 #endif
    00034
    00035 #include <sys/types.h>
    00036 #include <sys/stat.h>
    00037
    00038 #include "earthworm.h"
    00039 #include "earthworm_defs.h"
    00040 #include "trace_buf.h"
    00041 #include "swap.h"
    00042 #include "ws_clientII.h"
    00043 #include "site.h"
    00044 #include "time_ew.h"
    00045
    00046 #include "gsehead.h"
    00047 #include "seihead.h"
    00048
    00049
    00050 /* the value used to represent missing data in GSE */
    00051 #define GSE_MISSING_DATA_FLAG           0
    00052
    00053 /* private global variables */
    00054 static char *line_terminator;
    00055 static char *file_open_mode;
    00056 static char gse_filename [MAX_DIR_LEN];
    00057 static char tmp_filename [MAX_DIR_LEN];
    00058 static FILE *gse_fp;
    00059 static int new_data_channel;
    00060 static long channel_checksum = 0l;
    00061 static int data_line_length;
    00062 static int n_channels, channels_written;
    00063
    00064 /* private forward declarations */
    00065 static int open_gse_file (char *filename, char *msg_id, char *sta_code);
    00066 static int write_gse_channel_header (int start_year, int start_month, int start_day,
    00067                                      int start_hour, int start_min, double start_sec,
    00068                                      char *chan_name, char *chan_type, char *aux_id,
    00069                                      long n_samps,
    00070                                      double frequency, double calib_value,
    00071                                      double calib_period, char *instrum_name,
    00072                                      double horiz_angle, double vert_angle);
    00073 static int write_gse_channel_data (int n_samps, long *data);
    00074 static int write_gse_channel_trailer (void);
    00075 static int close_gse_file (void);
    00076
    00077
    00078
    00079 /**********************************************************************
    00080  * GSEPA_init
    00081  *
    00082  * Description: initialise GSE put away routines
    00083  *
    00084  * Input parameters: output_dir - the directory to be used for GSE
    00085  *                                output files
    00086  *                   output_format - "intel" or "sparc" for line termination
    00087  *                   debug - flag for debugging output
    00088  * Output parameters: none
    00089  * Returns: EW_SUCCESS or EW_FAILURE
    00090  *
    00091  * Comments:
    00092  *
    00093  ***********************************************************************/
    00094 int GSEPA_init (char *output_dir, char *output_format, int debug)
    00095
    00096 {
    00097
    00098   if (debug)
    00099   {
    00100     logit ("e", "Entering GSEPA_init, output dir: %s\n", output_dir);
    00101   }
    00102
    00103   /* make sure that the output directory exists */
    00104   if (CreateDir (output_dir) != EW_SUCCESS)
    00105   {
    00106     logit ("e", "GSEPA_init: Call to CreateDir failed\n");
    00107     return EW_FAILURE;
    00108   }
    00109
    00110 #if defined (_INTEL)
    00111   if (! strcmp (output_format, "intel"))
    00112   {
    00113     line_terminator = "\n";
    00114     file_open_mode = "w";
    00115   }
    00116   else if (! strcmp (output_format, "sparc"))
    00117   {
    00118     line_terminator = "\n";
    00119     file_open_mode = "wb";
    00120   }
    00121   else
    00122   {
    00123     logit ("e", "GSEPA_init: can't recognise OutputFormat (%s)\n", output_format);
    00124     return EW_FAILURE;
    00125   }
    00126 #elif defined (_SPARC)
    00127   if (! strcmp (output_format, "sparc"))
    00128   {
    00129     line_terminator = "\n";
    00130     file_open_mode = "w";
    00131   }
    00132   else if (! strcmp (output_format, "intel"))
    00133   {
    00134     line_terminator = "\r\n";
    00135     file_open_mode = "wb";
    00136   }
    00137   else
    00138   {
    00139     logit ("e", "SEIPA_init: can't recognise OutputFormat (%s)\n", output_format);
    00140     return EW_FAILURE;
    00141   }
    00142 #else
    00143 #error "_INTEL or _SPARC must be set before compiling"
    00144 #endif
    00145
    00146   return EW_SUCCESS;
    00147
    00148 }
    00149
    00150 /****************************************************************************
    00151  * GSEPA_next_ev
    00152  *
    00153  * Description: called when a snippet has been received,
    00154  *              before it is processed
    00155  *
    00156  * Input parameters: trace_req - array of trace reqeust structures
    00157  *                   n_reqs - size of array
    00158  *                   output_dir - output directory
    00159  *                   e_date, e_time - event time in the form
    00160  *                                    'ccyymmdd' and 'hhmmss.ff'
    00161  *                   debug - flag for debugging output
    00162  * Output parameters: none
    00163  * Returns: EW_SUCCESS or EW_FAILURE
    00164  *
    00165  * Comments:
    00166  *
    00167  ***********************************************************************/
    00168 int GSEPA_next_ev (TRACE_REQ *trace_req, int n_reqs, char *output_dir,
    00169                    char *e_date, char *e_time, int debug)
    00170 {
    00171
    00172   int event_year, event_month, event_day, event_hour, event_min;
    00173   double event_sec;
    00174   char string [100];
    00175   TRACE_HEADER *trace_hdr;
    00176
    00177   static int tmp_file_count = 0;
    00178
    00179
    00180   if (debug)
    00181   {
    00182     logit ("e", "Entering GSEPA_next_ev, date/time: %s %s\n", e_date, e_time);
    00183   }
    00184
    00185   /* parse and store the date/time - we assume that it doesn't need to
    00186    * be checked for validity - I don't know if that is correct */
    00187   strcpy (string, e_date);
    00188   event_day = atoi (&string[6]);
    00189   string[6] = '\0';
    00190   event_month = atoi (&string[4]);
    00191   string[4] = '\0';
    00192   event_year = atoi (string);
    00193   strcpy (string, e_time);
    00194   event_sec = atof (&string[4]);
    00195   string[4] = '\0';
    00196   event_min = atoi (&string[2]);
    00197   string[2] = '\0';
    00198   event_hour = atoi (string);
    00199
    00200   /* use the temporary file as the output file - we will rename it to the proper GSE file name
    00201    * when it is complete and closed */
    00202   sprintf (tmp_filename, "%s%c%d_%d_gse.tmp",
    00203            output_dir, DIR_DELIM, getpid (), tmp_file_count ++);
    00204   sprintf (gse_filename, "%s%c%04d_%02d_%02d_%02d_%02d_%02.0f.gse",
    00205            output_dir, DIR_DELIM, event_year, event_month, event_day,
    00206            event_hour, event_min, event_sec);
    00207
    00208   /* open the GSE file */
    00209   trace_hdr = (TRACE_HEADER *) trace_req->pBuf;
    00210   if (! open_gse_file (tmp_filename, "EW", trace_req->net))
    00211   {
    00212     logit ("e", "GSEPA_init: unable to open GSE output file\n");
    00213     return EW_FAILURE;
    00214   }
    00215
    00216   /* store tracking information */
    00217   n_channels = n_reqs;
    00218   channels_written = 0;
    00219
    00220   return EW_SUCCESS;
    00221
    00222 }
    00223
    00224 /*****************************************************************************
    00225  * GSEPA_next
    00226  *
    00227  * Description: called once for each trace to be put away
    00228  *
    00229  * Input parameters: trace_req - the data to be stored
    00230  *                   gap_thresh - size of any gap in seconds
    00231  *                   debug - flag for debugging output
    00232  * Output parameters: none
    00233  * Returns: EW_SUCCESS or EW_FAILURE
    00234  *
    00235  * Comments: see pa_find_data()
    00236  *
    00237  *****************************************************************************/
    00238 int GSEPA_next (TRACE_REQ *trace_req, double gap_thresh, int debug)
    00239
    00240 {
    00241
    00242   int status, loop_count;
    00243   short short_val;
    00244   long value, count;
    00245   float float_val;
    00246   double sample_time, double_val, data_end_time;
    00247   char *data_ptr;
    00248   struct Found_data data;
    00249   time_t ltime;
    00250   struct tm unix_time;
    00251
    00252
    00253   if (debug) logit ("e", "Entering GSEPA_next\n");
    00254
    00255   /* loop over the requested times for the data - the test for n_samples==0
    00256    * is an emergency condition that could happen with very bad floating point
    00257    * rounding errors (very unlikely though) */
    00258   data.n_samples = 1;
    00259   for (sample_time = trace_req->reqStarttime, loop_count = 0;
    00260        (sample_time < trace_req->reqEndtime) && (data.n_samples > 0);
    00261            sample_time += ((double) data.n_samples / data.sample_rate), loop_count ++)
    00262   {
    00263     /* get the data for this time */
    00264     status = pa_find_data (trace_req, sample_time, &data);
    00265     switch (status)
    00266         {
    00267     case FD_FOUND_REQUESTED:
    00268     case FD_FOUND_GAP:
    00269           break;
    00270     case FD_NO_MORE_DATA:
    00271       /* if no data has been found on previous calls, then exit
    00272            * so that no data will be recorded for this channel */
    00273           if (sample_time == trace_req->reqStarttime) return EW_SUCCESS;
    00274
    00275           /* otherwise calculate the size of the gap to the end of requested data */
    00276           data.n_samples = (long) (data.sample_rate * (trace_req->reqEndtime - sample_time));
    00277           break;
    00278
    00279     case FD_BAD_DATATYPE:
    00280       logit("e", "GSEPA_next: unrecognised data type code, skipping this scn: %s.%s.%s\n",
    00281             trace_req->sta, trace_req->chan, trace_req->net);
    00282       return EW_FAILURE;
    00283
    00284     case FD_CHANGED_SRATE:
    00285       logit("e", "GSEPA_next: bad sample rate, skipping this scn: %s.%s.%s\n",
    00286             trace_req->sta, trace_req->chan, trace_req->net);
    00287       return EW_FAILURE;
    00288         }
    00289
    00290     /* adjust the number of samples to ensure it doesn't go beyond the end time */
    00291         data_end_time = sample_time + ((double) data.n_samples / data.sample_rate);
    00292         if (data_end_time > trace_req->reqEndtime)
    00293           data.n_samples = (long) (data.sample_rate * (trace_req->reqEndtime - sample_time));
    00294     if (debug) logit ("e", "Loop %d: %s %ld @ %.1lfHz, time %.3lf\n",
    00295                       loop_count, status == FD_FOUND_REQUESTED ? "samples" : "gap",
    00296                                           data.n_samples, data.sample_rate, sample_time);
    00297
    00298     /* on the first time write the gse channel header */
    00299     if (sample_time == trace_req->reqStarttime)
    00300         {
    00301       ltime = (time_t) sample_time;
    00302       gmtime_ew (&ltime, &unix_time);
    00303       if (! write_gse_channel_header (unix_time.tm_year + 1900, unix_time.tm_mon +1,
    00304                                       unix_time.tm_mday, unix_time.tm_hour, unix_time.tm_min,
    00305                                       ((double) unix_time.tm_sec) + (sample_time - (double) ltime),
    00306                                       trace_req->sta, trace_req->chan, "-",
    00307                                       (long) (data.sample_rate * (trace_req->reqEndtime - trace_req->reqStarttime)),
    00308                                                                       data.sample_rate, -1.0, -1.0, "-", -1.0, -1.0))
    00309           {
    00310         logit ("e", "GSEPA_next: error starting new GSE channel\n");
    00311         return EW_FAILURE;
    00312           }
    00313         }
    00314
    00315         /* write the data */
    00316         value = GSE_MISSING_DATA_FLAG;
    00317         data_ptr = data.data;
    00318         for (count=0; count<data.n_samples; count++)
    00319         {
    00320           if (status == FD_FOUND_REQUESTED)
    00321           {
    00322                 switch (data.data_type_code)
    00323                 {
    00324                 case FD_SHORT_INT:
    00325                   short_val = *((short *) data_ptr);
    00326           value = (long) short_val;
    00327                   data_ptr += sizeof (short);
    00328                   break;
    00329                 case FD_LONG_INT:
    00330                   value = *((long *) data_ptr);
    00331                   data_ptr += sizeof (long);
    00332                   break;
    00333                 case FD_FLOAT:
    00334                   float_val = *((float *) data_ptr);
    00335           value = (long) float_val;
    00336                   data_ptr += sizeof (float);
    00337                   break;
    00338                 case FD_DOUBLE:
    00339                   double_val = *((double *) data_ptr);
    00340           value = (long) double_val;
    00341                   data_ptr += sizeof (double);
    00342                   break;
    00343                 }
    00344           }
    00345       write_gse_channel_data (1, &value);
    00346         }
    00347   }
    00348
    00349   /* stop writing on this channel and fill in any gap at the end of the data */
    00350   write_gse_channel_trailer ();
    00351
    00352   if (debug)
    00353   {
    00354     logit ("e", "Successful completion of GSEPA_next\n");
    00355   }
    00356   return EW_SUCCESS;
    00357
    00358 }
    00359
    00360 /************************************************************************
    00361  * GSEPA_end_ev
    00362  *
    00363  * Description: called when an event has been completely processed
    00364  *
    00365  * Input parameters: debug - flag for debugging output
    00366  * Output parameters: none
    00367  * Returns: EW_SUCCESS or EW_FAILURE
    00368  *
    00369  * Comments:
    00370  *
    00371  *****************************************************************************/
    00372 int GSEPA_end_ev (int debug)
    00373
    00374 {
    00375
    00376   int ret_val;
    00377
    00378
    00379   ret_val = EW_SUCCESS;
    00380
    00381   /* check and close the GSE file */
    00382   if (! close_gse_file ())
    00383   {
    00384     logit ("e", "GSEPA_end_ev: error writing to GSE file\n");
    00385     ret_val = EW_FAILURE;
    00386   }
    00387
    00388   /* rename the temporary file to the proper GSE file name - the return value from
    00389    * rename_ew() doesn't appear reliable, so check for the existence of the renamed
    00390    * file after the rename operation */
    00391   if (ret_val == EW_SUCCESS)
    00392   {
    00393     rename_ew (tmp_filename, gse_filename);
    00394     if (access (gse_filename, 0))
    00395     {
    00396       logit ("e", "GSEPA_end_ev: unable to rename file (%s) to (%s)\n", tmp_filename, gse_filename);
    00397       ret_val = EW_FAILURE;
    00398     }
    00399   }
    00400
    00401   /* if there was an error, delete the file */
    00402   if (ret_val != EW_SUCCESS)
    00403   {
    00404     logit ("e", "GSEPA_end_ev: output file is being deleted (%s)\n", tmp_filename);
    00405     remove (tmp_filename);
    00406   }
    00407
    00408   return ret_val;
    00409
    00410 }
    00411
    00412 /************************************************************************
    00413  * GSEPA_close
    00414  *
    00415  * Description: called at program shutdown
    00416  *
    00417  * Input parameters: debug - flag for debugging output
    00418  * Output parameters: none
    00419  * Returns: EW_SUCCESS or EW_FAILURE
    00420  *
    00421  * Comments:
    00422  *
    00423  *****************************************************************************/
    00424 int GSEPA_close (int debug)
    00425 {
    00426
    00427   if (debug)
    00428   {
    00429     logit ("e", "Entering GSEPA_close: \n");
    00430   }
    00431
    00432   return EW_SUCCESS;
    00433
    00434 }
    00435
    00436
    00437 /************************************************************************
    00438  ************************************************************************
    00439  * All code below this point is private to this file
    00440  ************************************************************************
    00441  ************************************************************************/
    00442
    00443 /************************************************************************
    00444  * open_gse_file
    00445  *
    00446  * Description: open a GSE file and write the main header for the file
    00447  *
    00448  * Input parameters: filename - the file to write
    00449  *                   msg_id - the message id
    00450  *                   sta_code - the station code
    00451  * Output parameters: none
    00452  * Returns: TRUE if file written OK, FALSE otherwise
    00453  *
    00454  * Comments:
    00455  *
    00456  ************************************************************************/
    00457 static int open_gse_file (char *filename, char *msg_id, char *sta_code)
    00458
    00459 {
    00460
    00461   /* attempt to open the file */
    00462   gse_fp = fopen (filename, file_open_mode);
    00463   if (! gse_fp) return FALSE;
    00464
    00465   /* write the GSE header */
    00466   fprintf (gse_fp, "BEGIN GSE2.0%s", line_terminator);
    00467   fprintf (gse_fp, "MSG_TYPE DATA%s", line_terminator);
    00468   fprintf (gse_fp, "MSG_ID %s %s%s", msg_id, sta_code, line_terminator);
    00469   fprintf (gse_fp, "DATA_TYPE WAVEFORM GSE2.0%s", line_terminator);
    00470
    00471   /* check the file */
    00472   if (ferror (gse_fp)) return FALSE;
    00473   return TRUE;
    00474
    00475 }
    00476
    00477 /************************************************************************
    00478  * write_gse_channel_header
    00479  *
    00480  * Description: write a GSE channel header
    00481  *
    00482  * Input parameters: start_year, month, day - the date of the data
    00483  *                   start_hour, min, sec - the time of the data
    00484  *                   chan_name, type - the channel name and type
    00485  *                                     (e.g. EKR1, SZ)
    00486  *                   aux_id - auxiliary identification code
    00487  *                   n_samps - number of samples in the following data block
    00488  *                   frequency - the recording frequency (hz)
    00489  *                   calib_value, calib_period - calibration details
    00490  *                   instrum_name - GSE code for the sensor type
    00491  *                   horiz_angle, vert_angle - sensor orientation
    00492  * Output parameters: none
    00493  * Returns: TRUE if file written OK, FALSE otherwise
    00494  *
    00495  * Comments:
    00496  *
    00497  ************************************************************************/
    00498 static int write_gse_channel_header (int start_year, int start_month, int start_day,
    00499                                      int start_hour, int start_min, double start_sec,
    00500                                      char *chan_name, char *chan_type, char *aux_id,
    00501                                      long n_samps,
    00502                                      double frequency, double calib_value,
    00503                                      double calib_period, char *instrum_name,
    00504                                      double horiz_angle, double vert_angle)
    00505
    00506 {
    00507
    00508   /* write the header for this channel */
    00509   fprintf (gse_fp, "WID2 %04d/%02d/%02d %02d:%02d:%06.3lf %-5.5s %-3.3s "
    00510                "%-4.4s INT %8ld %11.6lf %10.2le %7.3lf %-6.6s %5.1lf %4.1lf%s",
    00511            start_year, start_month, start_day, start_hour, start_min, start_sec,
    00512            chan_name, chan_type, aux_id, n_samps, frequency, calib_value,
    00513            calib_period, instrum_name, horiz_angle, vert_angle, line_terminator);
    00514   fprintf (gse_fp, "DAT2%s", line_terminator);
    00515
    00516   /* flag write_gse_channel_data to expect a new channel */
    00517   new_data_channel = TRUE;
    00518
    00519   /* check the file */
    00520   if (ferror (gse_fp)) return FALSE;
    00521   return TRUE;
    00522
    00523 }
    00524
    00525 /************************************************************************
    00526  * write_gse_channel_data
    00527  *
    00528  * Description: write channel data in GSE format
    00529  *
    00530  * Input parameters: n_samps - the number of samples to write
    00531  *                   data - the data to write
    00532  * Output parameters: none
    00533  * Returns: TRUE if file written OK, FALSE otherwise
    00534  *
    00535  * Comments: This routine may be called more than once if all the data
    00536  *           is not available at one go - the total number of samples
    00537  *           written must equal to number of samples declared in the header
    00538  *
    00539  ************************************************************************/
    00540 static int write_gse_channel_data (int n_samps, long *data)
    00541
    00542 {
    00543
    00544   int count, length;
    00545   long value;
    00546   char string [100];
    00547
    00548   static long modulo = 100000000;
    00549
    00550
    00551   /* if this is the start of a new channel, reset the sample
    00552    * counter and the checksum */
    00553   if (new_data_channel)
    00554   {
    00555     data_line_length = 0;
    00556     new_data_channel = FALSE;
    00557     channel_checksum = 0l;
    00558   }
    00559
    00560   /* for each data sample ... */
    00561   for (count=0; count<n_samps; count++)
    00562   {
    00563     /* format the sample, checking for missing data */
    00564     value = *(data + count);
    00565     sprintf (string, "%ld", value);
    00566
    00567     /* write the sample using an 80 char. line length */
    00568     length = strlen (string);
    00569     if ((length + data_line_length +1) > 80)
    00570     {
    00571       fprintf (gse_fp, "%s", line_terminator);
    00572       data_line_length = 0;
    00573     }
    00574     if (data_line_length > 0)
    00575     {
    00576       fprintf (gse_fp, " ");
    00577       data_line_length ++;
    00578     }
    00579     fprintf (gse_fp, string);
    00580     data_line_length += length;
    00581
    00582     /* accumulate the checksum */
    00583     if (labs (value) >= modulo) value -= (value / modulo) * modulo;
    00584     channel_checksum += value;
    00585     if (labs (channel_checksum) >= modulo)
    00586       channel_checksum -= (channel_checksum / modulo) * modulo;
    00587   }
    00588
    00589   /* check the file */
    00590   if (ferror (gse_fp)) return FALSE;
    00591   return TRUE;
    00592
    00593 }
    00594
    00595 /************************************************************************
    00596  * write_gse_channel_trailer
    00597  *
    00598  * Description: write trailer info. for a channel
    00599  *
    00600  * Input parameters: none
    00601  * Output parameters: none
    00602  * Returns: TRUE if file written OK, FALSE otherwise
    00603  *
    00604  * Comments:
    00605  *
    00606  ************************************************************************/
    00607 static int write_gse_channel_trailer (void)
    00608
    00609 {
    00610
    00611   /* write the checksum for this channel */
    00612   if (data_line_length > 0)
    00613   {
    00614     fprintf (gse_fp, "%s", line_terminator);
    00615     data_line_length = 0;
    00616   }
    00617   fprintf (gse_fp, "CHK2 %d%s", abs (channel_checksum), line_terminator);
    00618
    00619   /* check the file */
    00620   if (ferror (gse_fp)) return FALSE;
    00621   return TRUE;
    00622
    00623 }
    00624
    00625 /************************************************************************
    00626  * close_gse_file
    00627  *
    00628  * Description: write trailer info. for a file and close it
    00629  *
    00630  * Input parameters: none
    00631  * Output parameters: none
    00632  * Returns: TRUE if file written OK, FALSE otherwise
    00633  *
    00634  * Comments:
    00635  *
    00636  ************************************************************************/
    00637 static int close_gse_file (void)
    00638
    00639 {
    00640
    00641   int ret_val;
    00642
    00643
    00644   /* write the GSE trailer */
    00645   fprintf (gse_fp, "STOP%s", line_terminator);
    00646
    00647   /* check the file */
    00648   if (ferror (gse_fp)) ret_val = FALSE;
    00649   else ret_val = TRUE;
    00650
    00651   /* close it and return */
    00652   fclose (gse_fp);
    00653   return ret_val;
    00654
    00655 }
    00656
    00657
    00658