1 <!doctype html public "-//w3c//dtd html 4.0 transitional//en">
4 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5 <meta name="GENERATOR" content="Mozilla/4.5 [en] (X11; U; Linux 2.0.32 i686) [Netscape]">
8 <a href="index.html"><img SRC="rsl.gif" height=100 width=100></a>
13 Users Guide to RSL.</h1>
16 What is RSL good for?</h2>
17 The best feature of RSL is the ability to ingest many different RADAR data
18 file formats with a single library call. It can, also, read compressed
19 files -- compressed with GZIP or the older COMPRESS. The routine is called
20 <a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar</a>.
21 You give it a filename and it will return a pointer to a C structure called
22 <a href="RSL_radar_struct.html">Radar</a>.
23 The structure Radar contains all the information found in the input file.
24 The structure is intended to represent a superset of all RADAR data formats.
25 <p>Below, is a table listing the input/output routines supplied in RSL.
26 You will notice that there are only two output routines. RSL, by design,
27 is not a format converter, but, a library to facilitate reading and manipulation
28 of RADAR data. Output for UF and HDF are supplied because of the popularity
31 <table BORDER CELLPADDING=0 >
50 <td>HDF 1B-51 and 1C-51</td>
52 <td><a href="RSL_hdf_to_radar.html">RSL_hdf_to_radar</a></td>
54 <td><a href="RSL_radar_to_hdf.html">RSL_radar_to_hdf</a></td>
58 <td>Lassen (Darwin)</td>
60 <td><a href="RSL_lassen_to_radar.html">RSL_lassen_to_radar</a></td>
66 <td>WSR-88d (Nexrad)</td>
68 <td><a href="RSL_wsr88d_to_radar.html">RSL_wsr88d_to_radar</a></td>
74 <td>UF (Universal Format from NCAR)</td>
76 <td><a href="RSL_uf_to_radar.html">RSL_uf_to_radar</a></td>
78 <td><a href="RSL_radar_to_uf.html">RSL_radar_to_uf</a></td>
82 <td>SIGMET (Version 1)</td>
84 <td><a href="RSL_nsig_to_radar.html">RSL_nsig_to_radar</a></td>
90 <td>SIGMET (Version 2)</td>
92 <td><a href="RSL_nsig_to_radar.html">RSL_nsig2_to_radar</a></td>
100 <td><a href="RSL_mcgill_to_radar.html">RSL_mcgill_to_radar</a></td>
108 <td><a href="RSL_toga_to_radar.html">RSL_toga_to_radar</a></td>
114 <td>RAPIC (Berrimah) </td>
116 <td><a href="RSL_rapic_to_radar.html">RSL_rapic_to_radar</a></td>
122 <td>RADTEC (SPANDAR)</td>
124 <td><a href="RSL_radtec_to_radar.html">RSL_radtec_to_radar</a></td>
131 RSL is designed to provide you with a uniform data structure so that you
132 can design RADAR independent science applications. You no longer need to
133 wrestle over the input data format and have a different version of your
134 algorithm for each different RADAR format you may need to analyze.
135 <p>This paper presents RSL from a science application developer's point
136 of view. It will present some of the more useful routines and which fields
137 in the <a href="RSL_radar_struct.html">Radar</a> structure that will be
138 important to you and it will attempt to cover some of the programming pitfalls
139 associated with RSL usage. One of the most difficult hurdles to overcome
140 is that RSL makes extensive use of pointer syntax. You will find yourself
141 becoming expert with C pointers. However, the design of RSL makes it possible
142 to use C pointers painlessly.
144 Ok, I have some data, how do I look at it?</h2>
145 Let's first make some images. To do that you need only 3 RSL functions:
146 <p><tt><a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar</a></tt>
147 <br><tt><a href="RSL_load_color_table.html">RSL_load_refl_color_table</a></tt>
148 <br><tt><a href="RSL_volume_to.html">RSL_volume_to_gif</a></tt>
149 <p>The C program you need is incredibly short. It illustrates how to ingest
150 radar data and create a GIF image of the DZ (reflectivity) field:
151 <pre>#include "rsl.h"
152 void main(int argc, char **argv)
155 radar = RSL_anyformat_to_radar("radar.dat", NULL);
156 RSL_load_refl_color_table();
157 RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0);
160 <p><tt>#include "rsl.h"</tt>
161 <p>is required when using the RSL. It defines important constants and declares
162 all the RSL functions that your application may need.
164 <pre>Radar *radar;</pre>
165 declares the radar pointer. Only a pointer to a radar should be declared,
166 because, the ingest routines allocate all the space to hold all the appropriate
167 substructures: <a href="RSL_volume_struct.html">Volume</a>, <a href="RSL_sweep_struct.html">Sweep</a>,
168 <a href="RSL_ray_struct.html">Ray</a>,
169 and <a href="RSL_range_struct.html">Range</a>.
171 <pre>radar = RSL_anyformat_to_radar("radar.dat", NULL);</pre>
172 performs the actual ingest of data. The input file is called <tt>radar.dat</tt>.
173 <a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar
175 determines the type of radar data being read. It can handle *.gz or *.Z
176 files transparently. Reading gzip or compress files is faster, especially
177 over NFS. Generally, reading compressed radar files is faster
178 because of how UNIX pipes are implemented and that the compression is nearly
179 90%. The second argument, NULL, is optional. A second argument
180 is needed only when reading WSR-88D data. The WSR-88D site information
181 is provided in the first physical file on the 8mm tape, but, it is used
182 to fill lat/lon and other radar-site specific information when reading
183 the 2<sup>nd</sup> through last physical files on the tape.
184 <p>Note: <a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar</a>
185 can't handle every radar format for which there is an RSL ingest routine.
186 But, it does a good job at recognizing most formats. Currently, TOGA and
187 MCGILL files cannot be automatically detected. In those cases, use: <a href="RSL_toga_to_radar.html">RSL_toga_to_radar</a>
188 and <a href="RSL_mcgill_to_radar.html">RSL_mcgill_to_radar</a>.
189 <p>While basic image generation is provided in RSL, it is never intended
190 to be anything more than a diagnostic tool. Several assumptions are made,
191 but, the image generation functions provided are useful. This is what the
192 last two lines illustrate. First you must define a color table. That is
194 <pre>RSL_load_refl_color_table();</pre>
195 then, to generate disk files, gif images, you must call one of the image
196 generation functions, as in:
197 <pre>RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0);</pre>
198 This routine will generate several images, one for each sweep, mapping
199 the image to a 400 x 400 km grid, using a 1 x 1 km spacing, by collecting
201 <p>Making images of velocity data, <tt>VR_INDEX</tt>, involves two more
202 steps that are not very obvious. Because of the limited range of the values
203 presented in velocity data, you must re-bin the data. Do that with any
204 one of the following:
205 <pre><a href="RSL_rebin_velocity.html">RSL_rebin_velocity_sweep</a>,
206 <a href="RSL_rebin_velocity.html">RSL_rebin_velocity_volume</a></pre>
207 The second step is that you must call:
208 <pre><a href="RSL_load_color_table.html">RSL_load_vel_color_table()</a>;</pre>
209 The nyquist velocity is used to determine the limits of the re-binning.
211 functions modify the data in a sweep, or volume.</i> So, it is wise to
212 make copies of the sweep, or volume, if you plan on using the data later
213 in your application. Normally, though, making velocity images is the last
214 step of a program, therefore, you don't need to copy the velocity volume
215 as your program will be exiting shortly. RSL provides a number of color
216 table manipulation functions. You are not limited by the default settings
217 for DZ, VR, and SW color tables. You can specify any color table mapping
220 Whoopty doo, I really wanted to examine the values.</h2>
221 In order to get to values in the <a href="RSL_radar_struct.html">Radar</a>
222 structure, you have to trickle down all the substructues. The structures,
223 in order of nesting are: <a href="RSL_radar_struct.html">Radar</a>, <a href="RSL_volume_struct.html">Volume</a>,
224 <a href="RSL_sweep_struct.html">Sweep</a>,
225 <a href="RSL_ray_struct.html">Ray</a>,
226 <a href="RSL_range_struct.html">Range</a>.
227 Each of these structures is presented in that order. You will notice a
228 common organization across all of the structures -- each structure contains
229 a header and contains an array of pointers to the next substructure.
231 The Radar structure</h4>
232 Ok, make the call to <tt><a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar</a></tt>
233 as above, so that you get a pointer to a radar. The structure <tt><a href="RSL_radar_struct.html">Radar</a></tt>
234 is the most general structure in RSL. Radar is composed of two parts:
240 Array of pointers to <a href="RSL_volume_struct.html">Volume</a>s.</li>
242 The radar header, will be presented and described fully later, but, it
243 contains general information about the entire structure. To access the
244 radar header use the syntax:
246 radar->h.<i>member</i>;</pre>
247 The array of pointers to <a href="RSL_volume_struct.html">Volume</a>s contains
248 either pointers to <a href="RSL_volume_struct.html">Volume</a>s of data
249 or NULL. The number of possible <a href="RSL_volume_struct.html">Volume</a>s
250 in the radar is specified by radar->h.nvolumes. This number represents
251 the length of the array of pointers to <a href="RSL_volume_struct.html">Volume</a>s
252 and not the number of actual (non-NULL) volumes in the radar. The index
253 of this array of pointers to <a href="RSL_volume_struct.html">Volume</a>s
254 is the field type index. There are MAX_RADAR_VOLUMES (currently set to
255 19) field types defined in RSL. Each field type index has a specific value.
256 That value is illustrated in the table below. RSL ingest routines guarentee
257 that the length of the array of pointers to <a href="RSL_volume_struct.html">Volume</a>s,
259 is exactly the maximum number of field types, MAX_RADAR_VOLUMES. This is
260 done so that you can check for the existance of a field type with the syntax:
261 <pre>if (radar->v[XZ_INDEX]) /* XZ exists */</pre>
262 Normally, <tt>radar->h.nvolumes</tt> is set to the length of the array
263 of pointers to <a href="RSL_volume_struct.html">Volume</a>s, <tt>radar->v</tt>.
264 Because C array indexes start at 0, you should use a test similiar to:
265 ivol < radar->h.nvolumes. The maximum value for <tt>radar->h.nvolumes</tt>
266 is MAX_RADAR_VOLUMES which is a constant in RSL. The value for <tt>radar->h.nvolumes</tt>
267 could be less though. But, you can rest assured that you can test for the
268 existance of a field type simply by using the hard coded index name as
269 specified in the table below.
270 <p>There are basically two methods for indexing the array of pointers to
271 <a href="RSL_volume_struct.html">Volume</a>s:
274 Use the index name, eg. CZ_INDEX or its value.</li>
277 Use a variable that ranges from 0 to <tt>radar->h.nvolumes</tt>-1.</li>
279 Here are two coding examples that demonstrate how to access the array of
285 volume = radar->v[CZ_INDEX];
286 if (volume != NULL) {
287 /* Do something with volume. */
294 for (i=0; i<radar->h.nvolumes) {
295 volume = radar->v[i];
296 if (volume == NULL) continue; /* skip this NULL volume */
297 /* Do something with volume. */
299 It is very important that you check for the volume pointer being NULL.
300 It is very common that <tt>radar->h.nvolumes</tt> is larger than the number
301 of non-NULL volumes present in radar. By default, <tt>radar->h.nvolumes</tt>
302 is the length of array of pointers to <a href="RSL_volume_struct.html">Volume</a>s.
303 The volumes are also known as field types. There are several field types
304 and a <a href="RSL_volume_struct.html">Volume</a> can be only one field
305 type. The entire list of field types is presented in the table below. To
306 reference a particular field, you use a simple syntax:
307 <p><tt>radar->v[DZ_INDEX]</tt>
308 <br><tt>radar->v[VR_INDEX]</tt>
309 <p>Each field type encountered has a specific index within the <tt>radar->v</tt>
310 array of pointers to <a href="RSL_volume_struct.html">Volume</a>s. The
311 field type indexes are hard-coded and are defined to be specific numbers
312 starting at 0. Hard-coded field type indexes simplifies the syntax for
313 accessing volumes. When there is no volume for a particular field type,
314 the volume pointer is NULL. This is ok, as NULL is a perfectly acceptable,
315 albeit useless, volume. Here is a table of all the field type indexes used
318 <table BORDER CELLPADDING=0 >
341 <td>Reflectivity (dBZ)</td>
349 <td>Radial Velocity (m/s)</td>
357 <td>Spectral Width (m<sup><font size=-2>2</font></sup>/s<sup><font size=-2>2</font></sup>)</td>
365 <td>QC Reflectivity (dBZ)</td>
373 <td>Total Reflectivity (dBZ)</td>
381 <td>Differential reflectivity</td>
389 <td>Another differential refl.</td>
397 <td>Reflectivity Depolarization Ratio
398 <p>ZDR = 10log(ZH/ZV) (dB)</td>
406 <td>Received power (dBm)</td>
414 <td>Rho: Correlation coefficient</td>
422 <td>Phi (MCTEX parameter)</td>
430 <td>X-band reflectivity</td>
438 <td>Corrected DR reflectivity (differential).</td>
446 <td>DZ mask volume for HDF 1C-51 product.</td>
454 <td>DR mask volume for HDF 1C-51 product.</td>
462 <td>Edited reflectivity.</td>
470 <td>Edited velocity.</td>
478 <td>KDP (unknown) for MCTEX data.</td>
486 <td>TIME (unknown) for MCTEX data.</td>
491 The Volume structure</h4>
492 The Volume structure represents the RADAR data for one, and only one, field
493 type. Upon ingest, the data for each field type is separated and placed
494 into separate volumes. This makes it convenient to manipulate volumes based
496 <p>The organization of the Volume structure closely resembles the organization
497 of the Radar structure. It, too, is compose of two parts:
503 Array of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s.</li>
505 To access elements in the Volume header, you use the syntax:
507 volume->h.<i>member</i>;</pre>
508 You can find a description of each volume header member later. The array
509 of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s contains either
510 pointers to <a href="RSL_sweep_struct.html">Sweep</a>s of data or NULL.
511 The number of possible <a href="RSL_sweep_struct.html">Sweep</a>s in the
512 Volume is specified by <tt>volume->h.nsweeps</tt>. This number represents
513 the length of the array of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s
514 and not the number of actual (non-NULL) sweeps in the volume.
515 <p>There are two methods to accessing sweeps:
518 Use a loop index that ranges from 0 to <tt>volume->h.nsweeps-1</tt>.</li>
521 Use <a href="RSL_get_sweep.html">RSL_get_sweep</a> or other similiar RSL
522 sweep retieval functions.</li>
524 Here are two coding examples that demonstrate how to access the array of
531 /* Assume a non-NULL volume at this point. */
532 for (i=0; i<volume->h.nsweeps; i++) {
533 sweep = volume->sweep[i];
534 if (sweep == NULL) continue; /* Skip NULL sweeps. */
535 /* Do something with this sweep. */
536 printf("Sweep %d elevation is %f\n", i, sweep->h.elev);
543 /* No assumption about volume, it *can* be NULL! */
544 /* That's because RSL_get_sweep checks it. */
546 sweep = RSL_get_sweep(volume, elev);
548 printf("Sweep %d elevation is %f\n", i, sweep->h.elev);</pre>
549 Again, it is very important to check for NULL sweeps. By default volume->h.nsweeps
550 is the length of the array of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s.
552 The Sweep structure</h4>
553 The Sweep represents the data collected for one field type during one 360<sup>o</sup>
554 revolution of the RADAR. Like the Radar and Volume structures, the Sweep
555 organization is composed of two parts:
561 Array of pointers to <a href="RSL_ray_struct.html">Ray</a>s.</li>
563 To access elements in the Sweep header, you use the syntax:
565 sweep->h.<i>member</i>;</pre>
566 A description of each member of the Sweep header is presented later. The
567 array of pointers to <a href="RSL_ray_struct.html">Ray</a>s contains either
568 pointers to <a href="RSL_ray_struct.html">Ray</a>s of data or NULL. The
569 number of possible <a href="RSL_ray_struct.html">Ray</a>s in the Sweep
570 is specified by <tt>sweep->h.nrays</tt>. This number represents the length
571 of the array of pointers to <a href="RSL_ray_struct.html">Ray</a>s and
572 not the number of actual (non-NULL) rays in the Sweep.
573 <p>There are two methods to accessing rays:
576 Use a loop index that ranges from 0 to <tt>sweep->h.nrays-1</tt>.</li>
579 Use <a href="RSL_get_ray.html">RSL_get_ray</a> or other similiar RSL ray
580 retieval functions.</li>
582 Here are two coding examples illustrating how to access the array of pointers
583 to <a href="RSL_ray_struct.html">Ray</a>s.
589 /* Assume a non-NULL sweep at this point. */
590 for (i=0; i<sweep->h.nrays; i++) {
591 ray = sweep->ray[i];
592 if (ray == NULL) continue; /* Skip NULL rays. */
593 /* Do something with this ray. */
594 printf("Ray %d azimuth is %f\n", i, ray->h.azimuth);
601 /* No assumption about volume, it *can* be NULL! */
602 /* That's because RSL_get_ray checks it. */
605 ray = RSL_get_ray(volume, elev, azimuth);
607 printf("Ray %d elevation is %f, azimuth is %f\n", i, ray->h.elev, ray->h.azimuth);</pre>
608 You never know when you'll encounter NULL rays, so, make sure you test
609 for it. By default, sweep->h.nrays is the length of the array of pointers
610 to <a href="RSL_ray_struct.html">Ray</a>s which may or may not be the number
611 of non-NULL Rays present.
613 The Ray structure</h4>
614 A ray of RADAR measurements represents data collected from close to the
615 RADAR to some maximum physical range. The <a href="RSL_ray_struct.html">Ray</a>,
616 too, is composed of two parts:
622 Array of field type measurements. These are not pointers. It is an array
625 We're getting close to the data, now. The ray header contains the largest
626 collection of members and describe all characteristics of the ray. To access
627 elements in the Ray header, you use the syntax:
629 ray->h.<i>member</i>;</pre>
630 A description of each member of the Ray header is described later. The
631 array of field type measurements contains the data, finally. The data type
632 for the data is <a href="RSL_range_struct.html">Range</a>. The <a href="RSL_range_struct.html">Range</a>
633 data type must be converted to float by using the function that is in ray
634 header: <tt>ray->h.f(r)</tt>, where <tt>r</tt> is of type <a href="RSL_range_struct.html">Range</a>.
635 These conversion functions are in the headers for the volume and sweep.
636 They are there only as a convenience to the application developer. The
637 number of data values in the Rays is specified by <tt>ray->h.nbins</tt>.
638 This number represents the length of the array of <a href="RSL_range_struct.html">Range</a>
639 values. There is no abiguity here, the number of data values (<a href="RSL_range_struct.html">Range</a>
640 values) exactly matches <tt>ray->h.nbins</tt>.
641 <p>There are two methods to accessing the data:
644 Use a loop index that ranges from 0 to <tt>ray->h.nbins-1 </tt>calling
645 the <tt>ray->h.f</tt> function.</li>
648 Use <a href="RSL_get_value.html">RSL_get_value</a> or other similiar RSL
649 get value functions.</li>
651 Here are two coding examples illustrating how to access the array of <a href="RSL_range_struct.html">Range</a>
658 /* Assume a non-NULL ray at this point. */
659 for (i=0; i<ray->h.nbins; i++) {
660 x = ray->h.f(ray->range[i]);
661 /* Do something with this floating point value 'x'. */
662 printf("BIN %d value is %f\n", i, x);
667 float elev, azimuth, range;
669 /* No assumption about volume, it *can* be NULL! */
670 /* That's because RSL_get_value checks it. */
673 range = 87.3; /* KM */
674 x = RSL_get_value(volume, elev, azimuth, range);</pre>
677 No assumptions as to the validity of the data.</h2>
678 The RSL does not modify the data in any way. It merely, loads the data
679 into the Radar structure. For instance, during the MCTEX experiment, the
680 azimuth values were incorrect for the first four tapes. They remain incorrect.
681 It is up to you to write a conversion procedure that corrects the problem.
683 Pitfalls when using RSL in an application.</h2>
684 Here are some common mistakes made and things you should observe.
687 Not checking for NULL. It is very important to check for NULL pointers.
688 In the RSL context, NULL is a perfectly valid ray, sweep or volume. Blindly
689 assuming that a volume, sweep, or ray exists is asking for trouble. When
690 using an RSL interface routine, a routine that is prefixed with <b>RSL_</b>,
691 you don't have to worry too much about passing null pointers. RSL routines
692 check their arguments.</li>
695 Not checking for NULL, when passing a volume, sweep, or ray pointer into
696 a routine. Check for NULL immediately.</li>
699 Not using the value for <tt>radar->h.nvolumes</tt>, <tt>volume->h.nsweeps</tt>,
700 <tt>sweep->h.nray</tt>.
701 They represent the maximum index possible and not the actual number of
702 non-NULL structures. Remember a NULL sweep, in RSL, is a valid sweep; you
703 just can't do anything with it. If you want to know how many non-NULL volumes
704 you have, you'll have to count them yourself. Do that by looping from 0
705 to <tt>radar->h.nvolumes - 1</tt>.</li>
708 Not using the value for <tt>radar->h.nvolumes</tt>, <tt>volume->h.nsweeps</tt>,
709 <tt>sweep->h.nrays</tt>,
710 and <tt>ray->h.nbins</tt> for the current object. Never assume that the
711 values are constant throughout the radar structure. They constantly change.
712 For instance, the number of bins may decrease as the sweep elevation increases.</li>
715 Not converting the data in the <a href="RSL_radar_struct.html">Radar</a>,
716 <a href="RSL_volume_struct.html">Volume</a>,
717 <a href="RSL_sweep_struct.html">Sweep</a>,
718 <a href="RSL_ray_struct.html">Ray</a>,
719 (really the Ray) to floating point before comparing with anything, including
720 comparing it with BADVAL, RFVAL, APFLAG, NOECHO. Do this conversion with
721 the <tt>h.f(c)</tt>, where <tt>c</tt> is <tt>ray->range[i]</tt> and is
722 of type <a href="RSL_range_struct.html">Range</a>. For example:</li>
726 <p><tt>x = ray->h.f(ray->range[ibin]);</tt>
728 Not converting a floating point number to internal storage with <tt>h.invf(x)</tt>,
729 where <tt>x</tt> is of type float, before filling the range array. For
734 <p><tt>ray->range[ibin] = ray->h.invf(x);</tt>
736 Forgetting to load a color table before calling an image generation function.
737 If you don't load a color table, your images will be black.</li>
740 Not rebinning the velocity data before making velocity images. The default
741 color table is setup to cover the range of -nyquist to +nyquist.</li>