1 | /* |
---|
2 | * |
---|
3 | * Based on SUDS putaway and Geomag WDC putaway. |
---|
4 | * For Erol Kalcan |
---|
5 | * |
---|
6 | */ |
---|
7 | |
---|
8 | /* cosmos0putaway.c |
---|
9 | |
---|
10 | Routines for writing trace data in COSMOS V0 format. |
---|
11 | |
---|
12 | Volume 0 files have raw data values in digital counts, obtained directly from the native binary files of |
---|
13 | the recording instrument. (Records obtained by digitizing analog film generally do not have a V0 |
---|
14 | file.) V0 files may have almost no quality control or checking, and so they may be treated as internal |
---|
15 | files by networks. V0 files have adequate information in the headers to be converted to files with |
---|
16 | physical values. There is one component per file, so one record obtained by a triaxial recorder will |
---|
17 | result in three files. |
---|
18 | |
---|
19 | Header information is populated by a database of files. We don't need to know |
---|
20 | about it after we use the SCNL to find the right file and prepend it. |
---|
21 | |
---|
22 | Count data is extracted from a wave server: |
---|
23 | |
---|
24 | Data Section: |
---|
25 | The first line of the data section includes the type of data (accel., velocity, displ., etc.) and its |
---|
26 | units, the number of data points, and the format to be used in reading the data. The format |
---|
27 | will type be for integer or real values, as appropriate; the format for real values can be |
---|
28 | floating point (e.g., 8f10.5) or exponential (e.g., 5e16.7). Although not required, 80-character |
---|
29 | line lengths are most convenient for many engineering strong motion data users. |
---|
30 | The first line is followed by as many lines of data as are needed to accommodate the number |
---|
31 | of points, given the format in which the data values are written. |
---|
32 | |
---|
33 | In our case we'll alway use units=counts, and interger Format=(10I8): |
---|
34 | First line example followed by a data line. |
---|
35 | 17629 raw accel. pts, approx 176 secs, units=counts (50),Format=(10I8) |
---|
36 | -28596 -28611 -28630 -28617 -28609 -28550 -28543 -28654 -28698 -28661 |
---|
37 | |
---|
38 | */ |
---|
39 | |
---|
40 | #include <errno.h> |
---|
41 | #include <limits.h> |
---|
42 | #include <stdio.h> |
---|
43 | #include <stdlib.h> |
---|
44 | #include <string.h> |
---|
45 | #include <time.h> |
---|
46 | |
---|
47 | #include "earthworm.h" |
---|
48 | #include "trace_buf.h" |
---|
49 | #include "swap.h" |
---|
50 | #include "ws_clientII.h" |
---|
51 | #include "cosmos0head.h" |
---|
52 | #include "cosmos0putaway.h" |
---|
53 | #include "pa_subs.h" |
---|
54 | #include "earthworm_simple_funcs.h" |
---|
55 | #include "chron3.h" |
---|
56 | |
---|
57 | |
---|
58 | |
---|
59 | |
---|
60 | // just testing |
---|
61 | // sprintf(global_outputdir, "e:\earthworm\memphis\data\database_v0"); |
---|
62 | |
---|
63 | |
---|
64 | |
---|
65 | static long *COSMOS0Buffer; /* write out COSMOS0 data as long integers */ |
---|
66 | static char COSMOS0OutputFormat[MAXTXT]; |
---|
67 | static long LineMean; /* average of the 60 samples in the line */ |
---|
68 | |
---|
69 | |
---|
70 | |
---|
71 | /* Internal Function Prototypes */ |
---|
72 | static int StructMakeLocal(void *, int, char, int); |
---|
73 | /************************************************************************ |
---|
74 | * Initialization function, * |
---|
75 | * This is the Put Away startup intializer. This is called when * |
---|
76 | * the system first comes up. Here is a chance to look around * |
---|
77 | * and see if it's possible to do business, and to complain * |
---|
78 | * if not ,BEFORE an event has to be processed. * |
---|
79 | * * |
---|
80 | * For COSMOS0, all we want to do is to make sure that the * |
---|
81 | * directory where files should be written exists. * |
---|
82 | *************************************************************************/ |
---|
83 | int COSMOS0PA_init(int OutBufferLen, char *OutDir, char *OutputFormat, |
---|
84 | int debug) |
---|
85 | { |
---|
86 | /** Allocate COSMOS0Buffer and COSMOS0BufferShort |
---|
87 | We waste RAM by allocating both the long and short buffers here |
---|
88 | at the beginning of the code because some fluke (feature?) of NT |
---|
89 | which I don't understand becomes unhappy if we do the allocation |
---|
90 | later. Win2000, of course, behaves differently, and is quite happy |
---|
91 | with buffer allocation after we have determined the format of the |
---|
92 | incoming data */ |
---|
93 | if ((COSMOS0Buffer = (long *)malloc(OutBufferLen * sizeof(char))) == NULL) |
---|
94 | { |
---|
95 | logit("et", "COSMOS0PA_init: couldn't malloc COSMOS0Buffer\n"); |
---|
96 | return EW_FAILURE; |
---|
97 | } |
---|
98 | |
---|
99 | /* Make sure that the top level output directory exists */ |
---|
100 | if (RecursiveCreateDir(OutDir) != EW_SUCCESS) |
---|
101 | { |
---|
102 | logit("e", "COSMOS0PA_init: Call to RecursiveCreateDir failed\n"); |
---|
103 | return EW_FAILURE; |
---|
104 | } |
---|
105 | |
---|
106 | if (strlen(OutputFormat) >= sizeof(COSMOS0OutputFormat)) |
---|
107 | { |
---|
108 | logit("", "COSMOS0PA_init: Error: OutputFormat(%s) is too long! Quitting!\n", |
---|
109 | OutputFormat); |
---|
110 | return(EW_FAILURE); |
---|
111 | } |
---|
112 | else |
---|
113 | { |
---|
114 | strcpy(COSMOS0OutputFormat, OutputFormat); |
---|
115 | } |
---|
116 | return EW_SUCCESS; |
---|
117 | } |
---|
118 | |
---|
119 | /************************************************************************ |
---|
120 | * This is the Put Away event initializer. It's called when a snippet * |
---|
121 | * has been received, and is about to be processed. * |
---|
122 | * It gets to see the pointer to the TraceRequest array, * |
---|
123 | * and the number of loaded trace structures. * |
---|
124 | * * |
---|
125 | * We need to make sure that the target directory * |
---|
126 | * exists, create it if it does not, then open the COSMOS0 file * |
---|
127 | * for writing. * |
---|
128 | * * |
---|
129 | * This also opens the library file, and writes its contents to our * |
---|
130 | * output file * |
---|
131 | *************************************************************************/ |
---|
132 | int COSMOS0PA_next_ev(TRACE_REQ *ptrReq, |
---|
133 | char *OutDir, char *LibDir, char *EventDate, char *EventTime, |
---|
134 | int cadence, int debug, double Multiplier) |
---|
135 | |
---|
136 | { |
---|
137 | char COSMOS0File[4 * MAXTXT]; |
---|
138 | char COSMOS0LibFile[4 * MAXTXT]; |
---|
139 | char EventArcFile[4 * MAXTXT]; |
---|
140 | /* char c; */ |
---|
141 | char year[5]; |
---|
142 | char yr[3]; |
---|
143 | char mo[3]; |
---|
144 | char dy[3]; |
---|
145 | char hr[3]; |
---|
146 | char mn[3]; |
---|
147 | char sec[7]; |
---|
148 | char cos_date[35]; /* Start date of data requested */ |
---|
149 | char record_id[35]; |
---|
150 | char str[COSMOSLINELEN]; |
---|
151 | char tempstr[COSMOSLINELEN]; |
---|
152 | char tempstr2[COSMOSLINELEN]; |
---|
153 | int LineNumber = 0; |
---|
154 | time_t rawtime; |
---|
155 | struct tm * timeinfo; |
---|
156 | size_t nfbuffer; /* Read bytes */ |
---|
157 | char *fbuffer; /* File read buffer */ |
---|
158 | static long MaxMessageSize = 100000; /* size (bytes) of largest msg */ |
---|
159 | HypoArc arcmsg; /* ARC message */ |
---|
160 | char timestr[80]; /* Holds time messages */ |
---|
161 | time_t ot; |
---|
162 | struct tm * (*timefunc)(const time_t *); |
---|
163 | char time_type[30] = { 0 }; /* Time type UTC or local */ |
---|
164 | |
---|
165 | |
---|
166 | /* Grab the date-related substrings that we need for filenames. */ |
---|
167 | strncpy(year, EventDate, 4); |
---|
168 | year[4] = '\0'; |
---|
169 | strncpy(yr, EventDate + 2, 2); |
---|
170 | yr[2] = '\0'; |
---|
171 | strncpy(mo, EventDate + 4, 2); |
---|
172 | mo[2] = '\0'; |
---|
173 | strncpy(dy, EventDate + 6, 2); |
---|
174 | dy[2] = '\0'; |
---|
175 | |
---|
176 | strncpy(hr, EventTime, 2); |
---|
177 | hr[2] = '\0'; |
---|
178 | strncpy(mn, EventTime + 2, 2); |
---|
179 | mn[2] = '\0'; |
---|
180 | strncpy(sec, EventTime + 4, 5); |
---|
181 | sec[5] = '\0'; |
---|
182 | |
---|
183 | cos_date[34] = '\0'; |
---|
184 | record_id[34] = '\0'; |
---|
185 | tempstr[0]='\0'; |
---|
186 | |
---|
187 | |
---|
188 | sprintf(COSMOS0File, "%s/%s%s%s%s.v0", OutDir, |
---|
189 | ptrReq->sta, yr, mo, dy); |
---|
190 | |
---|
191 | /* cos_date "06/17/2018, 18:34:38.004 GMT (Q=5) "<-35 chars; Q stands for Quality, we have no way to know that */ |
---|
192 | sprintf(cos_date, "%s/%s/%s, %s:%s:%s UTC", mo, dy, year, hr, mn, sec); |
---|
193 | |
---|
194 | RecursiveCreateDir(OutDir); |
---|
195 | sprintf(COSMOS0LibFile, "%s/%s_%s_%s_%s.dlv0", |
---|
196 | LibDir, ptrReq->net, ptrReq->sta, ptrReq->loc, ptrReq->chan); |
---|
197 | |
---|
198 | if (debug == 1) |
---|
199 | logit("t", "Opening COSMOS0 library file header %s\n", COSMOS0LibFile); |
---|
200 | |
---|
201 | /* open library file just for reading */ |
---|
202 | if ((COSMOS0Libfp = fopen(COSMOS0LibFile, "r")) == NULL) |
---|
203 | { |
---|
204 | logit("e", "COSMOS0PA_next_ev: unable to open file %s: %s\n", |
---|
205 | COSMOS0LibFile, strerror(errno)); |
---|
206 | return EW_FAILURE; |
---|
207 | } |
---|
208 | |
---|
209 | if (debug == 1) |
---|
210 | logit("et", "Opening COSMOS0 file %s\n", COSMOS0File); |
---|
211 | |
---|
212 | /* open file */ |
---|
213 | if ((COSMOS0fp = fopen(COSMOS0File, "wt")) == NULL) |
---|
214 | { |
---|
215 | logit("e", "COSMOS0PA_next_ev: unable to open file %s: %s\n", |
---|
216 | COSMOS0File, strerror(errno)); |
---|
217 | return EW_FAILURE; |
---|
218 | } |
---|
219 | /* If there's enough time to implement, this filename should be able to be specified in the dot D file. */ |
---|
220 | sprintf(EventArcFile, "%s/event.arc", LibDir); |
---|
221 | if (debug == 1) |
---|
222 | logit("t", "Attempting to open event file which always must be named event.arc and located in the LibraryDirectory. \n LibraryDirectory is currently configured as: %s\n", LibDir); |
---|
223 | |
---|
224 | /* open Event file just for reading */ |
---|
225 | if ((EVENTARCfp = fopen(EventArcFile, "r")) == NULL) |
---|
226 | { |
---|
227 | logit("e", "COSMOS0PA_next_ev: unable to open file %s: %s\nAn .arc file is required to set event information in the COSMOS file format.", |
---|
228 | EventArcFile, strerror(errno)); |
---|
229 | return EW_FAILURE; |
---|
230 | } |
---|
231 | |
---|
232 | /* Read file to buffer |
---|
233 | *********************/ |
---|
234 | fbuffer = (char*)malloc(sizeof(char) * MaxMessageSize); /*check logic*/ |
---|
235 | if (fbuffer == NULL) |
---|
236 | { |
---|
237 | logit("et", "Unable to allocate memory for filter buffer\n"); |
---|
238 | return -1; |
---|
239 | } |
---|
240 | |
---|
241 | nfbuffer = fread(fbuffer, sizeof(char), |
---|
242 | (size_t)MaxMessageSize, EVENTARCfp); |
---|
243 | fclose(EVENTARCfp); // Done reading |
---|
244 | if (nfbuffer == 0) |
---|
245 | { |
---|
246 | logit( "eto", "COSMOS0PA_next_ev: No data read from %s\n\nAn .arc file is required to set event information in the COSMOS file format.", |
---|
247 | EventArcFile); |
---|
248 | return EW_FAILURE; |
---|
249 | } |
---|
250 | /* We should be able to do something like origintime = arcmsg.sum.ot - GSEC1970; after parse_arc */ |
---|
251 | if (debug == 1) logit("et", "COSMOS0PA_next_ev: Debug: Arc parsing %s\n", EventArcFile); |
---|
252 | if (parse_arc(fbuffer, &arcmsg) != 0 ) |
---|
253 | { |
---|
254 | logit("et", "COSMOS0PA_next_ev: Error parsing %s\n", |
---|
255 | EventArcFile); |
---|
256 | } |
---|
257 | timefunc = localtime; |
---|
258 | ot = (time_t)(arcmsg.sum.ot - GSEC1970); |
---|
259 | timeinfo = timefunc(&ot); |
---|
260 | /* Copy the library file to the putaway file*/ |
---|
261 | /* c = fgetc(COSMOS0Libfp); |
---|
262 | while (c != EOF) |
---|
263 | { |
---|
264 | fputc(c, COSMOS0fp); |
---|
265 | c = fgetc(COSMOS0Libfp); |
---|
266 | } |
---|
267 | */ |
---|
268 | while (fgets(str, COSMOSLINELEN, COSMOS0Libfp) != NULL) { |
---|
269 | LineNumber++ ; |
---|
270 | switch (LineNumber) { |
---|
271 | case 2: /* 2 1-40 Earthquake name (before a name has been assigned, may appear as Record of; test |
---|
272 | records may use Test Record of, etc.). |
---|
273 | 41-80 Earthquake date and time (including time zone). */ |
---|
274 | strftime(timestr, 80, "Record of Earthquake of %B %d, %Y, %H:%M:%S UTC", timeinfo); |
---|
275 | fprintf(COSMOS0fp, "%s\n", timestr); |
---|
276 | break; |
---|
277 | case 3: /*3 12-46 Hypocenter: 12-20 Latitude (positive North); 22-31 Longitude (positive East); and |
---|
278 | 35-37 Depth (km); 40-46 Source agency for hypocenter information. |
---|
279 | 47-80 Magnitude(s), including source agency for values (may be entered manually, so |
---|
280 | spacing may be variable).**/ |
---|
281 | sprintf(tempstr, "Hypocenter: %9.4f %9.4f H=%3.0fkm M=%3.1f, Md=%3.1f", |
---|
282 | arcmsg.sum.lat, arcmsg.sum.lon, arcmsg.sum.z, arcmsg.sum.Mpref, arcmsg.sum.Md); |
---|
283 | fprintf(COSMOS0fp, "%s\n", tempstr); |
---|
284 | break; |
---|
285 | case 4: /* 4 9-42 Earthquake origin date and time, in UTC (i.e., GMT), with source agency; 43-80, |
---|
286 | For use by preparing agency; may include note, e.g., Preliminary Processing, etc.*/ |
---|
287 | |
---|
288 | /* Prepare origin time. Second can have tenths place, so leaving two spaces here to indicate |
---|
289 | we're not going to that level of precision, the timestruct doesn't have tenths. Probably worth revisiting.*/ |
---|
290 | strftime(timestr, 80, "%m/%d/%Y, %H:%M:%S ", timeinfo); |
---|
291 | sprintf(tempstr, "Origin: %s UTC", timestr); |
---|
292 | fprintf(COSMOS0fp, "%s\n", tempstr); |
---|
293 | break; |
---|
294 | case 8: /* Record information: |
---|
295 | 8 17-50 Record start time (date and time of first sample; may be approximate - precise value |
---|
296 | should be obtained from real header) and time quality (0 through 5 correspond to |
---|
297 | lowest through highest quality). |
---|
298 | 59-80 Record identification, assigned by preparing agency. |
---|
299 | "06/17/2018, 18:34:38.004 GMT (Q=5) "<- 35 chars " (Q=5) " "38199368.SB.WLA.00.HN " <- 22char*/ |
---|
300 | /* strncpy(record_id, str + 45, 34); no, we're not going to use any of the prev string */ |
---|
301 | /* We pad with white space, because we're going to overwrite some of it, and we'll only copy |
---|
302 | the relevant characters to go up to 80, andything too long will get truncated. */ |
---|
303 | sprintf(tempstr, "Rcrd start time:%s ", cos_date); |
---|
304 | sprintf(tempstr2, "RcrdId:%d.%s.%s.%s.%s ", |
---|
305 | arcmsg.sum.qid,ptrReq->net, ptrReq->sta, ptrReq->loc, ptrReq->chan); |
---|
306 | strncpy(tempstr + 51, tempstr2, 29); |
---|
307 | tempstr[80] = '\0'; /* Chop off any extra junk */ |
---|
308 | fprintf(COSMOS0fp, "%s\n", tempstr); |
---|
309 | break; |
---|
310 | case 10: /* 10 20-27 Length of raw record, as recorded (seconds); 45-54 Maximum of raw (uncorrected) |
---|
311 | record in g (or other units);* 60-67 Time max occurs in raw record (secs after start). |
---|
312 | Example: |
---|
313 | Raw record length = 175.340 sec, Uncor max = 100000000, at 40.220 sec. */ |
---|
314 | sprintf(tempstr, "Raw record length = %f", (ptrReq->reqEndtime - ptrReq->reqStarttime)); |
---|
315 | strncpy(tempstr + 28, "sec, Uncor max = ", 53); |
---|
316 | fprintf(COSMOS0fp, "%s\n", tempstr); |
---|
317 | break; |
---|
318 | case 11: /*"Record Information; Line 11 |
---|
319 | 11-40 Processing/release date, time and agency. |
---|
320 | 48-80 Maximum of data series in file, units, and time of maximum (seconds after start).*" |
---|
321 | What should I put here? An example file looks like: |
---|
322 | "Processed: 06/17/18 12:00 PDT UCB " |
---|
323 | */ |
---|
324 | time(&rawtime); |
---|
325 | timeinfo = gmtime(&rawtime); |
---|
326 | sprintf(tempstr, "Processed: %d/%d/%d %d:%d UTC ", |
---|
327 | (timeinfo->tm_mon + 1), |
---|
328 | timeinfo->tm_mday, |
---|
329 | (timeinfo->tm_year + 1900), |
---|
330 | timeinfo->tm_hour, |
---|
331 | timeinfo->tm_min |
---|
332 | ); |
---|
333 | fprintf(COSMOS0fp, "%s\n", tempstr); |
---|
334 | break; |
---|
335 | case 47: /*AQMS normally writes this comment, but we're not using AQMS*/ |
---|
336 | /* Example: | RcrdId: NC.72282711.NC.C031.HNE.01 */ |
---|
337 | sprintf(tempstr, "| RcrdId: %s.%d.%s.%s.%s.%s ", /* FIX: If anyone knows what I can put here instead of 72282711, I'll do it!*/ |
---|
338 | ptrReq->net, arcmsg.sum.qid, ptrReq->net, ptrReq->sta, ptrReq->chan, ptrReq->loc); |
---|
339 | fprintf(COSMOS0fp, "%s\n", tempstr); |
---|
340 | break; |
---|
341 | case 48: /*AQMS normally writes this comment, but we're not using AQMS*/ |
---|
342 | /*Example:|<SCNL>C031.HNE.NC.01 <AUTH> 2015/03/01 16:46:25.000*/ |
---|
343 | sprintf(tempstr, "|<SCNL> %s.%s.%s.%s <AUTH> %d/%d/%d %d:%d:%d.000", |
---|
344 | ptrReq->sta, ptrReq->chan, ptrReq->net, ptrReq->loc, |
---|
345 | (timeinfo->tm_year + 1900), (timeinfo->tm_mon + 1), timeinfo->tm_mday, |
---|
346 | timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); |
---|
347 | fprintf(COSMOS0fp, "%s", tempstr); |
---|
348 | break; |
---|
349 | default: |
---|
350 | fprintf(COSMOS0fp, "%s", str); |
---|
351 | } |
---|
352 | |
---|
353 | } |
---|
354 | fclose(COSMOS0Libfp); |
---|
355 | return (EW_SUCCESS); |
---|
356 | } |
---|
357 | |
---|
358 | /************************************************************************ |
---|
359 | * This is the working entry point into the disposal system. This * |
---|
360 | * routine gets called for each trace snippet which has been recovered. * |
---|
361 | * It gets to see the corresponding SNIPPET structure, and the event id * |
---|
362 | * * |
---|
363 | * For COSMOS0, this routine writes to the COSMOS0 file, pointed to by * |
---|
364 | * the COSMOS0fp pointer, all of the received trace data in COSMOS0 * |
---|
365 | * format: * |
---|
366 | * * |
---|
367 | * 1. COSMOS0 tag - indicating what follows * |
---|
368 | * 2. COSMOS0_STATIONCOMP struct - describe the station * |
---|
369 | * 3. COSMOS0 tag - indicating what follows * |
---|
370 | * 4. COSMOS0_DESCRIPTRACE struct - describe the trace data * |
---|
371 | * 5. trace data * |
---|
372 | * * |
---|
373 | * One bit of complexity is that we need to write the files in the * |
---|
374 | * correct byte-order. Based on the OutputFormat parameter, determine * |
---|
375 | * whether or not to swap bytes before writing the COSMOS0 file. * |
---|
376 | * * |
---|
377 | * WARNING: we clip trace data to -2147483648 - +2147483647 so it will * |
---|
378 | * fit in a long int. Any incoming data that is longer than 32 bits * |
---|
379 | * will be CLIPPED. cjb 5/18/2001 * |
---|
380 | *************************************************************************/ |
---|
381 | /* Process one channel of data */ |
---|
382 | int COSMOS0PA_next(TRACE_REQ *getThis, double GapThresh, |
---|
383 | long OutBufferLen, int debug, |
---|
384 | int Cadence, double Multiplier) |
---|
385 | { |
---|
386 | TRACE2_HEADER *wf; |
---|
387 | char datatype; |
---|
388 | char day_line[122]; |
---|
389 | char fourdigits[5]; |
---|
390 | char hour_line[81] = "; "; |
---|
391 | char sample[12]; |
---|
392 | char elevendigits[12]; |
---|
393 | char *msg_p; /* pointer into tracebuf data */ |
---|
394 | double begintime = 0, starttime = 0, endtime = 0, currenttime = 0; |
---|
395 | double samprate, unrounded; |
---|
396 | float *f_data; |
---|
397 | int gap_count = 0; |
---|
398 | int i, j; |
---|
399 | int seconds = 0; |
---|
400 | int s_place = 0; |
---|
401 | int tabular_base; |
---|
402 | int total, raw_counts; |
---|
403 | long nfill_max = 0l; |
---|
404 | long nsamp, nfill; |
---|
405 | long nsamp_this_scn = 0l; |
---|
406 | long this_size; |
---|
407 | long *l_data; |
---|
408 | short *s_data; |
---|
409 | int current_int; |
---|
410 | char tempstr[COSMOSLINELEN]; |
---|
411 | char tempstr2[COSMOSLINELEN]; |
---|
412 | |
---|
413 | /* Put this in the .d file once we know we want it. */ |
---|
414 | /* double multiplier = 0.001; */ |
---|
415 | |
---|
416 | /* Check arguments */ |
---|
417 | if (getThis == NULL) |
---|
418 | { |
---|
419 | logit("e", "COSMOS0PA_next: invalid argument passed in.\n"); |
---|
420 | return EW_FAILURE; |
---|
421 | } |
---|
422 | /* Used for computing trace statistics */ |
---|
423 | total = 0; |
---|
424 | |
---|
425 | if ((msg_p = getThis->pBuf) == NULL) /* pointer to first message */ |
---|
426 | { |
---|
427 | logit("e", "COSMOS0PA_next: Message buffer is NULL.\n"); |
---|
428 | return EW_FAILURE; |
---|
429 | } |
---|
430 | wf = (TRACE2_HEADER *)msg_p; |
---|
431 | |
---|
432 | /* Look at the first TRACE2_HEADER and get set up of action */ |
---|
433 | if (WaveMsg2MakeLocal(wf) < 0) |
---|
434 | { |
---|
435 | logit("e", "COSMOS0PA_next: unknown trace data type: %s\n", |
---|
436 | wf->datatype); |
---|
437 | return(EW_FAILURE); |
---|
438 | } |
---|
439 | |
---|
440 | nsamp = wf->nsamp; |
---|
441 | starttime = wf->starttime; |
---|
442 | endtime = wf->endtime; |
---|
443 | samprate = wf->samprate; |
---|
444 | if (samprate < 0.0001) |
---|
445 | { |
---|
446 | logit("et", "unreasonable samplerate (%f) for <%s.%s.%s.%s>\n", |
---|
447 | samprate, wf->sta, wf->chan, wf->net, wf->loc); |
---|
448 | return(EW_FAILURE); |
---|
449 | } |
---|
450 | /* LAST header line now that we know sample rate*/ |
---|
451 | /* WRITE Dynamic header; this probably can't be here though because we need to calculate these results */ |
---|
452 | /* First we'll write a line that looks like this: */ |
---|
453 | /* 17770 raw accel.pts, approx 178 secs, units = counts(50), Format = (7I11) */ |
---|
454 | /*Line Cols |
---|
455 | 1st 1 - 8 Number of data points following; 10 - 21 Physical parameter of the data. |
---|
456 | 35 - 38 Approximate length of record(rounded to nearest sec; see Rhdr(66) for precise value). |
---|
457 | 52 - 58 Units of the data values(e.g., cm / sec2); 60 - 61 Index code for units |
---|
458 | 71-80 Format of the data values written on the following lines. |
---|
459 | */ |
---|
460 | /*sprintf(hour_line, "17770 raw accel.pts, approx 178 secs, units=counts (50),Format=(10I8)\r\n"); /* we want leading spaces */ |
---|
461 | |
---|
462 | /* sprintf(tempstr, "17770 raw accel.pts, approx 178 secs, units=counts (50),Format=(10I8) \n");*/ |
---|
463 | sprintf(tempstr, " raw accel.pts, approx , units=counts (50),Format=(10I8) \n"); |
---|
464 | raw_counts = (getThis->reqEndtime - getThis->reqStarttime ) * samprate; |
---|
465 | sprintf(tempstr2, "%d", raw_counts); |
---|
466 | strncpy(tempstr, tempstr2, strlen(tempstr2)); |
---|
467 | seconds = (getThis->reqEndtime - getThis->reqStarttime); |
---|
468 | sprintf(tempstr2, "%d secs", seconds); |
---|
469 | strncpy(tempstr + 34, tempstr2, strlen(tempstr2)); |
---|
470 | if (fwrite(tempstr, 81, 1, COSMOS0fp) != 1) |
---|
471 | { |
---|
472 | logit("et", "COSMOS0PA_next: error writing COSMOS0 dynamic header line. \n"); |
---|
473 | return EW_FAILURE; |
---|
474 | } |
---|
475 | begintime = starttime; |
---|
476 | /* datatype i4 = intel byte order 4 bytes, s2 = sparc byte order; 2 bytes */ |
---|
477 | datatype = 'n'; |
---|
478 | if (wf->datatype[0] == 's' || wf->datatype[0] == 'i') |
---|
479 | { |
---|
480 | if (wf->datatype[1] == '2') datatype = 's'; |
---|
481 | else if (wf->datatype[1] == '4') datatype = 'l'; |
---|
482 | } |
---|
483 | else if (wf->datatype[0] == 't' || wf->datatype[0] == 'f') |
---|
484 | { |
---|
485 | if (wf->datatype[1] == '4') datatype = 'f'; |
---|
486 | } |
---|
487 | if (datatype == 'n') |
---|
488 | { |
---|
489 | logit( "et", "COSMOS0PA_next: unsupported datatype: %s\n", wf->datatype ); |
---|
490 | return(EW_FAILURE); |
---|
491 | } |
---|
492 | |
---|
493 | if (debug == 1) |
---|
494 | logit("et", "COSMOS0PA_next: working on <%s/%s/%s/%s> datatype: %c \n", |
---|
495 | wf->sta, wf->chan, wf->net, wf->loc, datatype); |
---|
496 | |
---|
497 | /********************** loop through all the messages for this s-c-n **********************/ |
---|
498 | while (1) |
---|
499 | { |
---|
500 | /* advance message pointer to the data */ |
---|
501 | msg_p += sizeof(TRACE2_HEADER); |
---|
502 | |
---|
503 | /* check for sufficient memory in output buffer */ |
---|
504 | this_size = (nsamp_this_scn + nsamp) * sizeof(long); |
---|
505 | if (OutBufferLen < this_size) |
---|
506 | { |
---|
507 | logit("e", "out of space for <%s.%s.%s.%s>; saving long trace.\n", |
---|
508 | wf->sta, wf->chan, wf->net, wf->loc); |
---|
509 | break; |
---|
510 | } |
---|
511 | |
---|
512 | /* if data are floats, clip to longs cjb 5/18/2001 */ |
---|
513 | switch (datatype) |
---|
514 | { |
---|
515 | case 's': |
---|
516 | s_data = (short *)msg_p; |
---|
517 | for (j = 0; j < nsamp; j++, nsamp_this_scn++) |
---|
518 | COSMOS0Buffer[nsamp_this_scn] = (long)s_data[j]; |
---|
519 | msg_p += sizeof(short) * nsamp; |
---|
520 | break; |
---|
521 | case 'l': |
---|
522 | l_data = (long *)msg_p; |
---|
523 | for (j = 0; j < nsamp; j++, nsamp_this_scn++) |
---|
524 | COSMOS0Buffer[nsamp_this_scn] = l_data[j]; |
---|
525 | msg_p += sizeof(long) * nsamp; |
---|
526 | break; |
---|
527 | case 'f': |
---|
528 | f_data = (float *)msg_p; |
---|
529 | /* CLIP the data to long int */ |
---|
530 | for (j = 0; j < nsamp; j++, nsamp_this_scn++) |
---|
531 | { |
---|
532 | if (l_data[j] < (float)LONG_MIN) |
---|
533 | COSMOS0Buffer[nsamp_this_scn] = LONG_MIN; |
---|
534 | else if (l_data[j] > (float)LONG_MAX) |
---|
535 | COSMOS0Buffer[nsamp_this_scn] = LONG_MAX; |
---|
536 | else |
---|
537 | COSMOS0Buffer[nsamp_this_scn] = (long)l_data[j]; |
---|
538 | } |
---|
539 | msg_p += sizeof(float) * nsamp; |
---|
540 | break; |
---|
541 | } |
---|
542 | |
---|
543 | /* msg_p has been advanced to the next TRACE_BUF; localize bytes * |
---|
544 | * and check for gaps. */ |
---|
545 | wf = (TRACE2_HEADER *)msg_p; |
---|
546 | if (WaveMsg2MakeLocal(wf) < 0) |
---|
547 | { |
---|
548 | if (debug == 1) |
---|
549 | logit("e", "COSMOS0PA_next: unknown trace data type or unexpected end of data: %s\n", |
---|
550 | wf->datatype); |
---|
551 | else |
---|
552 | logit("e", "COSMOS0PA_next: unknown trace data type or unexpected end of data.\n"); |
---|
553 | break; |
---|
554 | //return(EW_FAILURE); |
---|
555 | } |
---|
556 | nsamp = wf->nsamp; |
---|
557 | starttime = wf->starttime; |
---|
558 | /* starttime is set for new packet; endtime is still set for old packet */ |
---|
559 | if (endtime + (1.0 / samprate) * GapThresh < starttime) |
---|
560 | { |
---|
561 | /* there's a gap, so fill it */ |
---|
562 | if (debug == 1) |
---|
563 | logit("e", "gap in %s.%s.%s.%s: %lf: %lf\n", wf->sta, wf->chan, wf->net, |
---|
564 | wf->loc, endtime, starttime - endtime); |
---|
565 | nfill = (long)(samprate * (starttime - endtime) - 1); |
---|
566 | if ((nsamp_this_scn + nfill) * (long)sizeof(long) > OutBufferLen) |
---|
567 | { |
---|
568 | logit( "e", "bogus gap (%ld); skipping\n", nfill ); |
---|
569 | return(EW_FAILURE); |
---|
570 | } |
---|
571 | /* do the filling */ |
---|
572 | for (j = 0; j < nfill; j++, nsamp_this_scn++) |
---|
573 | COSMOS0Buffer[nsamp_this_scn] = getThis->fill; // changed from local variable fill swl |
---|
574 | /* keep track of how many gaps and the largest one */ |
---|
575 | gap_count++; |
---|
576 | if (nfill_max < nfill) |
---|
577 | nfill_max = nfill; |
---|
578 | } |
---|
579 | /* Advance endtime to the new packet; * |
---|
580 | * process this packet in the next iteration */ |
---|
581 | endtime = wf->endtime; |
---|
582 | } /******************** end while(1) ***************************************************/ |
---|
583 | |
---|
584 | /* If the sample rate is 1 sample per minute then we'll have a sample rate of .016 */ |
---|
585 | /* For minute data we want 24 rows of 60 samples each, 1440 samples in a day. */ |
---|
586 | /* A single file fills the month of October for SJG, and includes four trace types */ |
---|
587 | /* FYXZ, so there are a total of 2976 lines in this file. */ |
---|
588 | |
---|
589 | /* Match our metadata with our waveserver request, if possible. |
---|
590 | * observatory's value is -1 if there isn't a match. */ |
---|
591 | |
---|
592 | currenttime = begintime; |
---|
593 | j = 0; |
---|
594 | |
---|
595 | |
---|
596 | while ((j < nsamp_this_scn) && (currenttime < getThis->reqEndtime)) |
---|
597 | { |
---|
598 | /* Only give them what they asked for, not each sample we got back. |
---|
599 | Tracebufs contain multiple samples, and we may need to request |
---|
600 | an earlier one to get the start sample we need, or a later one |
---|
601 | for the last sample*/ |
---|
602 | while (currenttime < getThis->reqStarttime) { |
---|
603 | currenttime = currenttime + 1 / samprate; |
---|
604 | j++; |
---|
605 | } |
---|
606 | |
---|
607 | s_place = 0; |
---|
608 | |
---|
609 | /* 35-394 60I6 60 6-digit 1-minute values for the given element for that data hour. |
---|
610 | * The values are in tenth-minutes for D and I, and in |
---|
611 | * nanoTeslas for the intensity elements. |
---|
612 | */ |
---|
613 | total = 0; |
---|
614 | LineMean = 0; |
---|
615 | |
---|
616 | i = 0; |
---|
617 | |
---|
618 | /* WRITE DATA */ |
---|
619 | |
---|
620 | while (i < 7 && j < nsamp_this_scn) |
---|
621 | { |
---|
622 | if (COSMOS0Buffer[j] != getThis->fill) { |
---|
623 | sprintf(elevendigits, " "); /* we want leading spaces */ |
---|
624 | if (((int)(COSMOS0Buffer[j] * Multiplier) > 999999) || ((int)(COSMOS0Buffer[j] * Multiplier) < -99999)) { |
---|
625 | sprintf(sample, GAP_FILL); |
---|
626 | /* prevent out of range string */ |
---|
627 | } |
---|
628 | else { |
---|
629 | sprintf(sample, "%d", (int)(COSMOS0Buffer[j] * Multiplier)); |
---|
630 | } |
---|
631 | strcpy(elevendigits + 11 - strlen(sample), sample); |
---|
632 | strcpy(hour_line + s_place, elevendigits); |
---|
633 | } |
---|
634 | else { |
---|
635 | /* We have a gap, this is where gap data is written */ |
---|
636 | //strcpy(hour_line + s_place, " 9999"); |
---|
637 | sprintf(sample, GAP_FILL); |
---|
638 | strcpy(elevendigits + 11 - strlen(sample), sample); |
---|
639 | strcpy(hour_line + s_place, elevendigits); |
---|
640 | } |
---|
641 | s_place = s_place + 11; |
---|
642 | |
---|
643 | total += (int)(COSMOS0Buffer[j] * Multiplier); |
---|
644 | |
---|
645 | j++; i++; |
---|
646 | } |
---|
647 | |
---|
648 | |
---|
649 | /* 401-402 Record end marker. |
---|
650 | * Two chars 'cr'= 13 and 'nl'= 10. |
---|
651 | */ |
---|
652 | hour_line[77] = ' '; /*Replace that null that sprintf got us*/ |
---|
653 | hour_line[80] = '\n'; |
---|
654 | |
---|
655 | /* Write out line */ |
---|
656 | if (fwrite(&hour_line, sizeof(hour_line), 1, COSMOS0fp) != 1) |
---|
657 | { |
---|
658 | logit("et", "COSMOS0PA_next: error writing COSMOS0 line. \n"); |
---|
659 | return EW_FAILURE; |
---|
660 | } |
---|
661 | } |
---|
662 | return EW_SUCCESS; |
---|
663 | } |
---|
664 | |
---|
665 | |
---|
666 | |
---|
667 | /************************************************************************ |
---|
668 | * This is the Put Away end event routine. It's called after we've * |
---|
669 | * finished processing one event * |
---|
670 | * * |
---|
671 | * For PC-COSMOS0 - close the COSMOS0 file, pointed to by COSMOS0fp * |
---|
672 | * free COSMOS0Buffer memory to be nice to everyone else * |
---|
673 | *************************************************************************/ |
---|
674 | int COSMOS0PA_end_ev(int debug) |
---|
675 | { |
---|
676 | fclose(COSMOS0fp); |
---|
677 | |
---|
678 | if (debug == 1) |
---|
679 | logit("t", "Closing COSMOS0 file \n"); |
---|
680 | |
---|
681 | return(EW_SUCCESS); |
---|
682 | } |
---|
683 | |
---|
684 | /************************************************************************ |
---|
685 | * This is the Put Away close routine. It's called after when * |
---|
686 | * we're being shut down. * |
---|
687 | *************************************************************************/ |
---|
688 | int COSMOS0PA_close(int debug) |
---|
689 | { |
---|
690 | |
---|
691 | free((char *)COSMOS0Buffer); |
---|
692 | return(EW_SUCCESS); |
---|
693 | } |
---|
694 | |
---|
695 | /* |
---|
696 | * |
---|
697 | * Byte swapping functions |
---|
698 | */ |
---|
699 | |
---|
700 | /* swap bytes if necessary, depending on what machine */ |
---|
701 | /* we have been compiled, and what machine the data */ |
---|
702 | /* is being read from/being written to */ |
---|
703 | |
---|
704 | static int StructMakeLocal(void *ptr, int struct_type, char data_type, |
---|
705 | int debug) |
---|
706 | { |
---|
707 | if (ptr == NULL) |
---|
708 | { |
---|
709 | logit("e", "StructMakeLocal: NULL pointer passed in\n"); |
---|
710 | return EW_FAILURE; |
---|
711 | } |
---|
712 | |
---|
713 | #if defined (_INTEL) |
---|
714 | if (data_type != '6') |
---|
715 | { |
---|
716 | if (debug == 1) |
---|
717 | logit("et", "Hoping we don't really have to do any swapping from Intel to Sun \n"); |
---|
718 | |
---|
719 | } |
---|
720 | |
---|
721 | #elif defined (_SPARC) |
---|
722 | if (data_type == '6') |
---|
723 | { |
---|
724 | if (debug == 1) |
---|
725 | logit("et", "Hoping we don't really have to do any swapping from Sun to Intel because we've deleted from COSMOS0 the SwapDo function that suds used. \n"); |
---|
726 | } |
---|
727 | |
---|
728 | #endif |
---|
729 | return EW_SUCCESS; |
---|
730 | } |
---|
731 | |
---|
732 | long Median(int number_of_array_elements, long *Array) |
---|
733 | { |
---|
734 | long *LocalArray; |
---|
735 | |
---|
736 | LocalArray = (long*)malloc(number_of_array_elements * sizeof(long)); |
---|
737 | |
---|
738 | qsort(&LocalArray[0], number_of_array_elements, sizeof(long), longCompareForQsort); |
---|
739 | /* Get Median */ |
---|
740 | return(LocalArray[(long)(number_of_array_elements / 2)]); |
---|
741 | } |
---|
742 | /*****************************************************************/ |
---|
743 | /* Just a simple compare function so that Q sort does it's thing */ |
---|
744 | /*****************************************************************/ |
---|
745 | int longCompareForQsort(const void *x, const void *y) |
---|
746 | { |
---|
747 | /* compare must have const void ptr params for qsort to work */ |
---|
748 | const long *ix = (const long *)x; |
---|
749 | const long *iy = (const long *)y; |
---|
750 | /* returns 1, -1 or 0 */ |
---|
751 | return (*ix > *iy) - (*ix < *iy); |
---|
752 | } |
---|