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>
132 <td><a href="RSL_edge_to_radar.html">RSL_edge_to_radar</a></td>
137 RSL is designed to provide you with a uniform data structure so that you
138 can design RADAR independent science applications. You no longer need to
139 wrestle over the input data format and have a different version of your
140 algorithm for each different RADAR format you may need to analyze.
141 <p>This paper presents RSL from a science application developer's point
142 of view. It will present some of the more useful routines and which fields
143 in the <a href="RSL_radar_struct.html">Radar</a> structure that will be
144 important to you and it will attempt to cover some of the programming pitfalls
145 associated with RSL usage. One of the most difficult hurdles to overcome
146 is that RSL makes extensive use of pointer syntax. You will find yourself
147 becoming expert with C pointers. However, the design of RSL makes it possible
148 to use C pointers painlessly.
150 Ok, I have some data, how do I look at it?</h2>
151 Let's first make some images. To do that you need only 3 RSL functions:
152 <p><tt><a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar</a></tt>
153 <br><tt><a href="RSL_load_color_table.html">RSL_load_refl_color_table</a></tt>
154 <br><tt><a href="RSL_volume_to.html">RSL_volume_to_gif</a></tt>
155 <p>The C program you need is incredibly short. It illustrates how to ingest
156 radar data and create a GIF image of the DZ (reflectivity) field:
157 <pre>#include "rsl.h"
158 void main(int argc, char **argv)
161 radar = RSL_anyformat_to_radar("radar.dat", NULL);
162 RSL_load_refl_color_table();
163 RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0);
166 <p><tt>#include "rsl.h"</tt>
167 <p>is required when using the RSL. It defines important constants and declares
168 all the RSL functions that your application may need.
170 <pre>Radar *radar;</pre>
171 declares the radar pointer. Only a pointer to a radar should be declared,
172 because, the ingest routines allocate all the space to hold all the appropriate
173 substructures: <a href="RSL_volume_struct.html">Volume</a>, <a href="RSL_sweep_struct.html">Sweep</a>,
174 <a href="RSL_ray_struct.html">Ray</a>,
175 and <a href="RSL_range_struct.html">Range</a>.
177 <pre>radar = RSL_anyformat_to_radar("radar.dat", NULL);</pre>
178 performs the actual ingest of data. The input file is called <tt>radar.dat</tt>.
179 <a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar
181 determines the type of radar data being read. It can handle *.gz or *.Z
182 files transparently. Reading gzip or compress files is faster, especially
183 over NFS. Generally, reading compressed radar files is faster
184 because of how UNIX pipes are implemented and that the compression is nearly
185 90%. The second argument, NULL, is optional. A second argument
186 is needed only when reading WSR-88D data. The WSR-88D site information
187 is provided in the first physical file on the 8mm tape, but, it is used
188 to fill lat/lon and other radar-site specific information when reading
189 the 2<sup>nd</sup> through last physical files on the tape.
190 <p>Note: <a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar</a>
191 can't handle every radar format for which there is an RSL ingest routine.
192 But, it does a good job at recognizing most formats. Currently, TOGA and
193 MCGILL files cannot be automatically detected. In those cases, use: <a href="RSL_toga_to_radar.html">RSL_toga_to_radar</a>
194 and <a href="RSL_mcgill_to_radar.html">RSL_mcgill_to_radar</a>.
195 <p>While basic image generation is provided in RSL, it is never intended
196 to be anything more than a diagnostic tool. Several assumptions are made,
197 but, the image generation functions provided are useful. This is what the
198 last two lines illustrate. First you must define a color table. That is
200 <pre>RSL_load_refl_color_table();</pre>
201 then, to generate disk files, gif images, you must call one of the image
202 generation functions, as in:
203 <pre>RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0);</pre>
204 This routine will generate several images, one for each sweep, mapping
205 the image to a 400 x 400 km grid, using a 1 x 1 km spacing, by collecting
207 <p>Making images of velocity data, <tt>VR_INDEX</tt>, involves two more
208 steps that are not very obvious. Because of the limited range of the values
209 presented in velocity data, you must re-bin the data. Do that with any
210 one of the following:
211 <pre><a href="RSL_rebin_velocity.html">RSL_rebin_velocity_sweep</a>,
212 <a href="RSL_rebin_velocity.html">RSL_rebin_velocity_volume</a></pre>
213 The second step is that you must call:
214 <pre><a href="RSL_load_color_table.html">RSL_load_vel_color_table()</a>;</pre>
215 The nyquist velocity is used to determine the limits of the re-binning.
217 functions modify the data in a sweep, or volume.</i> So, it is wise to
218 make copies of the sweep, or volume, if you plan on using the data later
219 in your application. Normally, though, making velocity images is the last
220 step of a program, therefore, you don't need to copy the velocity volume
221 as your program will be exiting shortly. RSL provides a number of color
222 table manipulation functions. You are not limited by the default settings
223 for DZ, VR, and SW color tables. You can specify any color table mapping
226 Whoopty doo, I really wanted to examine the values.</h2>
227 In order to get to values in the <a href="RSL_radar_struct.html">Radar</a>
228 structure, you have to trickle down all the substructues. The structures,
229 in order of nesting are: <a href="RSL_radar_struct.html">Radar</a>, <a href="RSL_volume_struct.html">Volume</a>,
230 <a href="RSL_sweep_struct.html">Sweep</a>,
231 <a href="RSL_ray_struct.html">Ray</a>,
232 <a href="RSL_range_struct.html">Range</a>.
233 Each of these structures is presented in that order. You will notice a
234 common organization across all of the structures -- each structure contains
235 a header and contains an array of pointers to the next substructure.
237 The Radar structure</h4>
238 Ok, make the call to <tt><a href="RSL_anyformat_to_radar.html">RSL_anyformat_to_radar</a></tt>
239 as above, so that you get a pointer to a radar. The structure <tt><a href="RSL_radar_struct.html">Radar</a></tt>
240 is the most general structure in RSL. Radar is composed of two parts:
246 Array of pointers to <a href="RSL_volume_struct.html">Volume</a>s.</li>
248 The radar header, will be presented and described fully later, but, it
249 contains general information about the entire structure. To access the
250 radar header use the syntax:
252 radar->h.<i>member</i>;</pre>
253 The array of pointers to <a href="RSL_volume_struct.html">Volume</a>s contains
254 either pointers to <a href="RSL_volume_struct.html">Volume</a>s of data
255 or NULL. The number of possible <a href="RSL_volume_struct.html">Volume</a>s
256 in the radar is specified by radar->h.nvolumes. This number represents
257 the length of the array of pointers to <a href="RSL_volume_struct.html">Volume</a>s
258 and not the number of actual (non-NULL) volumes in the radar. The index
259 of this array of pointers to <a href="RSL_volume_struct.html">Volume</a>s
260 is the field type index. There are MAX_RADAR_VOLUMES (currently set to
261 19) field types defined in RSL. Each field type index has a specific value.
262 That value is illustrated in the table below. RSL ingest routines guarentee
263 that the length of the array of pointers to <a href="RSL_volume_struct.html">Volume</a>s,
265 is exactly the maximum number of field types, MAX_RADAR_VOLUMES. This is
266 done so that you can check for the existance of a field type with the syntax:
267 <pre>if (radar->v[XZ_INDEX]) /* XZ exists */</pre>
268 Normally, <tt>radar->h.nvolumes</tt> is set to the length of the array
269 of pointers to <a href="RSL_volume_struct.html">Volume</a>s, <tt>radar->v</tt>.
270 Because C array indexes start at 0, you should use a test similiar to:
271 ivol < radar->h.nvolumes. The maximum value for <tt>radar->h.nvolumes</tt>
272 is MAX_RADAR_VOLUMES which is a constant in RSL. The value for <tt>radar->h.nvolumes</tt>
273 could be less though. But, you can rest assured that you can test for the
274 existance of a field type simply by using the hard coded index name as
275 specified in the table below.
276 <p>There are basically two methods for indexing the array of pointers to
277 <a href="RSL_volume_struct.html">Volume</a>s:
280 Use the index name, eg. CZ_INDEX or its value.</li>
283 Use a variable that ranges from 0 to <tt>radar->h.nvolumes</tt>-1.</li>
285 Here are two coding examples that demonstrate how to access the array of
291 volume = radar->v[CZ_INDEX];
292 if (volume != NULL) {
293 /* Do something with volume. */
300 for (i=0; i<radar->h.nvolumes) {
301 volume = radar->v[i];
302 if (volume == NULL) continue; /* skip this NULL volume */
303 /* Do something with volume. */
305 It is very important that you check for the volume pointer being NULL.
306 It is very common that <tt>radar->h.nvolumes</tt> is larger than the number
307 of non-NULL volumes present in radar. By default, <tt>radar->h.nvolumes</tt>
308 is the length of array of pointers to <a href="RSL_volume_struct.html">Volume</a>s.
309 The volumes are also known as field types. There are several field types
310 and a <a href="RSL_volume_struct.html">Volume</a> can be only one field
311 type. The entire list of field types is presented in the table below. To
312 reference a particular field, you use a simple syntax:
313 <p><tt>radar->v[DZ_INDEX]</tt>
314 <br><tt>radar->v[VR_INDEX]</tt>
315 <p>Each field type encountered has a specific index within the <tt>radar->v</tt>
316 array of pointers to <a href="RSL_volume_struct.html">Volume</a>s. The
317 field type indexes are hard-coded and are defined to be specific numbers
318 starting at 0. Hard-coded field type indexes simplifies the syntax for
319 accessing volumes. When there is no volume for a particular field type,
320 the volume pointer is NULL. This is ok, as NULL is a perfectly acceptable,
321 albeit useless, volume. Here is a table of all the field type indexes used
324 <table BORDER CELLPADDING=0 >
347 <td>Reflectivity (dBZ)</td>
355 <td>Radial Velocity (m/s)</td>
363 <td>Spectral Width (m<sup><font size=-2>2</font></sup>/s<sup><font size=-2>2</font></sup>)</td>
371 <td>QC Reflectivity (dBZ)</td>
379 <td>Total Reflectivity (dBZ)</td>
387 <td>Differential reflectivity</td>
395 <td>Another differential refl.</td>
403 <td>Reflectivity Depolarization Ratio
404 <p>ZDR = 10log(ZH/ZV) (dB)</td>
412 <td>Received power (dBm)</td>
420 <td>Rho: Correlation coefficient</td>
428 <td>Phi (MCTEX parameter)</td>
436 <td>X-band reflectivity</td>
444 <td>Corrected DR reflectivity (differential).</td>
452 <td>DZ mask volume for HDF 1C-51 product.</td>
460 <td>DR mask volume for HDF 1C-51 product.</td>
468 <td>Edited reflectivity.</td>
476 <td>Edited velocity.</td>
484 <td>KDP (unknown) for MCTEX data.</td>
492 <td>TIME (unknown) for MCTEX data.</td>
497 The Volume structure</h4>
498 The Volume structure represents the RADAR data for one, and only one, field
499 type. Upon ingest, the data for each field type is separated and placed
500 into separate volumes. This makes it convenient to manipulate volumes based
502 <p>The organization of the Volume structure closely resembles the organization
503 of the Radar structure. It, too, is compose of two parts:
509 Array of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s.</li>
511 To access elements in the Volume header, you use the syntax:
513 volume->h.<i>member</i>;</pre>
514 You can find a description of each volume header member later. The array
515 of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s contains either
516 pointers to <a href="RSL_sweep_struct.html">Sweep</a>s of data or NULL.
517 The number of possible <a href="RSL_sweep_struct.html">Sweep</a>s in the
518 Volume is specified by <tt>volume->h.nsweeps</tt>. This number represents
519 the length of the array of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s
520 and not the number of actual (non-NULL) sweeps in the volume.
521 <p>There are two methods to accessing sweeps:
524 Use a loop index that ranges from 0 to <tt>volume->h.nsweeps-1</tt>.</li>
527 Use <a href="RSL_get_sweep.html">RSL_get_sweep</a> or other similiar RSL
528 sweep retieval functions.</li>
530 Here are two coding examples that demonstrate how to access the array of
537 /* Assume a non-NULL volume at this point. */
538 for (i=0; i<volume->h.nsweeps; i++) {
539 sweep = volume->sweep[i];
540 if (sweep == NULL) continue; /* Skip NULL sweeps. */
541 /* Do something with this sweep. */
542 printf("Sweep %d elevation is %f\n", i, sweep->h.elev);
549 /* No assumption about volume, it *can* be NULL! */
550 /* That's because RSL_get_sweep checks it. */
552 sweep = RSL_get_sweep(volume, elev);
554 printf("Sweep %d elevation is %f\n", i, sweep->h.elev);</pre>
555 Again, it is very important to check for NULL sweeps. By default volume->h.nsweeps
556 is the length of the array of pointers to <a href="RSL_sweep_struct.html">Sweep</a>s.
558 The Sweep structure</h4>
559 The Sweep represents the data collected for one field type during one 360<sup>o</sup>
560 revolution of the RADAR. Like the Radar and Volume structures, the Sweep
561 organization is composed of two parts:
567 Array of pointers to <a href="RSL_ray_struct.html">Ray</a>s.</li>
569 To access elements in the Sweep header, you use the syntax:
571 sweep->h.<i>member</i>;</pre>
572 A description of each member of the Sweep header is presented later. The
573 array of pointers to <a href="RSL_ray_struct.html">Ray</a>s contains either
574 pointers to <a href="RSL_ray_struct.html">Ray</a>s of data or NULL. The
575 number of possible <a href="RSL_ray_struct.html">Ray</a>s in the Sweep
576 is specified by <tt>sweep->h.nrays</tt>. This number represents the length
577 of the array of pointers to <a href="RSL_ray_struct.html">Ray</a>s and
578 not the number of actual (non-NULL) rays in the Sweep.
579 <p>There are two methods to accessing rays:
582 Use a loop index that ranges from 0 to <tt>sweep->h.nrays-1</tt>.</li>
585 Use <a href="RSL_get_ray.html">RSL_get_ray</a> or other similiar RSL ray
586 retieval functions.</li>
588 Here are two coding examples illustrating how to access the array of pointers
589 to <a href="RSL_ray_struct.html">Ray</a>s.
595 /* Assume a non-NULL sweep at this point. */
596 for (i=0; i<sweep->h.nrays; i++) {
597 ray = sweep->ray[i];
598 if (ray == NULL) continue; /* Skip NULL rays. */
599 /* Do something with this ray. */
600 printf("Ray %d azimuth is %f\n", i, ray->h.azimuth);
607 /* No assumption about volume, it *can* be NULL! */
608 /* That's because RSL_get_ray checks it. */
611 ray = RSL_get_ray(volume, elev, azimuth);
613 printf("Ray %d elevation is %f, azimuth is %f\n", i, ray->h.elev, ray->h.azimuth);</pre>
614 You never know when you'll encounter NULL rays, so, make sure you test
615 for it. By default, sweep->h.nrays is the length of the array of pointers
616 to <a href="RSL_ray_struct.html">Ray</a>s which may or may not be the number
617 of non-NULL Rays present.
619 The Ray structure</h4>
620 A ray of RADAR measurements represents data collected from close to the
621 RADAR to some maximum physical range. The <a href="RSL_ray_struct.html">Ray</a>,
622 too, is composed of two parts:
628 Array of field type measurements. These are not pointers. It is an array
631 We're getting close to the data, now. The ray header contains the largest
632 collection of members and describe all characteristics of the ray. To access
633 elements in the Ray header, you use the syntax:
635 ray->h.<i>member</i>;</pre>
636 A description of each member of the Ray header is described later. The
637 array of field type measurements contains the data, finally. The data type
638 for the data is <a href="RSL_range_struct.html">Range</a>. The <a href="RSL_range_struct.html">Range</a>
639 data type must be converted to float by using the function that is in ray
640 header: <tt>ray->h.f(r)</tt>, where <tt>r</tt> is of type <a href="RSL_range_struct.html">Range</a>.
641 These conversion functions are in the headers for the volume and sweep.
642 They are there only as a convenience to the application developer. The
643 number of data values in the Rays is specified by <tt>ray->h.nbins</tt>.
644 This number represents the length of the array of <a href="RSL_range_struct.html">Range</a>
645 values. There is no abiguity here, the number of data values (<a href="RSL_range_struct.html">Range</a>
646 values) exactly matches <tt>ray->h.nbins</tt>.
647 <p>There are two methods to accessing the data:
650 Use a loop index that ranges from 0 to <tt>ray->h.nbins-1 </tt>calling
651 the <tt>ray->h.f</tt> function.</li>
654 Use <a href="RSL_get_value.html">RSL_get_value</a> or other similiar RSL
655 get value functions.</li>
657 Here are two coding examples illustrating how to access the array of <a href="RSL_range_struct.html">Range</a>
664 /* Assume a non-NULL ray at this point. */
665 for (i=0; i<ray->h.nbins; i++) {
666 x = ray->h.f(ray->range[i]);
667 /* Do something with this floating point value 'x'. */
668 printf("BIN %d value is %f\n", i, x);
673 float elev, azimuth, range;
675 /* No assumption about volume, it *can* be NULL! */
676 /* That's because RSL_get_value checks it. */
679 range = 87.3; /* KM */
680 x = RSL_get_value(volume, elev, azimuth, range);</pre>
683 No assumptions as to the validity of the data.</h2>
684 The RSL does not modify the data in any way. It merely, loads the data
685 into the Radar structure. For instance, during the MCTEX experiment, the
686 azimuth values were incorrect for the first four tapes. They remain incorrect.
687 It is up to you to write a conversion procedure that corrects the problem.
689 Pitfalls when using RSL in an application.</h2>
690 Here are some common mistakes made and things you should observe.
693 Not checking for NULL. It is very important to check for NULL pointers.
694 In the RSL context, NULL is a perfectly valid ray, sweep or volume. Blindly
695 assuming that a volume, sweep, or ray exists is asking for trouble. When
696 using an RSL interface routine, a routine that is prefixed with <b>RSL_</b>,
697 you don't have to worry too much about passing null pointers. RSL routines
698 check their arguments.</li>
701 Not checking for NULL, when passing a volume, sweep, or ray pointer into
702 a routine. Check for NULL immediately.</li>
705 Not using the value for <tt>radar->h.nvolumes</tt>, <tt>volume->h.nsweeps</tt>,
706 <tt>sweep->h.nray</tt>.
707 They represent the maximum index possible and not the actual number of
708 non-NULL structures. Remember a NULL sweep, in RSL, is a valid sweep; you
709 just can't do anything with it. If you want to know how many non-NULL volumes
710 you have, you'll have to count them yourself. Do that by looping from 0
711 to <tt>radar->h.nvolumes - 1</tt>.</li>
714 Not using the value for <tt>radar->h.nvolumes</tt>, <tt>volume->h.nsweeps</tt>,
715 <tt>sweep->h.nrays</tt>,
716 and <tt>ray->h.nbins</tt> for the current object. Never assume that the
717 values are constant throughout the radar structure. They constantly change.
718 For instance, the number of bins may decrease as the sweep elevation increases.</li>
721 Not converting the data in the <a href="RSL_radar_struct.html">Radar</a>,
722 <a href="RSL_volume_struct.html">Volume</a>,
723 <a href="RSL_sweep_struct.html">Sweep</a>,
724 <a href="RSL_ray_struct.html">Ray</a>,
725 (really the Ray) to floating point before comparing with anything, including
726 comparing it with BADVAL, RFVAL, APFLAG, NOECHO. Do this conversion with
727 the <tt>h.f(c)</tt>, where <tt>c</tt> is <tt>ray->range[i]</tt> and is
728 of type <a href="RSL_range_struct.html">Range</a>. For example:</li>
732 <p><tt>x = ray->h.f(ray->range[ibin]);</tt>
734 Not converting a floating point number to internal storage with <tt>h.invf(x)</tt>,
735 where <tt>x</tt> is of type float, before filling the range array. For
740 <p><tt>ray->range[ibin] = ray->h.invf(x);</tt>
742 Forgetting to load a color table before calling an image generation function.
743 If you don't load a color table, your images will be black.</li>
746 Not rebinning the velocity data before making velocity images. The default
747 color table is setup to cover the range of -nyquist to +nyquist.</li>