]> Pileus Git - ~andy/rsl/blob - src/radar_to_uf.c
Merge branch 'master' into aweather
[~andy/rsl] / src / radar_to_uf.c
1 /*
2     NASA/TRMM, Code 910.1.
3     This is the TRMM Office Radar Software Library.
4     Copyright (C) 1996, 1997
5             John H. Merritt
6             Space Applications Corporation
7             Vienna, Virginia
8
9     This library is free software; you can redistribute it and/or
10     modify it under the terms of the GNU Library General Public
11     License as published by the Free Software Foundation; either
12     version 2 of the License, or (at your option) any later version.
13
14     This library is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17     Library General Public License for more details.
18
19     You should have received a copy of the GNU Library General Public
20     License along with this library; if not, write to the Free
21     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26 #include <stdlib.h>
27
28 #define USE_RSL_VARS
29 #include "rsl.h"
30 extern int radar_verbose_flag;
31 /* Missing data flag : -32768 when a signed short. */
32 #define UF_NO_DATA 0X8000
33
34
35 /* Field names. Any convensions may be observed. */
36 /* Typically:
37  *    DZ = Reflectivity (dBZ).
38  *    VR = Radial Velocity.
39  *    SW = Spectrum Width.
40  *    CZ = Corrected Reflectivity. (Quality controlled: AP removed, etc.)
41  *    ZT = Total Reflectivity (dB(mW)).  Becomes UZ in UF files.
42  *    DR = Differential Reflectivity.
43  *    LR = Another DR (LDR).
44  *    ZD = Tina Johnson use this one.
45  *    DM = Received power.
46  *    RH = Rho coefficient.
47  *    PH = Phi (MCTEX parameter).
48  *    XZ = X-band reflectivity.
49  *    CD = Corrected ZD.
50  *    MZ = DZ mask for 1C-51 HDF.
51  *    MD = ZD mask for 1C-51 HDF.
52  *    ZE = Edited reflectivity.
53  *    VE = Edited velocity.
54  *    KD = KDP wavelength*deg/km
55  *    TI = TIME (units unknown).
56  * These fields may appear in any order in the UF file.
57  * There are more fields than appear here.  See rsl.h.
58  */
59
60
61 /* Changed old buffer size (16384) for larger dualpol files.  BLK 5/20/2011 */
62 typedef short UF_buffer[20000]; /* Bigger than documented 4096. */
63
64 void swap_uf_buffer(UF_buffer uf);
65 void swap2(short *buf, int n);
66
67 /**********************************************************************/
68 /*                                                                    */
69 /*                     RSL_radar_to_uf_fp                             */
70 /*                                                                    */
71 /*  By: John Merritt                                                  */
72 /*      Space Applications Corporation                                */
73 /*      May  20, 1994                                                 */
74 /**********************************************************************/
75 void RSL_radar_to_uf_fp(Radar *r, FILE *fp)
76
77 {
78   /*
79    * 1. Fill the UF buffers with data from the Radar structure.
80    * 2. Write to a stream.  Assume open and leave it so.
81    */
82
83
84   UF_buffer uf;
85
86 /* These are pointers to various locations within the UF buffer 'uf'.
87  * They are used to index the different components of the UF structure in
88  * a manor consistant with the UF documentation.  For instance, uf_ma[1]
89  * will be equivalenced to the second word (2 bytes/each) of the UF
90  * buffer.
91  */
92   short *uf_ma;  /* Mandatory header block. */
93   short *uf_op;  /* Optional header block.  */
94   short *uf_lu;  /* Local Use header block.  */
95   short *uf_dh;  /* Data header.  */
96   short *uf_fh;  /* Field header. */
97   short *uf_data; /* Data. */
98
99 /* The length of each header. */
100   int len_ma, len_op, len_lu, len_dh, len_fh, len_data;
101
102 /* Booleans to flag inclusion of headers. */
103   int q_op, q_lu, q_dh, q_fh;
104
105   int current_fh_index; 
106   int scale_factor;
107   int rec_len, save_rec_len;
108   int nfield;
109   float vr_az;
110   int max_field_names;
111
112   struct tm *tm;
113   time_t the_time;
114
115   int i,j,k,m;
116   int degree, minute;
117   float second;
118
119   int uf_sweep_mode = 1;  /* default PPI */
120
121 /* Here are the arrays for each field type.  Each dimension is the number
122  * of fields in the radar structure.  I do this because the radar organization
123  * is by volumes (field types) and the UF demands that each ray contain
124  * all the field types.
125  */
126   Volume **volume;
127   Sweep  **sweep;
128   Ray     *ray;
129   int     *nsweeps;
130   int nvolumes, maxsweeps, nrays;
131   int true_nvolumes;
132   int sweep_num, ray_num, rec_num;
133   float x;
134
135   if (r == NULL) {
136     fprintf(stderr, "radar_to_uf_fp: radar pointer NULL\n");
137     return;
138   }
139
140 /* Do all the headers first time around.  Then, prune OP and LU. */
141   q_op = q_lu = q_dh = q_fh = 1;
142
143   memset(&uf, 0, sizeof(uf)); /* Init to 0 or NULL for pointers. */
144
145   sweep_num = ray_num = rec_num = 0;
146   true_nvolumes = nvolumes = maxsweeps = nrays = 0;
147
148   /* PPI and RHI are enum constants defined in rsl.h */
149   if (r->h.scan_mode == PPI) uf_sweep_mode = 1;
150   else if (r->h.scan_mode == RHI) uf_sweep_mode = 3;
151
152 /*
153  * The organization of the Radar structure is by volumes, then sweeps, then
154  * rays, then gates.  This is different from the UF file organization.
155  * The UF format wants sweeps, rays, then gates for all field types (volumes).
156  * So, we have to do a back flip, here.  This is achieved by maintaining 
157  * an array of volume pointers and sweep pointers, each dimensioned by 
158  * 'nvolumes', which contains the data for the different field types; this
159  * is our innermost loop.  The variables are 'volume[i]' and 'sweep[i]' where
160  * 'i' is the volume index.
161  *
162  * In other words, we are getting all the field types together, when we
163  * are looping on the number of rays in a sweep, so we can load the UF_buffer
164  * appropriately.
165  */
166
167   nvolumes = r->h.nvolumes;
168   volume   = (Volume **) calloc(nvolumes, sizeof(Volume *));
169   sweep    = (Sweep  **) calloc(nvolumes, sizeof(Sweep  *));
170   nsweeps  = (int *)     calloc(nvolumes, sizeof(int));
171
172 /* Get the the number of sweeps in the radar structure.  This will be
173  * the main controlling loop variable.
174  */
175   for (i=0; i<nvolumes; i++) {
176     volume[i] = r->v[i];
177     if(volume[i]) {
178       nsweeps[i] = volume[i]->h.nsweeps;
179       if (nsweeps[i] > maxsweeps) maxsweeps = nsweeps[i];
180       true_nvolumes++;
181     }
182   }
183
184   if (radar_verbose_flag) {
185     fprintf(stderr,"True number of volumes for UF is %d\n", true_nvolumes);
186     fprintf(stderr,"Maximum #   of volumes for UF is %d\n", nvolumes);
187   }
188
189   max_field_names = sizeof(RSL_ftype) / 4;
190
191 /*--------
192  *   LOOP for all sweeps (typically 11 or 16 for wsr88d data.
193  *
194  */
195   for (i=0; i<maxsweeps; i++) {
196     /* Get the array of volume and sweep pointers; one for each field type. */
197     nrays = 0;
198     for (k=0; k<nvolumes; k++) {
199       if (volume[k]) sweep[k] = volume[k]->sweep[i];
200       
201       /* Check if we really can access this sweep.  Paul discovered that
202        * if the actual number of sweeps is less than the maximum that we
203        * could be chasing a bad pointer (a NON-NULL garbage pointer).
204        */
205       if (i >= nsweeps[k]) sweep[k] = NULL;
206
207       if (sweep[k]) if (sweep[k]->h.nrays > nrays) nrays = sweep[k]->h.nrays;
208     }
209
210     sweep_num++;  /* I guess it will be ok to count NULL sweeps. */
211     ray_num = 0;
212   if (radar_verbose_flag) 
213     fprintf(stderr,"Processing sweep %d for %d rays.", i, nrays);
214   if (radar_verbose_flag) {
215     if (little_endian()) fprintf(stderr," ... On Little endian.\n");
216     else fprintf(stderr,"\n");
217   }
218
219
220 /* Now LOOP for all rays within this particular sweep (i).
221  *    Get all the field types together for the ray, see ray[k], and
222  *    fill the UF data buffer appropriately.
223  */
224     for (j=0; j<nrays; j++) {
225       memset(uf, 0, sizeof(uf));
226       nfield = 0;
227       ray_num++;  /* And counting, possibly, NULL rays. */
228       current_fh_index = 0;
229
230
231       /* Find any ray for header information. It does not matter which
232        * ray, since the information for the MANDITORY, OPTIONAL, and LOCAL
233        * USE headers is common to any field type ray.
234        */
235       ray = NULL;
236       for (k=0; k<nvolumes; k++) {
237         if (sweep[k])
238           if (j < sweep[k]->h.nrays)
239             if (sweep[k]->ray)
240               if ((ray = sweep[k]->ray[j])) break;
241       }
242
243       /* If there is no such ray, then continue on to the next ray. */
244       if (ray) {
245 /*
246                   fprintf(stderr,"Ray: %.4d, Time: %2.2d:%2.2d:%f  %.2d/%.2d/%.4d\n", ray_num, ray->h.hour, ray->h.minute, ray->h.sec, ray->h.month, ray->h.day, ray->h.year);
247 */
248
249         /* 
250          * ---- Begining of MANDITORY HEADER BLOCK.
251          */
252         uf_ma = uf;
253         memcpy(&uf_ma[0], "UF", 2);
254         if (little_endian()) memcpy(&uf_ma[0], "FU", 2);
255         uf_ma[1]  = 0;  /* Not known yet. */
256         uf_ma[2]  = 0;  /* Not known yet. Really, I do. */
257         uf_ma[3]  = 0;  /* Not known yet. */
258         uf_ma[4]  = 0;  /* Not known yet. */
259
260         uf_ma[6]  = 1;
261         uf_ma[7]  = ray_num;
262         uf_ma[8 ] = 1;
263         uf_ma[9 ] = sweep_num;
264         memcpy(&uf_ma[10], r->h.radar_name, 8);
265         if (little_endian()) swap2(&uf_ma[10], 8/2);
266         memcpy(&uf_ma[14], r->h.name, 8);
267         if (little_endian()) swap2(&uf_ma[14], 8/2);
268         /* Convert decimal lat/lon to d:m:s */
269
270         if (ray->h.lat != 0.0) {
271           degree = (int)ray->h.lat;
272           minute = (int)((ray->h.lat - degree) * 60);
273           second = (ray->h.lat - degree - minute/60.0) * 3600.0;
274         } else {
275           degree = r->h.latd;
276           minute = r->h.latm;
277           second = r->h.lats;
278         }
279         uf_ma[18] = degree;
280         uf_ma[19] = minute;
281         if (second > 0.0) uf_ma[20] = second*64 + 0.5;
282         else uf_ma[20] = second*64 - 0.5;
283
284         if (ray->h.lon != 0.0) {
285           degree = (int)ray->h.lon;
286           minute = (int)((ray->h.lon - degree) * 60);
287           second = (ray->h.lon - degree - minute/60.0) * 3600.0;
288         } else {
289           degree = r->h.lond;
290           minute = r->h.lonm;
291           second = r->h.lons;
292         }
293         uf_ma[21] = degree;
294         uf_ma[22] = minute;
295         if (second > 0.0) uf_ma[23] = second*64 + 0.5;
296         else uf_ma[23] = second*64 - 0.5;
297         if (ray->h.alt != 0) 
298           uf_ma[24] = ray->h.alt;
299         else
300           uf_ma[24] = r->h.height;
301
302         uf_ma[25] = ray->h.year % 100; /* By definition: not year 2000 compliant. */
303         uf_ma[26] = ray->h.month;
304         uf_ma[27] = ray->h.day;
305         uf_ma[28] = ray->h.hour;
306         uf_ma[29] = ray->h.minute;
307         uf_ma[30] = ray->h.sec;
308         memcpy(&uf_ma[31], "UT", 2);
309         if (little_endian()) memcpy(&uf_ma[31], "TU", 2);
310         if (ray->h.azimuth > 0) uf_ma[32] = ray->h.azimuth*64 + 0.5;
311         else uf_ma[32] = ray->h.azimuth*64 - 0.5;
312         uf_ma[33] = ray->h.elev*64 + 0.5;
313         uf_ma[34] = uf_sweep_mode;
314         if (ray->h.fix_angle != 0.)
315              uf_ma[35] = ray->h.fix_angle*64.0 + 0.5;
316         else uf_ma[35] = sweep[k]->h.elev*64.0 + 0.5;
317         uf_ma[36] = ray->h.sweep_rate*(360.0/60.0)*64.0 + 0.5;
318         
319         the_time = time(NULL);
320         tm = gmtime(&the_time);
321         
322         uf_ma[37] = tm->tm_year % 100; /* Same format as data year */
323         uf_ma[38] = tm->tm_mon+1;
324         uf_ma[39] = tm->tm_mday;
325         memcpy(&uf_ma[40], "RSL" VERSION, 8);
326         if (little_endian()) swap2(&uf_ma[40], 8/2);
327         uf_ma[44] = (signed short)UF_NO_DATA;
328         len_ma = 45;
329         uf_ma[2] = len_ma+1;
330         /*
331          * ---- End of MANDITORY HEADER BLOCK.
332          */
333         
334         /* ---- Begining of OPTIONAL HEADER BLOCK. */
335         len_op = 0;
336         if (q_op) {
337           q_op = 0;  /* Only once. */
338           uf_op = uf+len_ma;
339           memcpy(&uf_op[0], "TRMMGVUF", 8);
340           if (little_endian()) swap2(&uf_op[0], 8/2);
341           uf_op[4] = (signed short)UF_NO_DATA;
342           uf_op[5] = (signed short)UF_NO_DATA;
343           uf_op[6] = ray->h.hour;
344           uf_op[7] = ray->h.minute;
345           uf_op[8] = ray->h.sec;
346           memcpy(&uf_op[9], "RADAR_UF", 8);
347           if (little_endian()) swap2(&uf_op[9], 8/2);
348           uf_op[13] = 2;
349           len_op = 14;
350         }
351         /* ---- End of OPTIONAL HEADER BLOCK. */
352         
353         /* ---- Begining of LOCAL USE HEADER BLOCK. */
354         q_lu = 0;
355
356         /* TODO: Code within "#ifdef LUHDR_VR_AZ" below should be removed
357          * once testing of merge_split_cuts is completed.
358          */
359 /* 5/18/2010 Temporarily define LUHDR_VR_AZ until merge_split_cuts is
360    completed. */
361 #define LUHDR_VR_AZ
362 #ifdef LUHDR_VR_AZ
363         /* If DZ and VR azimuths are different, store VR azimuth in Local Use
364          * Header. This is done for WSR-88D split cuts.
365          */
366         if (sweep[DZ_INDEX] && sweep[VR_INDEX]) {
367             if (sweep[DZ_INDEX]->ray[j] && sweep[VR_INDEX]->ray[j]) {
368             vr_az = sweep[VR_INDEX]->ray[j]->h.azimuth;
369             if (sweep[DZ_INDEX]->ray[j]->h.azimuth != vr_az)
370                 q_lu = 1; /* Set to use Local Use Header block. */
371             }
372         }
373 #endif
374         len_lu = 0;
375         if (q_lu) {
376           /* Store azimuth for WSR-88D VR ray in Local Use Header. */
377           uf_lu = uf+len_ma+len_op;
378           memcpy(&uf_lu[0], "AZ", 2);
379           if (little_endian()) memcpy(&uf_lu[0], "ZA", 2);
380           if (vr_az > 0) uf_lu[1] = vr_az*64 + 0.5;
381           else uf_lu[1] = vr_az*64 - 0.5;
382           len_lu = 2;
383         }
384         /* ---- End  of LOCAL USE HEADER BLOCK. */
385
386
387        /* Here is where we loop on each field type.  We need to keep
388         * track of how many FIELD HEADER and FIELD DATA sections, one
389         * for each field type, we fill.  The variable that tracks this
390         * index into 'uf' is 'current_fh_index'.  It is bumped by
391         * the length of the FIELD HEADER and FIELD DATA for each field
392         * type encountered.  Field types expected are: Reflectivity,
393         * Velocity, and Spectrum width; this is a typicial list but it
394         * is not restricted to it.
395         */
396         
397          for (k=0; k<nvolumes; k++) {
398           if (sweep[k])
399             if (j < sweep[k]->h.nrays && sweep[k]->ray[j])
400               ray = sweep[k]->ray[j];
401             else
402               ray = NULL;
403           else ray = NULL;
404
405           if (ray) {
406             /* ---- Begining of DATA HEADER. */
407             nfield++;
408             if (q_dh) {
409               len_dh = 2*true_nvolumes + 3;
410               uf_dh = uf+len_ma+len_op+len_lu;
411               uf_dh[0] = nfield;
412               uf_dh[1] = 1;
413               uf_dh[2] = nfield;
414               /* 'nfield' indexes the field number.
415                * 'k' indexes the particular field from the volume.
416                *  RSL_ftype contains field names and is defined in rsl.h.
417                */
418               if (k > max_field_names-1) {
419                 fprintf(stderr,
420                   "RSL_uf_to_radar: No field name for volume index %d\n", k);
421                 fprintf(stderr,"RSL_ftype must be updated in rsl.h for new field.\n");
422                 fprintf(stderr,"Quitting now.\n");
423                 return;
424               }
425               memcpy(&uf_dh[3+2*(nfield-1)], RSL_ftype[k], 2);
426               if (little_endian()) swap2(&uf_dh[3+2*(nfield-1)], 2/2);
427               if (current_fh_index == 0) current_fh_index = len_ma+len_op+len_lu+len_dh;
428               uf_dh[4+2*(nfield-1)] = current_fh_index + 1;
429             }
430             /* ---- End of DATA HEADER. */
431             
432             /* ---- Begining of FIELD HEADER. */
433             if (q_fh) {
434               uf_fh = uf+current_fh_index;
435               if (k != PH_INDEX) scale_factor = 100;
436               else scale_factor = 10;
437               uf_fh[1] = scale_factor;
438               uf_fh[2] = ray->h.range_bin1/1000.0;
439               uf_fh[3] = ray->h.range_bin1 - (1000*uf_fh[2]);
440               uf_fh[4] = ray->h.gate_size;
441               uf_fh[5] = ray->h.nbins;
442               uf_fh[6] = ray->h.pulse_width*(RSL_SPEED_OF_LIGHT/1.0e6);
443               uf_fh[7] = sweep[k]->h.beam_width*64.0 + 0.5;
444               uf_fh[8] = sweep[k]->h.beam_width*64.0 + 0.5;
445               uf_fh[9] = ray->h.frequency*64.0 + 0.5; /* Bandwidth (mHz). */
446               uf_fh[10] = 0; /* Horizontal polarization. */ 
447               uf_fh[11] = ray->h.wavelength*64.0*100.0; /* m to cm. */
448               uf_fh[12] = ray->h.pulse_count;
449               memcpy(&uf_fh[13], "  ", 2);
450               uf_fh[14] = (signed short)UF_NO_DATA;
451               uf_fh[15] = (signed short)UF_NO_DATA;
452               if (k == DZ_INDEX || k == ZT_INDEX) {
453                 uf_fh[16] = volume[k]->h.calibr_const*100.0 + 0.5;
454               }
455               else {
456                 memcpy(&uf_fh[16], "  ", 2);
457               }
458               if (ray->h.prf != 0)
459                 uf_fh[17] = 1.0/ray->h.prf*1000000.0; /* Pulse repetition time(msec)  = 1/prf */
460               else
461                 uf_fh[17] = (signed short)UF_NO_DATA; /* Pulse repetition time  = 1/prf */
462               uf_fh[18] = 16;
463               if (VR_INDEX == k || VE_INDEX == k) {
464                 uf_fh[19] = scale_factor*ray->h.nyq_vel;
465                 uf_fh[20] = 1;
466                 len_fh = 21;
467               } else {
468                 len_fh = 19;
469               }
470               
471               uf_fh[0] = current_fh_index + len_fh + 1;
472               /* ---- End of FIELD HEADER. */
473               
474               /* ---- Begining of FIELD DATA. */
475               uf_data = uf+len_fh+current_fh_index;
476               len_data = ray->h.nbins;
477               for (m=0; m<len_data; m++) {
478                 x = ray->h.f(ray->range[m]);
479                 if (x == BADVAL || x == RFVAL || x == APFLAG || x == NOECHO)
480                   uf_data[m] = (signed short)UF_NO_DATA;
481                 else
482                   uf_data[m] = scale_factor * x;
483               }
484               
485               current_fh_index += (len_fh+len_data);
486             }
487           }
488         /* ---- End of FIELD DATA. */
489         }
490         /* Fill in some infomation we didn't know.  Like, buffer length,
491          * record number, etc.
492          */
493         rec_num++;
494         uf_ma[1] = current_fh_index;
495         uf_ma[3] = len_ma + len_op + 1;
496         uf_ma[4] = len_ma + len_op + len_lu + 1;
497         uf_ma[5] = rec_num;
498         
499         /* WRITE the UF buffer. */
500         rec_len =(int)uf_ma[1]*2;
501         save_rec_len = rec_len;  /* We destroy 'rec_len' when making it
502                         big endian on a little endian machine. */
503         if (little_endian())
504             swap_4_bytes(&rec_len);
505         if (fwrite(&rec_len, sizeof(int), 1, fp) != 1)
506             perror("RSL_radar_to_uf_fp: short write");
507         if (little_endian())
508             swap_uf_buffer(uf);
509         if (fwrite(uf, sizeof(char), save_rec_len, fp) != 1)
510             perror("RSL_radar_to_uf_fp: short write");
511         if (fwrite(&rec_len, sizeof(int), 1, fp) != 1)
512             perror("RSL_radar_to_uf_fp: short write");
513       } /* if (ray) */
514     }
515   }
516 }
517
518 /**********************************************************************/
519 /*                                                                    */
520 /*                     RSL_radar_to_uf                                */
521 /*                                                                    */
522 /**********************************************************************/
523 void RSL_radar_to_uf(Radar *r, char *outfile)
524 {
525   FILE *fp;
526   if (r == NULL) {
527     fprintf(stderr, "radar_to_uf: radar pointer NULL\n");
528     return;
529   }
530
531   if ((fp = fopen(outfile, "w")) == NULL) {
532     perror(outfile);
533     return;
534   }
535
536   RSL_radar_to_uf_fp(r, fp);
537   fclose(fp);
538 }
539
540 /**********************************************************************/
541 /*                                                                    */
542 /*                     RSL_radar_to_uf_gzip                           */
543 /*                                                                    */
544 /**********************************************************************/
545 void RSL_radar_to_uf_gzip(Radar *r, char *outfile)
546 {
547   FILE *fp;
548   if (r == NULL) {
549     fprintf(stderr, "radar_to_uf_gzip: radar pointer NULL\n");
550     return;
551   }
552
553   if ((fp = fopen(outfile, "w")) == NULL) {
554     perror(outfile);
555     return;
556   }
557
558   fp = compress_pipe(fp);
559   RSL_radar_to_uf_fp(r, fp);
560   rsl_pclose(fp);
561 }