From 012916676d26251849e408aaf574458e196df2c4 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Wed, 28 Oct 2009 01:36:10 +0000 Subject: [PATCH] Initial import --- .gitignore | 27 + CHANGES | 1655 ++++++++++++++++++++++ CHECK_LIST | 84 ++ Copyright | 22 + GPL | 339 +++++ LGPL | 481 +++++++ Makefile.am | 73 + README | 237 ++++ africa.c | 141 ++ africa.h | 69 + africa_to_radar.c | 163 +++ anyformat_to_radar.c | 171 +++ cappi.c | 192 +++ carpi.c | 302 ++++ colors/Makefile.am | 6 + colors/blu_dz.clr | Bin 0 -> 206 bytes colors/blu_height.clr | Bin 0 -> 236 bytes colors/blu_hh.clr | Bin 0 -> 236 bytes colors/blu_rainfall.clr | Bin 0 -> 216 bytes colors/blu_reflectivity.clr | Bin 0 -> 206 bytes colors/blu_reflectivity1.clr | Bin 0 -> 206 bytes colors/blu_spectral_width.clr | Bin 0 -> 236 bytes colors/blu_sw.clr | Bin 0 -> 236 bytes colors/blu_velocity.clr | Bin 0 -> 192 bytes colors/blu_vr.clr | Bin 0 -> 236 bytes colors/blu_zdr.clr | Bin 0 -> 192 bytes colors/grn_dz.clr | Bin 0 -> 206 bytes colors/grn_height.clr | Bin 0 -> 236 bytes colors/grn_hh.clr | Bin 0 -> 236 bytes colors/grn_rainfall.clr | Bin 0 -> 216 bytes colors/grn_reflectivity.clr | Bin 0 -> 206 bytes colors/grn_reflectivity1.clr | Bin 0 -> 206 bytes colors/grn_spectral_width.clr | Bin 0 -> 236 bytes colors/grn_sw.clr | Bin 0 -> 236 bytes colors/grn_velocity.clr | Bin 0 -> 192 bytes colors/grn_vr.clr | Bin 0 -> 236 bytes colors/grn_zdr.clr | Bin 0 -> 192 bytes colors/red_dz.clr | Bin 0 -> 206 bytes colors/red_height.clr | Bin 0 -> 236 bytes colors/red_hh.clr | Bin 0 -> 236 bytes colors/red_rainfall.clr | Bin 0 -> 216 bytes colors/red_reflectivity.clr | Bin 0 -> 206 bytes colors/red_reflectivity1.clr | Bin 0 -> 206 bytes colors/red_spectral_width.clr | Bin 0 -> 236 bytes colors/red_sw.clr | Bin 0 -> 236 bytes colors/red_velocity.clr | Bin 0 -> 192 bytes colors/red_vr.clr | Bin 0 -> 236 bytes colors/red_zdr.clr | Bin 0 -> 192 bytes configure.in | 90 ++ cube.c | 265 ++++ doc/Example_RSL_copy.html | 31 + doc/Makefile.am | 12 + doc/RSL_Er_loc_struct.html | 16 + doc/RSL_add_dbz_offset.html | 43 + doc/RSL_allocate_histogram.html | 25 + doc/RSL_anyformat_to_radar.html | 87 ++ doc/RSL_area_of_ray.html | 31 + doc/RSL_azimuth_hash_struct.html | 13 + doc/RSL_bscan.html | 35 + doc/RSL_cappi_at_h.html | 31 + doc/RSL_cappi_struct.html | 26 + doc/RSL_cappi_to_carpi.html | 31 + doc/RSL_carpi_struct.html | 29 + doc/RSL_carpi_value.html | 8 + doc/RSL_carpi_value_struct.html | 8 + doc/RSL_clear.html | 34 + doc/RSL_color_table.html | 77 + doc/RSL_copy.html | 34 + doc/RSL_copyright.html | 36 + doc/RSL_cube_struct.html | 19 + doc/RSL_edge_to_radar.html | 48 + doc/RSL_enum_sorted_type.html | 10 + doc/RSL_fill_cappi.html | 31 + doc/RSL_find_rng_azm.html | 28 + doc/RSL_fix_time.html | 39 + doc/RSL_fraction_of.html | 31 + doc/RSL_fractional_area_of_sweep.html | 31 + doc/RSL_free.html | 33 + doc/RSL_free_cappi.html | 40 + doc/RSL_free_histogram.html | 26 + doc/RSL_free_radar.html | 30 + doc/RSL_get_closest_ray_from_sweep.html | 32 + doc/RSL_get_closest_sweep.html | 31 + doc/RSL_get_first_ray_of.html | 32 + doc/RSL_get_first_sweep_of_volume.html | 32 + doc/RSL_get_gr_slantr_h.html | 31 + doc/RSL_get_groundr_and_h.html | 30 + doc/RSL_get_histogram_from.html | 33 + doc/RSL_get_linear_value.html | 31 + doc/RSL_get_next_cwise_ray.html | 35 + doc/RSL_get_nyquist_from_radar.html | 32 + doc/RSL_get_range_of_range_index.html | 27 + doc/RSL_get_ray.html | 31 + doc/RSL_get_ray_above-below.html | 35 + doc/RSL_get_ray_from_sweep.html | 31 + doc/RSL_get_slantr_and_elev.html | 30 + doc/RSL_get_slantr_and_h.html | 30 + doc/RSL_get_slice_from_cube.html | 33 + doc/RSL_get_sweep.html | 33 + doc/RSL_get_sweep_index_from_volume.html | 29 + doc/RSL_get_value.html | 43 + doc/RSL_get_value_from_cappi.html | 31 + doc/RSL_get_volume.html | 69 + doc/RSL_get_win.html | 34 + doc/RSL_hash_table_struct.html | 15 + doc/RSL_hdf_to_radar.html | 59 + doc/RSL_histogram_struct.html | 17 + doc/RSL_lassen_to_radar.html | 33 + doc/RSL_load_color_table.html | 72 + doc/RSL_mcgill_to_radar.html | 34 + doc/RSL_new.html | 48 + doc/RSL_new_cappi.html | 33 + doc/RSL_new_carpi.html | 31 + doc/RSL_nsig_to_radar.html | 57 + doc/RSL_print_histogram.html | 31 + doc/RSL_print_version.html | 40 + doc/RSL_prune.html | 35 + doc/RSL_radar_file_format.html | 14 + doc/RSL_radar_header_struct.html | 41 + doc/RSL_radar_intro.html | 112 ++ doc/RSL_radar_struct.html | 92 ++ doc/RSL_radar_to_hdf.html | 50 + doc/RSL_radar_to_uf.html | 39 + doc/RSL_radar_verbose.html | 29 + doc/RSL_radtec_to_radar.html | 43 + doc/RSL_range_struct.html | 20 + doc/RSL_rapic_to_radar.html | 44 + doc/RSL_ray_header_struct.html | 19 + doc/RSL_ray_struct.html | 18 + doc/RSL_read.html | 41 + doc/RSL_read_histogram.html | 31 + doc/RSL_read_radar.html | 33 + doc/RSL_read_these_sweeps.html | 64 + doc/RSL_rebin.html | 52 + doc/RSL_rebin_velocity.html | 49 + doc/RSL_return_eth_sweep.html | 48 + doc/RSL_return_hzmax_sweep.html | 38 + doc/RSL_return_zmax_sweep.html | 47 + doc/RSL_reverse.html | 17 + doc/RSL_select_fields.html | 71 + doc/RSL_set_hdf_qc_parameters.html | 46 + doc/RSL_sort.html | 41 + doc/RSL_structures.html | 27 + doc/RSL_sweep_header_struct.html | 20 + doc/RSL_sweep_struct.html | 13 + doc/RSL_sweep_to.html | 73 + doc/RSL_sweep_to_cart.html | 31 + doc/RSL_toga_to_radar.html | 33 + doc/RSL_uf_to_radar.html | 37 + doc/RSL_volume_header_struct.html | 18 + doc/RSL_volume_struct.html | 14 + doc/RSL_volume_to.html | 69 + doc/RSL_volume_to_carpi.html | 31 + doc/RSL_volume_to_cube.html | 36 + doc/RSL_write.html | 40 + doc/RSL_write_histogram.html | 31 + doc/RSL_write_radar.html | 41 + doc/RSL_wsr88d_to_radar.html | 33 + doc/RSL_z_to_r.html | 30 + doc/alan.mcconnell.html | 9 + doc/changes.gif | Bin 0 -> 4336 bytes doc/david.wolff.html | 19 + doc/dennis.flanigan.html | 9 + doc/field_but.gif | Bin 0 -> 2737 bytes doc/functionality_index.html | 279 ++++ doc/gv_but.gif | Bin 0 -> 2726 bytes doc/gv_sites_but.gif | Bin 0 -> 2771 bytes doc/home_but.gif | Bin 0 -> 1611 bytes doc/hot.gif | Bin 0 -> 500 bytes doc/index.html | 164 +++ doc/internal_routines.html | 248 ++++ doc/john.merritt.html | 10 + doc/mike.kolander.html | 9 + doc/programmers_guide.html | 409 ++++++ doc/quick_ref.gif | Bin 0 -> 786 bytes doc/quick_ref.html | 290 ++++ doc/quickref.gif | Bin 0 -> 4176 bytes doc/rain.gif | Bin 0 -> 1901 bytes doc/rsl.fig | 79 ++ doc/rsl.gif | Bin 0 -> 2194 bytes doc/rsl3.gif | Bin 0 -> 15701 bytes doc/rsl_big.jpg | Bin 0 -> 51776 bytes doc/search.gif | Bin 0 -> 809 bytes doc/search_rsl.html | 20 + doc/software_but.gif | Bin 0 -> 1707 bytes doc/t2do.gif | Bin 0 -> 8395 bytes doc/users_guide.html | 751 ++++++++++ doc/whats_new.gif | Bin 0 -> 1030 bytes doc/whats_new.html | 185 +++ doc/x_to_radar.fig | 48 + dorade.c | 616 ++++++++ dorade.h | 324 +++++ dorade_print.c | 245 ++++ dorade_to_radar.c | 255 ++++ edge_to_radar.c | 496 +++++++ endian.c | 73 + examples/Makefile.am | 24 + examples/adjust_gate_size.c | 100 ++ examples/any_to_gif.c | 167 +++ examples/any_to_ppm.c | 78 + examples/any_to_uf.c | 52 + examples/any_to_ufgz.c | 52 + examples/bscan.c | 88 ++ examples/cappi_image.c | 82 ++ examples/dorade_main.c | 21 + examples/killer_sweep.c | 180 +++ examples/kwaj_subtract_one_day.c | 121 ++ examples/lassen_to_gif.c | 32 + examples/print_hash_table.c | 121 ++ examples/print_header_info.c | 188 +++ examples/qlook.c | 688 +++++++++ examples/qlook_usage.c | 141 ++ examples/run_tests | 225 +++ examples/sector.c | 110 ++ examples/test_get_win.c | 128 ++ examples/wsr88d_to_gif.c | 59 + examples/wsr_hist_uf_test.c | 86 ++ farea.c | 142 ++ fix_headers.c | 131 ++ fraction.c | 131 ++ get_win.c | 204 +++ gts.c | 111 ++ gzip.c | 109 ++ hdf_to_radar.c | 966 +++++++++++++ histogram.c | 280 ++++ image_gen.c | 1255 ++++++++++++++++ interp.c | 436 ++++++ lassen.c | 523 +++++++ lassen.h | 299 ++++ lassen_to_radar.c | 460 ++++++ mcgill.c | 430 ++++++ mcgill.h | 109 ++ mcgill_to_radar.c | 503 +++++++ nsig.c | 644 +++++++++ nsig.h | 921 ++++++++++++ nsig2_to_radar.c | 23 + nsig_to_radar.c | 788 ++++++++++ prune.c | 107 ++ radar.c | 199 +++ radar_to_hdf_1.c | 1107 +++++++++++++++ radar_to_hdf_2.c | 781 ++++++++++ radar_to_uf.c | 539 +++++++ radtec.c | 300 ++++ radtec.h | 138 ++ radtec_to_radar.c | 216 +++ rainbow.c | 286 ++++ rainbow.h | 61 + rainbow_to_radar.c | 308 ++++ range.c | 183 +++ rapic-lex.l | 119 ++ rapic.y | 624 ++++++++ rapic_routines.c | 323 +++++ rapic_routines.h | 115 ++ rapic_to_radar.c | 34 + ray_indexes.c | 241 ++++ read_write.c | 382 +++++ reverse.c | 48 + rsl.h | 819 +++++++++++ sort_rays.c | 235 +++ toga.c | 808 +++++++++++ toga.h | 346 +++++ toga_to_radar.c | 478 +++++++ toolkit_1BC-51_appl.h | 97 ++ toolkit_memory_mgt.c | 189 +++ uf_to_radar.c | 633 +++++++++ volume.c | 1620 +++++++++++++++++++++ wsr88d.c | 975 +++++++++++++ wsr88d.h | 219 +++ wsr88d_get_site.c | 98 ++ wsr88d_locations.dat | 146 ++ wsr88d_m31.c | 781 ++++++++++ wsr88d_to_radar.c | 433 ++++++ 272 files changed, 37980 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGES create mode 100644 CHECK_LIST create mode 100644 Copyright create mode 100644 GPL create mode 100644 LGPL create mode 100644 Makefile.am create mode 100644 README create mode 100644 africa.c create mode 100644 africa.h create mode 100644 africa_to_radar.c create mode 100644 anyformat_to_radar.c create mode 100644 cappi.c create mode 100644 carpi.c create mode 100644 colors/Makefile.am create mode 100644 colors/blu_dz.clr create mode 100644 colors/blu_height.clr create mode 100644 colors/blu_hh.clr create mode 100644 colors/blu_rainfall.clr create mode 100644 colors/blu_reflectivity.clr create mode 100644 colors/blu_reflectivity1.clr create mode 100644 colors/blu_spectral_width.clr create mode 100644 colors/blu_sw.clr create mode 100644 colors/blu_velocity.clr create mode 100644 colors/blu_vr.clr create mode 100644 colors/blu_zdr.clr create mode 100644 colors/grn_dz.clr create mode 100644 colors/grn_height.clr create mode 100644 colors/grn_hh.clr create mode 100644 colors/grn_rainfall.clr create mode 100644 colors/grn_reflectivity.clr create mode 100644 colors/grn_reflectivity1.clr create mode 100644 colors/grn_spectral_width.clr create mode 100644 colors/grn_sw.clr create mode 100644 colors/grn_velocity.clr create mode 100644 colors/grn_vr.clr create mode 100644 colors/grn_zdr.clr create mode 100644 colors/red_dz.clr create mode 100644 colors/red_height.clr create mode 100644 colors/red_hh.clr create mode 100644 colors/red_rainfall.clr create mode 100644 colors/red_reflectivity.clr create mode 100644 colors/red_reflectivity1.clr create mode 100644 colors/red_spectral_width.clr create mode 100644 colors/red_sw.clr create mode 100644 colors/red_velocity.clr create mode 100644 colors/red_vr.clr create mode 100644 colors/red_zdr.clr create mode 100644 configure.in create mode 100644 cube.c create mode 100644 doc/Example_RSL_copy.html create mode 100644 doc/Makefile.am create mode 100644 doc/RSL_Er_loc_struct.html create mode 100644 doc/RSL_add_dbz_offset.html create mode 100644 doc/RSL_allocate_histogram.html create mode 100644 doc/RSL_anyformat_to_radar.html create mode 100644 doc/RSL_area_of_ray.html create mode 100644 doc/RSL_azimuth_hash_struct.html create mode 100644 doc/RSL_bscan.html create mode 100644 doc/RSL_cappi_at_h.html create mode 100644 doc/RSL_cappi_struct.html create mode 100644 doc/RSL_cappi_to_carpi.html create mode 100644 doc/RSL_carpi_struct.html create mode 100644 doc/RSL_carpi_value.html create mode 100644 doc/RSL_carpi_value_struct.html create mode 100644 doc/RSL_clear.html create mode 100644 doc/RSL_color_table.html create mode 100644 doc/RSL_copy.html create mode 100644 doc/RSL_copyright.html create mode 100644 doc/RSL_cube_struct.html create mode 100644 doc/RSL_edge_to_radar.html create mode 100644 doc/RSL_enum_sorted_type.html create mode 100644 doc/RSL_fill_cappi.html create mode 100644 doc/RSL_find_rng_azm.html create mode 100644 doc/RSL_fix_time.html create mode 100644 doc/RSL_fraction_of.html create mode 100644 doc/RSL_fractional_area_of_sweep.html create mode 100644 doc/RSL_free.html create mode 100644 doc/RSL_free_cappi.html create mode 100644 doc/RSL_free_histogram.html create mode 100644 doc/RSL_free_radar.html create mode 100644 doc/RSL_get_closest_ray_from_sweep.html create mode 100644 doc/RSL_get_closest_sweep.html create mode 100644 doc/RSL_get_first_ray_of.html create mode 100644 doc/RSL_get_first_sweep_of_volume.html create mode 100644 doc/RSL_get_gr_slantr_h.html create mode 100644 doc/RSL_get_groundr_and_h.html create mode 100644 doc/RSL_get_histogram_from.html create mode 100644 doc/RSL_get_linear_value.html create mode 100644 doc/RSL_get_next_cwise_ray.html create mode 100644 doc/RSL_get_nyquist_from_radar.html create mode 100644 doc/RSL_get_range_of_range_index.html create mode 100644 doc/RSL_get_ray.html create mode 100644 doc/RSL_get_ray_above-below.html create mode 100644 doc/RSL_get_ray_from_sweep.html create mode 100644 doc/RSL_get_slantr_and_elev.html create mode 100644 doc/RSL_get_slantr_and_h.html create mode 100644 doc/RSL_get_slice_from_cube.html create mode 100644 doc/RSL_get_sweep.html create mode 100644 doc/RSL_get_sweep_index_from_volume.html create mode 100644 doc/RSL_get_value.html create mode 100644 doc/RSL_get_value_from_cappi.html create mode 100644 doc/RSL_get_volume.html create mode 100644 doc/RSL_get_win.html create mode 100644 doc/RSL_hash_table_struct.html create mode 100644 doc/RSL_hdf_to_radar.html create mode 100644 doc/RSL_histogram_struct.html create mode 100644 doc/RSL_lassen_to_radar.html create mode 100644 doc/RSL_load_color_table.html create mode 100644 doc/RSL_mcgill_to_radar.html create mode 100644 doc/RSL_new.html create mode 100644 doc/RSL_new_cappi.html create mode 100644 doc/RSL_new_carpi.html create mode 100644 doc/RSL_nsig_to_radar.html create mode 100644 doc/RSL_print_histogram.html create mode 100644 doc/RSL_print_version.html create mode 100644 doc/RSL_prune.html create mode 100644 doc/RSL_radar_file_format.html create mode 100644 doc/RSL_radar_header_struct.html create mode 100644 doc/RSL_radar_intro.html create mode 100644 doc/RSL_radar_struct.html create mode 100644 doc/RSL_radar_to_hdf.html create mode 100644 doc/RSL_radar_to_uf.html create mode 100644 doc/RSL_radar_verbose.html create mode 100644 doc/RSL_radtec_to_radar.html create mode 100644 doc/RSL_range_struct.html create mode 100644 doc/RSL_rapic_to_radar.html create mode 100644 doc/RSL_ray_header_struct.html create mode 100644 doc/RSL_ray_struct.html create mode 100644 doc/RSL_read.html create mode 100644 doc/RSL_read_histogram.html create mode 100644 doc/RSL_read_radar.html create mode 100644 doc/RSL_read_these_sweeps.html create mode 100644 doc/RSL_rebin.html create mode 100644 doc/RSL_rebin_velocity.html create mode 100644 doc/RSL_return_eth_sweep.html create mode 100644 doc/RSL_return_hzmax_sweep.html create mode 100644 doc/RSL_return_zmax_sweep.html create mode 100644 doc/RSL_reverse.html create mode 100644 doc/RSL_select_fields.html create mode 100644 doc/RSL_set_hdf_qc_parameters.html create mode 100644 doc/RSL_sort.html create mode 100644 doc/RSL_structures.html create mode 100644 doc/RSL_sweep_header_struct.html create mode 100644 doc/RSL_sweep_struct.html create mode 100644 doc/RSL_sweep_to.html create mode 100644 doc/RSL_sweep_to_cart.html create mode 100644 doc/RSL_toga_to_radar.html create mode 100644 doc/RSL_uf_to_radar.html create mode 100644 doc/RSL_volume_header_struct.html create mode 100644 doc/RSL_volume_struct.html create mode 100644 doc/RSL_volume_to.html create mode 100644 doc/RSL_volume_to_carpi.html create mode 100644 doc/RSL_volume_to_cube.html create mode 100644 doc/RSL_write.html create mode 100644 doc/RSL_write_histogram.html create mode 100644 doc/RSL_write_radar.html create mode 100644 doc/RSL_wsr88d_to_radar.html create mode 100644 doc/RSL_z_to_r.html create mode 100644 doc/alan.mcconnell.html create mode 100644 doc/changes.gif create mode 100644 doc/david.wolff.html create mode 100644 doc/dennis.flanigan.html create mode 100644 doc/field_but.gif create mode 100644 doc/functionality_index.html create mode 100644 doc/gv_but.gif create mode 100644 doc/gv_sites_but.gif create mode 100644 doc/home_but.gif create mode 100644 doc/hot.gif create mode 100644 doc/index.html create mode 100644 doc/internal_routines.html create mode 100644 doc/john.merritt.html create mode 100644 doc/mike.kolander.html create mode 100644 doc/programmers_guide.html create mode 100644 doc/quick_ref.gif create mode 100644 doc/quick_ref.html create mode 100644 doc/quickref.gif create mode 100644 doc/rain.gif create mode 100644 doc/rsl.fig create mode 100644 doc/rsl.gif create mode 100644 doc/rsl3.gif create mode 100644 doc/rsl_big.jpg create mode 100644 doc/search.gif create mode 100644 doc/search_rsl.html create mode 100644 doc/software_but.gif create mode 100644 doc/t2do.gif create mode 100644 doc/users_guide.html create mode 100644 doc/whats_new.gif create mode 100644 doc/whats_new.html create mode 100644 doc/x_to_radar.fig create mode 100644 dorade.c create mode 100644 dorade.h create mode 100644 dorade_print.c create mode 100644 dorade_to_radar.c create mode 100644 edge_to_radar.c create mode 100644 endian.c create mode 100644 examples/Makefile.am create mode 100644 examples/adjust_gate_size.c create mode 100644 examples/any_to_gif.c create mode 100644 examples/any_to_ppm.c create mode 100644 examples/any_to_uf.c create mode 100644 examples/any_to_ufgz.c create mode 100644 examples/bscan.c create mode 100644 examples/cappi_image.c create mode 100644 examples/dorade_main.c create mode 100644 examples/killer_sweep.c create mode 100644 examples/kwaj_subtract_one_day.c create mode 100644 examples/lassen_to_gif.c create mode 100644 examples/print_hash_table.c create mode 100644 examples/print_header_info.c create mode 100644 examples/qlook.c create mode 100644 examples/qlook_usage.c create mode 100755 examples/run_tests create mode 100644 examples/sector.c create mode 100644 examples/test_get_win.c create mode 100644 examples/wsr88d_to_gif.c create mode 100644 examples/wsr_hist_uf_test.c create mode 100644 farea.c create mode 100644 fix_headers.c create mode 100644 fraction.c create mode 100644 get_win.c create mode 100644 gts.c create mode 100644 gzip.c create mode 100644 hdf_to_radar.c create mode 100644 histogram.c create mode 100644 image_gen.c create mode 100644 interp.c create mode 100644 lassen.c create mode 100644 lassen.h create mode 100644 lassen_to_radar.c create mode 100644 mcgill.c create mode 100644 mcgill.h create mode 100644 mcgill_to_radar.c create mode 100644 nsig.c create mode 100644 nsig.h create mode 100644 nsig2_to_radar.c create mode 100644 nsig_to_radar.c create mode 100644 prune.c create mode 100644 radar.c create mode 100644 radar_to_hdf_1.c create mode 100644 radar_to_hdf_2.c create mode 100644 radar_to_uf.c create mode 100644 radtec.c create mode 100644 radtec.h create mode 100644 radtec_to_radar.c create mode 100644 rainbow.c create mode 100644 rainbow.h create mode 100644 rainbow_to_radar.c create mode 100644 range.c create mode 100644 rapic-lex.l create mode 100644 rapic.y create mode 100644 rapic_routines.c create mode 100644 rapic_routines.h create mode 100644 rapic_to_radar.c create mode 100644 ray_indexes.c create mode 100644 read_write.c create mode 100644 reverse.c create mode 100644 rsl.h create mode 100644 sort_rays.c create mode 100644 toga.c create mode 100644 toga.h create mode 100644 toga_to_radar.c create mode 100644 toolkit_1BC-51_appl.h create mode 100644 toolkit_memory_mgt.c create mode 100644 uf_to_radar.c create mode 100644 volume.c create mode 100644 wsr88d.c create mode 100644 wsr88d.h create mode 100644 wsr88d_get_site.c create mode 100644 wsr88d_locations.dat create mode 100644 wsr88d_m31.c create mode 100644 wsr88d_to_radar.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ccbb51d --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +*.bz2 +*.gz +*~ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +core +depcomp +gmon.out +gtk-doc.make +install-sh +libtool +local +ltmain.sh +missing +stamp-h1 +tags +valgrind.out diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..af29ca9 --- /dev/null +++ b/CHANGES @@ -0,0 +1,1655 @@ +/* Changes for RSL + * + *--------------------------------------------------------------------- + * v1.40 Released 10/10/2008 + * + * 1. wsr88d_m31.c (load_wsr88d_m31_into_radar): Corrected a potential problem + * in which the end of sweep or volume might occur at a point in the program + * that was isolated from the code that handles that condition. + * Store vcp in radar header. + * 2. rsl.h: Added vcp to radar header structure for WSR-88D. + * 3. nsig_to_radar.c: Corrected a problem involving Extended Header, which + * when present, caused elevation in ray header to be set to 0. + * 4. wsr88d_m31.c (wsr88d_load_ray_into_radar): Changed the way we determine + * whether or not to keep the reflectivity field (we don't want it from + * Doppler split cuts). The previous method was inadequate for VCP 121. + * 5. read_write.c (RSL_write_radar_fp, RSL_write_volume, RSL_write_sweep) + * (RSL_write_ray): Initialize header_buf to zero to avoid junk in output + * files. This provides clean outputs for comparing in test situations. + *--------------------------------------------------------------------- + * v1.39 Released 07/24/2008 + * + * 1. Added wsr88d_m31.c. It contains routines to handle new Message Type 31 + * in WSR-88D Level II Build 10. + * 2. wsr88d_to_radar.c: Modified to call message 31 routine. + * 3. wsr88d.c: Added code for VCPs 211, 212, 213. + * 4. lassen_to_radar.c: Added a fix for PhiDP provided by Scott Collis of BMRC. + * + *--------------------------------------------------------------------- + * v1.38 Released 11/29/2007 + * + * 1. wsr88d.c (wsr88d_read_sweep): Modified to handle unusual message packets + * at start of WSR-88D files from some future GPM sites. + * + *--------------------------------------------------------------------- + * v1.37 Released 06/19/2007 (Severity: low) + * + * 1. radar_to_uf.c, uf_to_radar.c: Modified to use Local Use Header to store + * and retrieve WSR-88D VR azimuth. This is necessary because WSR-88D runs + * separate scans for DZ and VR at lower elevations, which means that they + * have different azimuths for a given ray. Thanks go to Pat Kennedy of CSU + * for discovering this problem and for bringing it to our attention. + * 2. lassen_load_sweep in lassen_to_radar.c: Removed 1.4 dB correction for + * reflectivity--BMRC version no longer uses it. + * + *--------------------------------------------------------------------- + * v1.36 Released 08/29/2006 (Severity: low) + * + * 1. Forgot to put the modified wsr88d_locations.dat file into previous + * release. + * + *--------------------------------------------------------------------- + * v1.35 Released 08/28/2006 (Severity: low) + * + * 1. lassen_to_radar.c: fixed a bug in lassen_load_sweep where sweep index + * was being used for sweep number in headers. + * 2. radar.c: Modified RSL_get_volume to return volume for any field type. + * It had been limited to velocity, spectrum width and reflectivity types. + * 3. Added SQ_INDEX for Signal Quality Index field. Files modified: rsl.h, + * volume.c, nsig_to_radar.c, nsig.h, uf_to_radar.c, radar_to_uf.c. + * 4. wsr88d_locations.dat modified to change height units from feet to meters. + * Thanks go to Dave Makofski for finding and fixing that one. + * + *--------------------------------------------------------------------- + * v1.34 Released 02/15/2006 (Severity: low) + * + * 1. wsr88d.c: Fixed a bug in checking msg_type. The problem occurred while + * processing data from Houston, which recently switched over to the new + * Open RDA (ORDA) being implemented by NEXRAD. Msg_type is in the + * righthand byte of a two-byte word, the left containing Channel ID, + * but the full two-byte value was being used to check msg_type. This + * became a problem when ORDA used a non-zero value for Channel ID. + * 2. wsr88d.c and wsr88d_to_radar.c: Added information for new VCPs 12 and + * 121. + * 3. Added Huntsville site to wsr88d_locations.dat. + * + *--------------------------------------------------------------------- + * v1.33 Began 02/25/2004. Released 08/27/2004 (Severity: low) + * + * 1. Modified wsr88d_to_radar.c and anyformat_to_radar.c to handle change in + * WSR-88D header record for Level II Build 5 data format. + * 2. Fixed a bug in wsr88d.c, wsr88d_read_sweep, which caused the last ray + * of sweep to be deleted along with empty rays in second tilt and above. + * + *--------------------------------------------------------------------- + * v1.32 Began 11/05/2003. Released 02/13/2004 (Severity: low) + * + * 1. Changed computation of sweep seconds in nsig_to_radar.c to eliminate + * rounding error. + * 2. wsr88d_to_radar.c: removed call to wsr88d_get_wavelength, which computed + * the WSR-88D wavelength when parameters were available, or returned a + * constant otherwise. Replaced with constant wavelength of 10 cm. Thanks to + * Joe Holmes of SIGMET for noticing differing wavelengths between fields. + * 3. Added ingest for Rainbow format. Only handles DZ. + * + *--------------------------------------------------------------------- + * v1.31 Began 04/30/2003. Released 09/03/2003 (Severity: low) + * + * 1. nsig_to_radar.c: removed unused #define, made some cosmetic changes in + * code and comment alignment. + * 2. Makefile.am: Added line to install include-directory under target + * install-exec-hook. + * 3. Added code to configure.in to fix yywrap unresolved reference that + * occurred when installing rsl when the TSDIS toolkit was not installed. + * + *--------------------------------------------------------------------- + * v1.30 Began 07/30/2001. Released 03/13/2003 (Severity: low) + * + * 1. Increased the size of parameter arrays in nsig.c as recommended by + * Paul Kucera, to accommodate NPOL polarimetric parameters. + * 2. Fixed a bug in nsig_endianess in nsig.c. + * 3. Modified uf_to_radar to compute unambiguous range using PRF. Reduced + * UF record length by removing extra byte at end of record. Made to handle + * 4-digit years (previously assumed 2-digit, as declared in UF documention). + * 4. Modified hdf_to_radar to use more accurate value for sweep.h.nrays. + * 5. Corrected computation in function wsr88d_get_azimuth_rate in wsr88d.c. + * 6. Fixed bug in sweep rate computation in wsr88d.c + * 7. Changed wsr88d_ray_to_float in wsr88d.c to use field data pointers + * provided in the data, instead of computing offsets. The latter method is + * incorrect according to NOAA Radar Operations Center. + * 8. Modified radar_to_uf to get fixed angle for mandatory header from value + * stored in ray. Previously used average elevation of sweep. + * 9. Added examples/adjust_gate_size.c, and added enhanced version of qlook.c + * which uses it. + *10. Fixed problem in which rsl libraries could not be built if a library + * didn't already exist in the target directory. Brought configure.in up to + * date with autoconf version 2.53 standards. Removed acconfig.h. + *11. Removed outdated email addresses found in comments. + * + *--------------------------------------------------------------------- + * v1.29 Began 09/19/2000. Released 4/3/2001 (Severity: low) + * + * 1. Modified radar_to_hdf_1.c maskBuild() to build MZ mask differently: + * maskBuild was checking where CZ and DZ volumes were equal + * to build MZ volume (mask). Now, maskBuild just checks where + * CZ volume == BADVAL, for runtime speed, and because the comparison between + * CZ and DZ volumes was corrupted by the addition of qcParm[ZCAL] to + * each CZ range bin in level_1_qc.c qualityControl(). This change is + * compatible with Danny Rosenfeld's algorithm by which CZ range bins + * are set to BADVAL. + * 2. Included Stacy Brodzik's modifications for storing calibration constants + * in UF (radar_to_uf.c, uf_to_radar.c). + * 3. Corrected version string and units for sweep rate written to UF mandatory + * header in radar_to_uf.c, thanks to Joseph Holmes of Sigmet for catching + * the inaccuracies. Corrected rounding error in latitude/longitude for UF + * mandatory header in same program. Modified assignments of sweep rate + * and/or azimuth rate in uf_to_radar.c and hdf_to_radar.c + * + *--------------------------------------------------------------------- + * v1.28 Began 03/23/2000. Released: 7/24/2000 (Severity: low) + * + * 1. Added 3 functions to volume.c : + * RSL_add_dbz_offset_to_volume() , RSL_add_dbz_offset_to_sweep(), + * RSL_add_dbz_offset_to_ray() + * 2. Modified nsig.h , nsig_to_radar.c , volume.c to handle sigmet's + * RhoHV and PhiDP fields. + * 3. Modified volume.c to fix problem with subsequent calls to + * read_these_sweeps() + * 4. Modified uf_to_radar.c to compute unambiguous range for + * Radar structure. + * + *--------------------------------------------------------------------- + * + * v1.27 Began 01/11/2000. Released: 2/17/2000 (Severity: low) + * + * 1. Modified files radar_to_hdf_1.c and radar_to_hdf_2.c + * to accomodate random ray lengths, eg, Berrimah data. + * + *---------------------------------------------------------------------- + * v1.26 Began 12/11/1999. Released: 12/21/1999 (Severity: low) + * + * 1. Configuration change for rapic.l and rapic.y. + * 2. Changed dependency for rsl.h and wsr88d.h + * + *---------------------------------------------------------------------- + * v1.25 Began 11/30/1999. Released: 12/10/1999 (Severity: medium) + * + * 1. Merged branch v1.24.1. + * 2. Added configure/configure.in/Makefile.in. + * 3. Added Makefile.am (automake) and other related files. + * 4. Configuration is a snap: + * + * configure --prefix=/some/dir/to/install + * make install + * + *---------------------------------------------------------------------- + * v1.24.1 Began 8/1/1999. Released: 11/30/1999 (Severity: new features) + * + * 1. Introduced radar->h.project[24] -- project name. + * 2. Added dorade ingest -- RSL_dorade_to_radar. + * 3. Added examples/kwaj_subtract_one_day.c -- fix KWAJEX dates. + * 4. Removed rsl_popen/pclose routines from gzip.c. I found + * a way to eliminate the 'Broken pipe' message, the message + * reappeared in linux 2.2.* series, by flushing the + * stream when looking at the magic numbers in anyformat_to_radar.c. + * 5. HDF ROUTINES ARE REMOVED. I have moved them to gvs for level_1. + * See gvs/src/gvslib/. That's where they live now. The interface + * RSL_hdf_to_radar and RSL_radar_to_hdf remain as hooks. If + * you have libgvs, then you can specify -DHAVE_TSDIS_TOOLKIT in + * the Makefile. + * + *---------------------------------------------------------------------- + * v1.24 Began 6/25/1999. Released: 6/28/1999 (Severity: bug fix) + * + * 1. UF ingest improperly set the Fixed angle. + * 2. Removed max_reasonable_dbz (60) from gts.c. The app must decide + * what a max allowable dbz is. + * + *---------------------------------------------------------------------- + * v1.23 Began 3/31/1999. Released: 4/2/1999 (Severity: upgrade) + * + * 1. Added EDGE format ingest. This requires the library ETOR + * which is obtained from Enterprise Electronics. + * To build this component, set -DHAVE_EDGE in Makefile. + * + *---------------------------------------------------------------------- + * v1.22 Began 3/4/1999. Released: 3/4/1999 (Severity: bux fix) + * + * 1. Forgot to set the global 'rsl_kdp_wavelen' in nsig_to_radar.c. + * + *---------------------------------------------------------------------- + * v1.21 Began 02/16/1999. Released: 3/4/1999 (Severity: minor bux fix) + * + * 1. UF code didn't recognize VE, now it does. + * 2. RSL_SPEED_OF_LIGHT unifies c throughout the library. + * 3. Modification to KDP processing for Sigmet. New + * F and INVF functions. + * + *---------------------------------------------------------------------- + * v1.20 Began 11/12/98. Released: 01/25/1999 (Severity: bug fix/upgrade) + * + * 1. Fixed RADTEC ingest. Does RHI too, but, + * RSL doesn't have any good RHI image routines. + * + * 2. Added: RSL_set_color_table + * RSL_get_color_table + * + * 3. Added: '-b x' option to any_to_gif. This makes images black below + * x dbz. This is a simple noise filter. + *---------------------------------------------------------------------- + * v1.19 Began 9/15/98. Released: 9/23/98 (Severity: bug fix) + * + * 1. Modified file volume.c . New INV_F, _F routines for diff refl. + * + * 2. Created examples/images to hold a base-line set of images + * to compare when running 'run_tests'. Modified run_tests + * to compare images. + * + *---------------------------------------------------------------------- + * v1.18 Began 4/28/98. Released: 8/13/98 (Severity: upgrade) + * + * 1. Added routines: + * RSL_radtec_to_radar -- in radtec_to_radar.c + * RSL_fix_time -- in volume.c + * + * 2. Added files: + * radtec.c + * radtec.h + * radtec_to_radar.c + * + * 3. Modified image generation. Images are produced out to 'range' + * specified. Each image pixels is no longer 1km, but radius/range. + * + * 4. any_to_gif can now accept range and image size arguments. + * + * 5. RADTEC requires PKWARE routines explode and crc32. + * RADTEC is built into RSL, if you specify -DHAVE_PKWARE in + * the Makefile. When using RADTEC, you must link your application + * staticly; with -static. + * + * Contact PKWARE at 414-354-8699. + * + * 6. Modified radar_to_hdf_1.c. Removed ZDR data from 1C-51 HDF. + * + * 7. Moved HDF_FILE_VERSION definition from toolkit_1BC-51_appl.h + * into the application level_1.c + * + *---------------------------------------------------------------------- + * v1.17 Began 4/23/98. Released: 4/28/98 (Severity: upgrade) + * + * 1. Finally received info regarding KDP (KD_INDEX) for SIGMET. + * Assumming the units are similar for LASSEN. Boosted nsig_to_radar + * to recognize KDP. It is really KDP * wavelength. + * The units are deg*cm/km. You must divide out the wavelength, + * if that is desired. + * + * 2. BADVAL/NOECHO mod for nsig_to_radar.c. This should affect + * the values that may be stored in any possible UF output. + * + * WTD : lassen_to_radar.c - check the ZDR conversion, if any. Do + * we need this? + * WTD : RHI + * + *---------------------------------------------------------------------- + * v1.16 Began 3/6/98. Released: 4/21/98 (Severity: bug fix/upgrade) + * + * 1. Changed how any_to_gif output's filenames produced. Now, they + * are written to stdout. -v (verbose) and -V (all volume) options + * are added. Changed image_gen.c (RSL_volume_to_gif) to output + * filenames to stdout. + * + * 2. You really do need 'bison' (GNU yacc), 'flex' (GNU lex) and + * make (GNU make) to build this library. This has been true + * since v1.15 when I introduced the rapic format. These programs + * are superior to those on your stock Unix system, so take the + * time to install them. + * + * 3. README explains how to apply patches. + * + * 4. Eliminated the reduce/reduce conflict in rapic.y + * + * 5. Year 2000 compliant. + * + * 6. I forgot the format in sprintf. See rapic.y. + * + *---------------------------------------------------------------------- + * v1.15 Began 2/20/98. Released: 3/4/98 (Severity: bug fix/upgrade) + * + * 1. Michael Whimpey from BMRC, Australia changed code, for the + * different callibrations, between, Pre_mctex, mctex, Gunn_Pt + * periods. Please see code where there is m.whimpey. See + * lassen_to_radar.c + * + * 2. Added RAPIC format ingest. RSL_rapic_to_radar. + * I used GNU Bison (YACC) and GNU Flex (LEX) to code the RAPIC ingest. + * This format is used by the Berrimah radar. See rapic_to_radar.c, + * rapic_routines.c, rapic.y, and rapic.l. + * Not tested w/ older YACC and LEX found on older Unix systems. + * + * 3. Fixed a bug regarding the reading of stdin streams. Now + * you can read compressed or uncompressed files from stdin. + * Previously, you couldn't specify NULL as a filename and + * have it work reliably in all cases for any file format. + * This bug was found by accident and it is nothing you should + * be worried about in earlier RSL releases. The reason you need + * not worry about it is because 'RSL_anyformat_to_radar' cannot + * accept NULL as a filename. For you to notice this, you must + * have called the specific ingest routine for the format + * being read: RSL_lassen_to_radar, for example. + * + * 4. Bug in the UF ingest. The scale_factor needs to be float. + * When it was 'int', round off errors (truncation) were + * happening. This affected the Velocity data, only. The reflectivity + * data seemed unaffected, because, the magnitude of the values + * was high enough to avoid truncation. + *---------------------------------------------------------------------- + * v1.14 Began 2/2/98. Released: 2/3/98 (Severity: upgrade) + * + * 1. Added calibration for Gunn Point radar. Assumes that + * the radar name will be 'Gunn_Pt'. + * + *---------------------------------------------------------------------- + * v1.13 Began 1/16/98. Released: 1/26/98 (Severity: minor bug fix) + * + * 01/16/98 + * + * 1. radar_to_hdf_1.c: Changed decision algorithm regarding + * whether or not to write a VOS into a 1C-51 HDF file. + * 1C-51 HDF VOS time_slot status is encoded within the + * metaData field 'TK_GEN_DATE_INPUT_FILES'. + * + *---------------------------------------------------------------------- + * v1.12 Began 1/12/98. Released: 1/12/98 (Severity: minor bug fix) + * + * 1. Changed HDF metadata item for empty granules. + * + *---------------------------------------------------------------------- + * v1.11 Began 12/17/97. Released: 12/17/97 (Severity: minor bug fix) + * + * 1. Increased the size of pipecmd in RSL_write_gif and TK_MAX_FILENAME to 256.* 2. Modified image_gen.c to increase the data range of Zdr values. + * 3. Bug fix in radar_to_hdf_1.c: No longer dumps core for "tiny" sweeps + having fewer than 5 rays. + * + *---------------------------------------------------------------------- + * v1.10 Began 8/27/97. Released: 10/21/97 (Severity: minor upgrade) + * + * 1. Modified ZDR image generation: rsl.h, image_gen.c, ZDR color tables. + * 2. Added South Africa data format ingest. Not possible to + * interface in RSL_anyformat_to_radar, at this time. The format + * is primitive and I need to convert RVPC to dBZ. + * 3. Modified HDF component to maintain integrity of anomalous_condition + * flags. (RFVAL, APFLAG, NOECHO, BADVAL) + * Files: toolkit_1BC-51_appl.h, hdf_to_radar.c, radar_to_hdf_2.c + * 4. Modified radar_to_hdf_1.c for TSDIS/DAAC metadata requirements. + * 5. Modified any_to_gif.c to output site and date/time for image filenames. + * 6. Added QC algorithm parameter. Modified files: + * toolkit_1BC-51_appl.h, radar_to_hdf_1.c, radar_to_hdf_2.c, + * hdf_to_radar.c + * + *---------------------------------------------------------------------- + * v1.9 Began 8/18/97. Released: 8/18/97 (Severity: bug fix) + * + * 1. Mofified radar_to_hdf_1.c : Metadata mods for TSDIS. + * + *---------------------------------------------------------------------- + * v1.8 Began 7/30/97. Released: 8/05/97 (Severity: upgrade) + * + * 1. Added RSL_read_these_sweeps. Specify specific sweep numbers for + * ingest. This drastically speeds up ingest, if you're only interested + * in the first or first couple of sweeps. For example, making + * base scan images. + * wsr88d -done + * UF -done + * sigmet -done + * lassen -done + * HDF -done + * toga -done + * mcgill -done. BUT, apparently, mcgill ingest is broken!!! + * When did this happen? + * + * 2. Added RSL_load_zdr_color_table(); + * Includes color tables for this field. See colors/ + * + * 3. More HDF mods; more warning messages. + * + * 4. The TRMM Office has fixed several bugs in the TSDIS toolkit. + * For proper HDF creation, that conform to TSDIS HDF specifications, + * you will need toolkit 4.5r1.1. + * + * Toolkit 4.5r1.1 is an unofficial release; the TRMM office will + * pass this out upon request. + * + *---------------------------------------------------------------------- + * v1.7 Began 7/23/97. Released: 7/25/97 (Severity: bug fix) + * + * 1. Handles corrupt SIGMET files more gracefully. + * + * 2. All lat/lon (degree,minute,second) triplets have the same sign. + * Except, if UF, then what ever the file tells me and if they're + * not all the same sign, then you'll have + * to correct the UF w/ an RSL application. In other words, UF + * stores the lat/lon as deg/min/sec and they have their own signs; + * Strict UF have deg/min/sec all w/ the same sign, anyway. + * + * 3. Minor changes to HDF component of RSL. + *---------------------------------------------------------------------- + * v1.6 Began 5/02/97. Released: 7/23/97 (Severity: bug fix) + * + * 1. wsr88d_to_radar.c -- Was too permissive. No longer defaults to KMLB. + * If unable to establish a valid site based on callID or first_file, + * returns NULL. + * + * 2. 18 Jul 97 Kolander + * Modified radar_to_uf.c & uf_to_radar.c : Fixed some incorrect and + * missing sweep and ray header values. Salvaged some numerical precision. + * + * 3. Fixed a time problem in nsig_to_radar.c. Daylight savings time. + * + * 4. Saves lat/lon on each ray for UF. + * + *-------------------- + * 16 Jun 97 Kolander + * + * Modifications to radar parameter calulations in: + * wsr88d_to_radar.c, wsr88d.h, wsr88d.c, nsig_to_radar.c, + * lassen_to_radar.c, rsl.h + * + * Modified HDF-related files: + * hdf_to_radar.c toolkit_1BC-51_appl.h + * and split file 'radar_to_hdf.c' into two files: + * radar_to_hdf_1.c and radar_to_hdf_2.c + * Can handle oddly sized and/or corrupt VOSs. + *---------------------------------------------------------------------- + * v1.5 Began 3/17/97. Released: 4/30/97 (Severity: minor upgrade) + * + * 1. Additional error checking in wsr88d.c to warn when number of gates + * expected is exceeded. + * 2. Changes by Mike Kolander affect the HDF component of RSL. This + * version of RSL works with the TSDIS toolkit 4.0. + * 3. Changes to carpi and cube functions, see below. + *------------------------- + * Date: 26 Mar 97 kolander + * + * Files: radar_to_hdf.c, hdf_to_radar.c + * Moved QC parameters out of the metadata string into VOS comments + * field. + * + * Files: rsl.h, anyformat_to_radar.c + * Moved enum File_type definition from anyformat_to_radar.c into + * rsl.h + *-------------------------- + * Date: 17 Mar 97 kolander + * + * File: rsl.h + * Changed carpi structure: + * Added f, invf fields. + * (Carpi_value **)data is now a doubly indexed array 'data[nrow][ncol]' + * Changed slice structure: + * Added f, invf fields. + * (Slice_value **)data is now a doubly indexed array 'data[nrow][ncol]' + * Added function prototypes for: + * RSL_free_carpi, RSL_free_cube, RSL_free_slice, RSL_new_cube, + * RSL_new_slice, RSL_carpi_to_cart, RSL_carpi_to_gif, + * RSL_carpi_to_pict, RSL_carpi_to_ppm, RSL_carpi_to_pgm + * + * File: cube.c + * Added functions: + * RSL_free_slice, RSL_new_slice, RSL_new_cube, RSL_free_cube + * Modified functions: + * RSL_volume_to_cube, RSL_get_slice_from_cube + * + * File: carpi.c + * Added functions: + * RSL_free_carpi + * Modified functions: + * RSL_new_carpi, RSL_find_rng_azm, RSL_cappi_to_carpi + * + * File: image_gen.c + * Added functions: + * (These are modified clones of the sweep image_gen functions.) + * RSL_carpi_to_cart, RSL_carpi_to_gif, RSL_carpi_to_pict,, + * RSL_carpi_to_ppm, RSL_carpi_to_pgm + * + *---------------------------------------------------------------------- + * v1.4 Began 12/24/96. Released: 3/7/97 (Severity: bug fix) + * + * 1. Some WSR88D files have a 'radial status' of 28. This is un- + * documented. I assume it means some catastrophic reset has occured. + * Therefore, the code that counts the number of rays is modified + * to rely on the 'ray_num' reported upon reading the file. + * Also, I assume that when the status tells me that I'm reading + * the 'start of a new elevation' (status == 0) that all subsequent + * records will overwrite previously stored rays. + * + * I've seen this status number(28) occur, rarely, in the + * WSR88D data. See wsr88d.c. + * + * 2. Removed kwaj component. - Mike. + * + * 3. Installs toolkit_1BC-51_appl.h in INCDIR. This file is needed + * only if you plan to use the HDF component. + * + * 4. Fixes a freeing bug in nsig.c. Added member nparams to the + * NSIG_Sweep structure to track this for the free routine. + * + * 5. Ray indexing bug fixed in wsr88d_to_radar.c which produced an + * invalid time when the first wsr88d ray was null. Basically, using + * 'i' instead of 'iray'. + *---------------------------------------------------------------------- + * v1.3 Began 08/26/96. Released: 12/17/96 (Severity: upgrade) + * + * 1. Lassen field 'Zdr' loaded into RSL 'ZD' field, not the RSL 'DR' + * field, as originally envisioned within HDF functions. Henceforth, + * 'ZD' represents (linear) reflectivity depolarization ratio: + * ZD = 10log(Z_horiz/Z_vert) in units dB + * as opposed to the circular depolarization ratio. + * + * What exactly are the RSL 'LR' and 'DR' fields?? + * + * + * For consistency of field nomenclature: + * + * Renamed 'CR' to 'CD'. (corrected ZDR for 1C-51) + * 'MR' to 'MD'. (1C-51 mask for ZDR) + * + * CD_F returns ZD_F + * CD_INVF returns ZD_INVF + * + * 2. Sort by time forgot to compare the hour field. Minor fix. + * + * 3. Fix z_to_r to return proper value. + * + * 4. Lassen ingest: fix the sign of deg/min/sec so they match. + * Trusting that the sign of the deg is correct. + * + * 5. Added RSL_select_fields. This reduces memory requirements + * upon ingest. You can select, "all" (default), "none" (just to + * get header info) or "dz", "vr", ... + * + * WHAT? STATUS? + * lassen done + * wsr88d done + * UF done + * nsig done + * nsig2 done + * kwaj not applicable as it only has DZ. + * hdf done + * mcgill not applicable as it only has DZ. + * toga not done. If you want to do this, feel free. + * + * 6. Uses 'gzip -1'. This cuts the time for making UF files in half. + * + * 7. Renamed 'makefile' to 'Makefile' + * + * 8. The HDF component has changed drastically and is not compatable + * with previous versions. It may change again, contingent upon + * the TSDIS toolkit 3.5.2.1 (as of 12/17/96). Expect minor changes + * to the HDF component in the future. + * + * 9. Pruning of sweeps and rays now sets moved object pointers to + * NULL. See prune.c + * + *10. Updated nsig_to_radar.c to check for ant_scan_mode. If mode is + * RHI, then return NULL because RSL can't handle RHIs. --Paul + * + *11. Split memory management routines for hdf processing. --Mike K. + *---------------------------------------------------------------------- + * v1.2 Began 08/26/96. Released: 9/6/96 (Severity: minor bug-fix upgrade) + * + * 1. Eliminated zero sized arrays in lassen.h. SGI 'cc' can't + * handle zero sized arrays. This brings back the -pedantic + * compile flag. + * + * 2. Implemented popen and pclose (called rsl_popen and rsl_pclose) + * to eliminate the annoying message 'Broken pipe.' on SGI and HP + * computers. + * + * 3. The HDF component is incompatable with earlier versions because + * of the use of additional fields. It now uses the MASK fields + * and calibration information. It should be considered that the + * HDF component is in a state of flux. + * + * 4. Minor bug in nsig.c wherein when rays are missing (0 sized) + * that not all rays present will be ingested. This is fixed. + * + * 5. Copyrighted the software. + * + * 6. 'anyformat_to_radar' can recognize HDF files. + * + *---------------------------------------------------------------------- + * v1.1 Began 08/21/96. Released: 08/22/96 (Severity: SERIOUS bug fix) + * If you have already upgraded to RSL v1.0.1, then this is a minor + * upgrade. + * + * 1. I should have left well enough alone. But, getting rid + * of rsl.h.template in favor of only having rsl.h has revealed + * a serious bug. + * + * THIS BUG IS IN V1.0 ONLY. + * + * The type for 'Range' could be built into + * the RSL differently than how your application is built. + * For instance, if RSL is built with USE_TWO_BYTE_PRECISION, then + * your application will think 'Range' is a one byte storage class, + * because the default RSL configuration is to use one byte storage. + * + * This bug slipped through all the tests that I perform and was + * discovered only when using the radar_to_hdf component of RSL. + * Thanks to Mike Kolander for finding this one. + * + * Configuration instructions are changed so that you must edit + * rsl.h to use one byte precision. + * + * 2. All MCTEX fields are recognized and loaded into Radar. + * h.f and h.invf are modeled after LASSEN conversion functions. + * 3. Added radar_to_hdf.o to makefile. + * 4. In examples/any_to_gif.c, outputs all fields. + * 5. Three convience arrays are defined in rsl.h. + * a. RSL_ftype[]; + * b. RSL_f_list[]; + * c. RSL_invf_list[]; + * Each array is MAX_RADAR_VOLUMES long and contain: strings + * representing the field type, a pointer + * to the F function, and a pointer to the INVF function. + * + * Usage is conditional by defining USE_RSL_VARS before including + * rsl.h. Use: + * #define USE_RSL_VARS + * #include "rsl.h" + * + * Normally, you shouldn't worry about this. + * + * 6. Removed -pedantic compile flag because LASSEN code has a 0 + * sized array -- no warnings. + *---------------------------------------------------------------------- + * v1.0 Began 04/19/96. Released: 8/18/96 (Severity: minor upgrade) + * + * 1. Ignore SIGPIPE when making images. + * 2. Can read UF files of MCTEX data. This UF file contains + * RH and PH fields. This is LASSEN data that has been converted + * to UF via a sun program. It is the LASSEN II format. + * 3. Fixed date/time == 0 when calling uf_to_radar multiple times. + * The second and subsequent calls produced 0 for the + * radar->h.year/month/day and radar->h.hour/min/second. + * 4. Always allocate MAX_RADAR_VOLUMES for new radars during ingest. + * This will allow one to test any volume index for presence. + * 5. Set the default functions to DZ_F. This sets CZ_F correctly. + * It is unclear if the other conversion fuctions are properly + * defined. + * 6. Pure UF file ingest bug fixes. + * 7. Added RSL_hdf_to_radar - Mike Kolander. + * 8. Added RSL_radar_to_hdf - Mike Kolander. + * 9. New field type: XZ for X-band Reflectivity. + * 10. Working version of nsig_to_radar. - Paul Kucera. + * This version works on both big endian and little endian (Linux), + * and, for both version 1 and version 2 formats. Version 2 + * files are generated on big-endian machines (so far, SGI Iris + * computers), whereas, Version 1 files were written on + * little-endian DEC computers. Two routines are provided: + * + * RSL_nsig_to_radar(char *infile); + * RSL_nsig2_to_radar(char *infile); + * + * Nsig ingest can handle nsig files/tapes that were + * written on a DEC (little endian) or an SGI (big endian). + * It is handled automatically by examination of the 'magic' bytes. + * You will note that the byte-ordering in the file is dependant + * on which machine wrote the tape or file. The New-SIGMET + * documentation does not specify which byte-ordering is to be used + * when the file is written. + * + * Re-wrote nsig.c and beefed up nsig.h. Now, there is an + * interface to read an entire nsig sweep. You can loop through + * the returned sweep and pick your values, and load RSL. + * This re-write was done to make reading version 2 files easier. + * Additionally, all NSIG code for version 1 and version 2 files + * is centrally located in: + * nsig.h + * nsig.c + * nsig_to_radar.c + * To have both versions supported in the same files, I use #ifdef + * and the C preprocessor. 'nsig.h' is saturated with #ifdef NSIG_VER2 + * constructs. Thus, only one source is maintained for both NSIG versions. + * + * 11. Added RSL_print_version(); + * 12. Added docs for users guide, hdf. + * 13. Added html 'grouping by functionality' page. + * 14. Restores stdin and stdout when creating pipes. + * The pipe readers need to loop until no data available, because + * 'read/fread' will not get all the data in one call. + * 15. Added moving platform headers to Ray structure: + * float pitch; Pitch angle. + * float roll; Roll angle. + * float heading; Heading. + * float pitch_rate; (angle/sec) + * float roll_rate; (angle/sec) + * float heading_rate; (angle/sec) + * float lat; Latitude (degrees) + * float lon; Longitude (degrees) + * int alt; Altitude (m) + * int rvc; Radial velocity correction (units of velocity) + * + * This information typically comes from NSIG. For other formats + * the values are all zero. + * 16. Read version 1.3 and 1.4 of LASSEN data. RSL_lassen_to_radar. + * This means that RSL can read MCTEX data. + * 17. Users manual. Walk a novice through a simple example and explain + * what header information is important. Teach how to take advantage + * of the library. + * 18. Eliminated the #ifeq in makefile. Thus, rsl.h.template is removed + * and rsl.h is resurrected. + *---------------------------------------------------------------------- + * v0.45 Began 03/26/96. Froze: 03/27/96 (Severity: minor) + * + * 1. Fixed broken pipe problem on HP and SGI. Cause unknown. + * All I did was to remove the pclose in any_format_to_radar.c + * It seems that if there is any data left in the pipe that a + * SIGPIPE is sent when trying to close the pipe. + * On SGI's this causes a core dump. This bug is difficult to + * reproduce. + * 2. Nsig ingest is severly broken. It always was. Work in + * progress. + * 3. It is important that TSDIS get this version to run on their SGI + * as it prevents a core dump. Normally, this shouldn't affect + * anyone. + *---------------------------------------------------------------------- + * v0.44 Began 03/19/96. Froze: 03/19/96. + * + * 1. In prune.c, pointers that are pruned are now set to NULL. + * This elimated core dumps associated with trying to free structues. + * 2. On gzip-ed UF output, stdout is flushed before the pipe is opened. + * 3. Added reverse.c -- Reverse the order of the sweep pointers in + * a volume. + *---------------------------------------------------------------------- + * v0.43 Began 03/01/96. Froze: 03/05/96. + * + * 1. farea.c -- nbins fix. + * 2. On UF output, checks for NOECHO. + * + *---------------------------------------------------------------------- + * v0.42 Began 11/27/95. Froze: 02/16/96. + * + * 1. Removed '#include '. + * 2. Added a couple of missing prototypes in rsl.h.template. + * 3. Added: + * Ray *RSL_prune_ray (Ray *ray); + * Sweep *RSL_prune_sweep (Sweep *s); + * Volume *RSL_prune_volume(Volume *v); + * Radar *RSL_prune_radar (Radar *r); + * + * These routine remove dataless substructures. Prompted by + * poor NCAR ingest routines for UF files; it is wise to prune + * a Radar prior to calling RSL_radar_to_uf. Therefore, if + * software cannot read the UF files created by RSL, then try these + * prune functions before outputting the UF file. In either case, + * RSL_radar_to_uf produces valid UF files. + * 4. Removed trigraph in mcgill.c. + * 5. Fixed lassen ingest problem on Linux. I think XDR has a bug + * where bit fields are not loaded properly. This is a kludge fix. + * 6. Removed column.c. Code not mature and takes way too much + * RAM. Included in the removal are the vertical structure routines. + * The code has been moved to the application (qcwin). + * 7. RSL_get_first_ray_of_sweep now returns when the ray number is 1 or + * 0. This drasitically speeds the routine. + * 8. Increased the UF buffer size from 4096 to 16384. + *---------------------------------------------------------------------- + * v0.41 Began 11/01/95. Froze: 11/20/95. + * + * 1. Minor doc changes. More up to date with implementation. + * 2. Implemented 'radar_type' in the radar_header structure. Values + * are strings and are: "wsr88d", "lassen", "uf", "nsig", "mcgill", + * "kwajalein", "toga". + * 3. Increased range of data (internal storage conversion functions) + * when using 2 byte storage. Some nsig data can have values below the + * default wsr88d function range. + * 4. 'farea.c' -- Volumes are used to compute the fractional area. + * This matches the latest specification of the function. + * 5. Automatically uncompress files. Transparently sets up + * a decompression pipe. If the input is not stdin, then 'anyformat_to...' + * can peek inside a compressed file and determine what ingest routine to + * use. Reading copmressed files from disk and internally uncompressing + * them turns out to be the fastest form of ingesting wsr88d (only format + * timed) data on my 486. However, I get mixed results on the HP 755. + * 'anyformat_to...' uses 'gunzip' to peek inside compressed files. + * 6. Can make gzip-ed UF files. The new routine is 'RSL_radar_to_uf_gzip'. + * Also, RSL_radar_to_uf_fp takes a file pointer. Thus, you can + * define your own output filter. + * 7. Added RSL_write_radar_fp, RSL_write_radar_gzip. + *---------------------------------------------------------------------- + * v0.40 Began 10/24/95. Froze: 10/24/95. + * + * 1. Type cast for Sweep_header and Ray_header was removed so that + * stock 'cc' on SGI could digest the code. File: column.c. Why? + * + * Version 0.39 was short lived. :-) + *---------------------------------------------------------------------- + * v0.39 Began 7/1/95. Froze: 10/24/95. + * + * 1. Mcgill library is not separate. Included in rsl in whole. + * 2. Interpolation routines added. + * 3. Added RSL_load_height_color_table -- and the colors/*height.clr + * 4. Added RSL_load_rainfall_color_table -- and the colors/*rainfall.clr + * 5. Removed RSL_print_{volume,sweep,ray} + * 6. Removed some unused routines. + * 7. Vertical_structure is its own type composed of Vertical_sweeps and + * Vertical_rays (columns). + * 8. Added doc/internal_routines.html. + * 9. UF is exchangable between big and little endian. Finally, this + * has been fixed. Now UF can be generated on little endian machines + * and read on big endian (the UF generated is in big endian format even + * on the little endian machine). And, visa versa. + *10. New version of RSL_get_vertical_structure in column.c. Doc's updated. + *11. Fixed bug in radar_to_uf. When the number of actual sweeps (and perhaps + * volumes) is less than the determined max of the entire radar structure, + * then the pointers may be erroneous. Paul caught this flounder. + *12. Added RSL_uf_to_radar_fp. The FILE *fp version of the UF ingest. + * Also, passing NULL to RSL_uf_to_radar means to read from stdin. + *13. Added NOECHO flag for f and invf. Currently, defined for UF, NSIG and + * Kwaj data. + *14. Included source for libraries: wsr88d, lassen, tg, nsig, mcgill, + * and kwajlein. Now linking needs only: -lrsl -lm + *15. Simplified the configuration procedure. All configuration + * is specified from 'makefile'. See README for new install instructions. + *16. Removed ray_status, sec_num, atm_att, min_dif, sys_cal from ray + * header. These are not used and specific for wsr88d. + *17. Summary of routine that handle NULL filenames as STDIN. + * RSL_wsr88d_to_radar + * RSL_uf_to_radar -- calls --> RSL_uf_to_radar_fp + * RSL_lassen_to_radar + * RSL_nsig_to_radar + * RSL_toga_to_radar + * RSL_mcgill_to_radar + *18. Removed RSL_get_sweep_index_from_volume. + *19. Removed RSL_X_ray_indexes. Actually, just renamed the routine + * to 'construct_sweep_hash_table'. The hash table retains the hi and + * low ray pointers for closest ray comparison. Angle diff's removed. + *20. Removed hash table implementation in the Sweep structure. It + * is now implemented internally in RSL. + *21. BADVAL valued depends on Range type. Picked to be out of range. + * + *---------------------------------------------------------------------- + * v0.38 Began 6/1/95. Froze 6/29/95. + * + * 1. Makes 2's compliment, instead of 1's compliment, in sweep_to_cart. + * 2. Modifications to eth functions. + * 3. Added routine RSL_get_column. See column.c. + * 4. Added Column data structure. + * 5. Static pointer for image generation. Free up image pointer and + * reallocate. Otherwise, we've got a memory leak when making many + * images. + * 6. Added Paul's and Dennis's modifications of the cappi routines. + * I modified the cappi structure so that Sweep is a substructure. + * This makes image generation and get_value_from_cappi easy to implement. + * 7. Added a test program in examples/cappi_image.c to test cappi + * generation. + * 8. Change doc/ for the cappi routines. Routines added/modified are: + * float RSL_get_value_from_cappi(Cappi *cappi, float rng, float azm); + * int RSL_fill_cappi(Volume *v, Cappi *cap, int method); + * void RSL_free_cappi(Cappi *c); + * Cappi *RSL_new_cappi(Sweep *sweep, float height); + * Cappi *RSL_cappi_at_h(Volume *v, float height, float max_range); + * Carpi *RSL_cappi_to_carpi(Cappi *cappi, float dx, float dy, + * 9. Carpi structure modified to be compatable with cappi routines. + * 10. Added RSL_get_gr_slantr_h. -> range.c + * 11. RSL_uf_to_radar only recognizes UF files. + * 12. RSL_uf_to_radar handles TRUE UF, 2 and 4 byte record length delimeters. + * 13. Minor bug fix in ray_indexes.c to handle RHI input. The number of + * hash table entries is now a function of the beam_width and not the + * number of rays. + * 14. Bug fix in rebin_velocity_sweep. New velocity color tables. + * 'examples/qlook.c' added. Yet another image generation program; + * redundant. + * 15. RSL_uf_to_radar allocated additional space for sweeps, when the + * initial allocation is not enough. + * 16. Added a programmers guide. See programmers_guide.html. + * 17. Get_closest routines removed. + * 18. Added RSL_kwaj_to_radar. -- Mike Kolander. + * 19. Added docs for RSL_kwaj_to_radar. + * + * Note: Since v0.37 we've been using h.f and h.invf for the storage + * functions and, thus, the library is not compatable with earlier + * versions. All subsequent version are, however, compatable. + * This means, code that used v0.36 and earlier will break (not + * even link) with v0.37 or later. + * + * You must now use: + * ray->h.f(ray->range[i]) instead of F(ray->range[i]) + * and + * ray->h.invf(x) instead of INVF(x). + * + *---------------------------------------------------------------------- + * v0.37 Began 5/24/95. Froze 5/29/95. + * + * 1. Removed RSL_float_to_char; too specific. + * 2. Implemented seperate conversion functions for each field type. + * This added h.f and h.invf to Volume, Sweep and Ray headers. + * The ingest routines optionally define there own conversion function. + * Most of the time, though, I use the default: wsr88d conversions. + * Tested: wsr88d, lassen, mcgill, UF, rsl. + * Coded but not tested: toga, nsig. + * 3. Added ETH routines: + * Sweep *RSL_get_eth_sweep(Volume *v,float et_point); + * float RSL_get_echo_top_height(Volume *v,float azim,float grange, float et_point); + * 4. If using #define USE_TWO_BYTE_PRECISION, uses 100 as a storage + * factor. Now, there is no loss of precision when converting between + * internal and float. Before there was just a minor round off when + * using any data that used anything other than 1/2 dbz precision. + * Using 100 is more than enough. + *---------------------------------------------------------------------- + * v0.36 Began 5/19/95. Froze 5/19/95. + * + * 1. Magic in anyformat_to_radar was slightly different than expected + * for lassen data. Tested on lassen data. + * 2. DEFAULT is to use 2 byte storage precision. See rsl.h. + * 3. Several changes to get_closest routines -- Flanigan. + * + *---------------------------------------------------------------------- + * v0.35 Began 5/18/95. Froze 5/18/95. + * + * 1. Checks iazim validity in ray_indexes.c. Bad angles use to cause + * core dumps. + * 2. wsr88d_to_radar can handle bogus filenames and callid's. + * + *---------------------------------------------------------------------- + * v0.34 Began 5/17/95. Froze 5/18/95. + * + * 1. Modified the bscan interface. + * + * 2. Fixed a minor nrays bookkeeping bug in radar_to_uf. + * + * 3. Updated Sweep searching routines. + * + * 4. Added get_closest and get_next_closest ray searching routines. + * Updated RSL_get_ray_from_sweep so that it uses the + * new_get_closest function. + * + *---------------------------------------------------------------------- + * v0.33 Began 5/12/95. Froze 5/16/95. + * + * 1. Configure for building using 2 byte precision instead of 1 byte. + * This should quell any accuracy problems associated with the + * functions F and INVF. + * + * 2. Added 'RSL_mcgill_to_radar'. Link with -lmcgill. + * + * 3. Bug fix in cube.c, cappi.c, and carpi.c. + *---------------------------------------------------------------------- + * + * v0.32 Began 5/5/95. Froze 5/12/95. + * + * 1. Compiles with -Wall -ansi -pedantic. + * 2. Minor bug fixes in get_win.c + * 3. Compiles on SGI, 486, SUN, HP using gcc or stock cc. + *---------------------------------------------------------------------- + * v0.31 Began 4/28/95. Froze 5/5/95. + * + * 1. Added ray_high and ray_low Azimuth_hash pointers + * to Azimuth_hash data structure and code in the + * the routine RSL_sweep_ray_indexes to set these + * pointers. ray_low points to the Azimuth_hash + * with the next lowest ray_angle, with ray_high + * points to the next highest. + * + * 2. Created internal routine dir_angle_diff. Returns + * negitive difference if the second angle in + * the parameter list is counter-clockwise to the + * first angle. Returns positive is second + * angle is clockwise tk first angle. + * + * 3. Added internal routine the_closest_hash. This + * routine returns the an Azimuth_hash + * data structure that contains the closest + * ray to the requested angle. + * + * 4. Added two routines: RSL_get_closest_ray_from_sweep and + * RSL_get_next_closest_ray_from_sweep. + * + * 5. Added routines: RSL_get_window_from_radar, + * RSL_get_window_from_volume, RSL_get_window_from_sweep, and + * RSL_get_window_from_ray. + * + * 6. Modified farea.c. + * 7. Isolated contruction of azimuth table linked list. + * 8. Fixed get_sweep NULL sweep reference (See patch v0_29_3 also). + * 9. Compiles on HP CC, SGI CC, GNU CC. I had to #ifdef the + * varargs declaration in anyformat_to_radar.c. Why? + * 10. Added examples/killer_sweep.c. This randomizes the azimuth + * values of each ray. The output checks the sortedness of the + * hi and low links in the hash table. + * 11. Added doc/...closest... doc/...next_closest... + * + *------------------------------------------------------------------------- + * v0.30 Began 4/20/95. Froze 4/27/95 + * + * 0. IMPORTANT: Renamed libradar.a to librsl.a. Also, radar.h to rsl.h. + * 1. Removed NOTFOUND_H reference in the get_ray function. + * 2. Simplified get_sweep. + * 3. Uses within 1/2 beam_width test in get_ray_from_sweep. + * 4. Checks -1 and +1 bin in azimuth hash table to really find the + * closest ray that is within 1/2 beam_width of the target azim. + * Surprisingly, it shortened the get_value_from_sweep routine. + * + * 5. Added anyformat_to_radar.c. Uses magic information to determine + * the file format. Handles: UF, RSL, WSR88D, LASSEN. Toga may + * be difficult. Unknown, yet, for NSIG. Alan will get me that + * information. + * 6. Added beam_width to the ray structure. + *------------------------------------------------------------------------- + * v0.29.1 Began 4/18/95. Froze 4/18/95. + * + * 1. Bug fix in endian.c. Needed to initialize the word.val to 0. + * 2. Bug fix in radar_to_uf.c. little_endian() call. + * 3. Added Azumuth_hash to structure list in doc/. + * 4. Other minor changes. + *------------------------------------------------------------------------- + * v0.29 Began 3/1/94. Froze ??/??/?? + * + * 0. Thanks to Dennis Flanigan for helping with this release. + * + * 1. Modified sort_rays.c. By Dennis Flanigan, Jr. + * a. Added h.sorted_flag to Volume and Sweep header structures. + * + * b. Added routines: + * int ray_sort_compare_by_time(Ray **r1,Ray **r2); + * int sweep_sort_compare(Sweep **s1, Sweep **s2) + * Sweep *RSL_sort_rays_by_time(Sweep *s); + * Volume *RSL_sort_sweeps_in_volume(Volume *v) + * Volume *RSL_sort_volume(Volume *v) + * Radar *RSL_sort_radar(Radar *r) + * + * c. Routines that sort data structures now set the + * number of structures in the parent data structure. + * + * d. Fixed: nsweeps was not being set correctly by + * RSL_sort_sweeps_in_volume. + * + * 2. Removed sort calls in the ingest routines: (whatever)_to_radar. + * + * 3. Removed the auxillary trig tables in image_gen.c. It's just a + * memory hog. + * + * 4. Changed the extension of the tar archives to .tgz. This + * allows netscape to ftp the file rather than displaying it :-) + * + * 5. Added variables in the sweep data structures to represent + * the half of the beam width angles. These variables are + * vert_half_bw and horz_half_bw. Also added code to all + * RSL ingest routines (something_to_radar) to set these values. + * The half angle values are used in the volume.c searching routines. + * + * 6. Added h.indexes to Sweep structure. This is a simple hash + * table for making azimuth lookup cake. So far, I've only + * got the malloc part placed in the routines that create the + * radar structure. Added the file 'ray_indexes.c'. This changes + * RSL_get_value_from_ray. + * + * Code affected: + * Modify code: + * RSL_copy... + * RSL_free... + * RSL_clear... + * RSL_sort..??? really??? + * RSL_get... + * RSL_{write,read}_radar + * RSL_get_ray??? + * + * Modify doc + * RSL_sweep_struct.html + * + * 7. Updated doc/. + * + * 8. Added CHECK_LIST. + * + * 9. Changed the name from radar-v0.?? to rsl-v0.??. + * + * + *------------------------------------------------------------------------- + * v0.28 Began 7/23/94. Froze 2/16/95 + * Changes: + * + * 1. Support for little endian machines (*86 PC's using Linux). + * Includes 'endian.c' in 'uf_to_radar.c' and 'radar_to_uf'. It is not + * needed in 'lassen.c' because that program uses xdr to transfer the + * data. Nor is it required in 'wsr88d_to_radar.c', 'nsig_to_radar.c' + * nor 'toga_to_radar.c' because the support for little endian is in + * the respective libraries: libwsr88d.a, libnsig.a, libtg.a. + * + * Requires: + * wsr88d_v1.12.taz + * lassen_v1.0.taz + * libnsig_v1.3.taz + * libtg_v1.1.taz + * + * In order to make this library compatable with versions on either + * big endian or little endian machines, it will be adopted that all + * output will be in big endian format. Little endian machines will + * have to do the extra work of swapping bytes upon input as well as + * swapping bytes on output. I could adopt to use the xdr library, + * however, it seems too complicated for the simple task of always + * guarenteeing that the output is in big endian format. After all, + * we only support one output format: UF. (Well, we will make our own + * radar format output in big endian format too, but we keep that + * knowledge hush hush). + * + * 2. Documentation in the seperate directory complete for all routines + * in the RSL. Documentation froze at v0.27 and is in HTML format. + * The documentation version number will be updated to match the version + * number of the most current release of RSL. Note: The live link is + * in /PUBLIC/httpd/htdocs/trmm_office/software/radar/quick_reference. + * It is a symbolic link to ~/proj/trmm/radar/doc/v0.xx. + * + * 3. Added RSL_ prefix to all documentation. This renamed the HTML files + * to begin with RSL_, also. + * + * 4. Prefixed all routines with RSL_. Status is that it builds. + * 5. Combined radar.h, cube.h and volume.h into radar.h. + * + *------------------------------------------------------------------------- + * v0.27 Began 7/23/94. Froze 9/13/94. + * Changes: + * + * 1. Beam width calculation in get_value_from_sweep is not 1/2 on either + * side. No provision for best fit. See WTD #2. + * 2. Added sort_rays.c. Sort rays in a sweeps and volumes. + * 3. Added Vset_earth_radius. Set global variable 'Re' (Default: 4/3R). + * 4. Added trig modification of get_slantr_and_h. + * 5. Added sort rays call to: toga_to_radar, wsr88d_to_radar, + * uf_to_radar, lassen_to_radar. + * 6. Added cube.c. By Mike Kolander. + * 7. Added carpi.c + * 8. Added toga_to_radar.c. By Mike Kolander. + * 9. Signed all source files. + * 10. Quieted some image print statements. See image_gen.c. + * 11. Changed wsr88d_to_radar so it takes 'first_file' or the 4 character + * call sign (eg. KMLB). + * 12. Fixed makefile so it removes libradar.a before building. This prevents + * duplicate object files, only the long filenamed ones, from + * appearing in the archive file. + * 13. Added gts.c. By Dave Wolff. + * 14. Fixed minor round off error in 'uf_to_radar' which caused a 0 dBZ spike. + * 15. Added histogram.c. By Dave Wolff. + * 16. Added nsig_to_radar.c. By Alan McConnell. + * + * WTD: + * + * + * 2. Vget_value_from_sweep. When the beam width is increased we + * want to return the value that is the best fit for a ray and not + * just the first fit. Currently when the beam width is really + * large then we will pick the wrong beam for the desired point. + * + * 3. Add the following to the ray header: + * - u,v for ray. + * - offset for azim, range, elev (for moving radar) + * - lat/lon (for moving radar) + * + * 4. Bilinear interpolation. + * 6. Modify get_ray_above to return a good ray so that QC doesn't zap points + * near the radar. + * 7. Optimize/Improve the get_value routine. + * 8. Remove V prefix to routine names? + * 10. Fix why there are bands of missing data when making images. + * 11. Specify resolution when making images. + * 14. Update: doc's (in HTML), README, etc. + * 16. NEED *TESTING* suite of programs. + * + * Proposed changes for v0.28 + * 1. Add support for little endian machines (386, 486, etc.) + * 2. F(x, DZ) or ray->f.dz(x). I.e., object function conversion functions. + * + * + *------------------------------------------------------------------------- + * v0.26 Began 7/23/94. + * Changes: + * 1. Adding cappi_to_carpi. + * 2. Enhanced the Cappi structure; not the same as a sweep anymore. + * + *------------------------------------------------------------------------- + * v0.26 Began 7/13/94. Froze 7/20/93. + * Changes: + * 1. Units for wavelength, in radar_to_uf, changed from meters to cm; + * as they should be. + * 2. Library runs quietly. No noisy print statements. Call + * radar_verbose_on() and radar_verbose_off() to control printing. + *------------------------------------------------------------------------- + * v0.25 Began 7/1/94. Froze 7/1/94 + * Changes: + * 1. Modifications to makefile to add portibility to building on + * other systems w/o gcc. Change to CFLAGS. + * 2. Passes lint. + * 3. Moved documents radar.ez and volume.ez to ../doc (../doc_RCS). + * This means that the version of the documentation will not be kept + * up to the version of the RSL library. Only changes to the doc. will + * force a new version of the documentation. I'll want to see if this + * is a good idea. + *------------------------------------------------------------------------- + * v0.24 Began 6/29/94. Froze 6/29/94 + * Changes: + * 1. radar_to_uf, uf_to_radar. Fixed inconsistant use of BADVAL vs. + * UF_NO_DATA. The latter is check and used. + * 2. Added function: + * float get_nyquist_from_radar(Radar *radar); + * Useful, for loading non-velocity fields with PRF, PRT and NYQUIST. + * 3. Made the makefile more general and added comments. + * + * WTD: + * 1. Modify wsr88d_to_radar to fill PRF, PRT and NYQUIST values in + * non-velocity rays. + *------------------------------------------------------------------------- + * v0.23 Began 6/27/94. Froze 6/27/94 + * Changes: + * 1. First distribution release. + * 2. Added README w/ installation instructions. + * 3. Made example_main and colors directories. + * 4. Shortened lassen.h to be close to minimial. + * 5. Modified makefile to only make libradar.a. Example_main/ has it's + * own makefile. + *------------------------------------------------------------------------- + * v0.22 Began 6/24/94. Froze 6/24/94 + * Changes: + * 1. radar_to_uf/uf_to_radar PRF/PRT calculation corrected. + * + *------------------------------------------------------------------------- + * v0.21 Began 6/24/94. Froze 6/24/94 + * Changes: + * 1. radar_to_uf: prf now in microseconds. + * 2. uf_to_radar: prf now converted from microseconds to seconds. + * + *------------------------------------------------------------------------- + * v0.20 + * Changes: + * Need to determine the changes. + *------------------------------------------------------------------------- + * v0.19 Began 6/17/94. Froze: 6/17/94. + * Changes: + * 1. Fixed NULL access in write_radar subroutine. + * + *------------------------------------------------------------------------- + * v0.19 Began 6/15/94. Froze: 6/15/94. + * Changes: + * 1. Check for NULL in Vget_ray_from_sweep fixes a segmentation fault on + * Sun. + *------------------------------------------------------------------------- + * v0.18 Began 6/11/94. Froze: 6/12/94 2pm. + * Changes: + * 1. Minor changes in volume.c. Vget_value_from_sweep now uses the + * beam_width for matching rays. See Vget_sweep too. + * 2. cappi.c sets the beam_width. + * 3. Added radar types. There is no sure fire way to set + * radar->h.radar_type to one of these values automatically, ie. from + * information in the input file. It may have to be done by the + * application; a runtime parameter, option. + * Types are: + * TOGACOARE_TOGA_SIGMET + * TOGACOARE_MIT_SIGMET + * TRMM_DARWIN_LASSEN + * DARWIN_TOGA_SIGMET + * TRMM_MELBOURNE_WSR88D + * TRMM_KWAJALEIN_SIGMET + * TRMM_HOUSTON_WSR88D + * 4. Added function: + * Sweep *Vget_first_sweep_of_volume(Volume *v); + * 5. Placed the wsr88d code in wsr88d_to_radar.c (removed from radar.c). + * + * WORK TO DO: + * 1. Rework Vget_value_from_sweep to do a better search for the value. + * + *------------------------------------------------------------------------- + * v0.17 Began 6/10/94. Froze 6/10/94 3:30pm. + * Changes: + * 1. Corrected the pulse width calculation in uf_to_radar and in + * radar_to_uf. + *------------------------------------------------------------------------- + * v0.16 Began 6/10/94. Froze 6/10/94 12:30pm. + * Changes: + * 1. Minor changes to radar.c because v1.3 of the wsr88d library is + * now using WSR88D_DZ, WSR88D_VR, WSR88D_SW as the field type mask. + * REFLECTIVITY, VELOCITY and SPECTRUM_WIDTH are not used. + * + *------------------------------------------------------------------------- + * v0.15 Began 6/7/94. Froze 6/7/94 1pm. + * Changes: + * 1. Discovered that the range to bin1 calculation in radar_to_uf.c and + * uf_to_radar.c was incorrect. See fh[2] and fh[3]. + * + *------------------------------------------------------------------------- + * v0.14 Began 6/2/94. Froze 6/2/94 1pm. + * Changes: + * 1. Modified the date for the Radar structure for UF reading to reflect + * the time of the first ray. It was the generation time of the radar + * structure, however, Dave Wolff insists that it reflect the time of + * the first ray. Modification to 'uf_to_radar.c' + * + *------------------------------------------------------------------------- + * v0.13 Began 6/2/94. Froze 6/2/94 11am. + * Changes: + * 1. Modified radar_to_uf.c to undo the faking of the headers. This is + * the correct way. + * + *------------------------------------------------------------------------- + * v0.12 Began 5/31/94. Froze 5/31/94 7pm. + * Changes: + * 1. Check for malloc errors in Vnew* routines. + * 2. Fixed a nasty bug in radar_to_uf. I was letting 'j' get to high + * for a particular ray in a sweep. 'j' is looping on the maximum + * rays possible. I noticed this bug only after Vcopy_volume to + * replace a radar->v[i]. + *------------------------------------------------------------------------- + * v0.11 Began 5/27/94. Froze 5/27/94 12:50pm. + * Changes: + * 1. Modified radar_to_uf.c to fake header information when fields do + * exist, eventually, but not in the current sweep. This is to allow + * brain dead UF ingestors (Zeb, RDSS, etc.) to read the UF file; they + * assume that whatever fields exist in the first UF sweep is constant + * throughout the file. + * + * 2. Added functions to volume.c + * Ray *Vget_first_ray_of_sweep(Sweep *s); + * Ray *Vget_first_ray_of_volume(Volume *v); + * + *------------------------------------------------------------------------- + * v0.10 Began 5/26/94. Froze 5/27/94 9am. + * Changes: + * 1. Modified the names of the INDEX and MASK variables. + * + * ZT Total Reflectivity (dBZ) ZT_INDEX + * May be uncommon, but important + * + * DZ Reflectivity (dBZ), may contain some DZ_INDEX + * signal-processor level QC and/or + * filters. This field would contain + * Darwin's CZ, or WSR88D's standard + * reflectivity. In other words, unless + * the field is described otherwise, it + * should always go here. In essence, this + * is the "cleanest" reflectivity field + * for a radar. + * + * DR Differential reflectivity DR_INDEX + * DR and LR are for dual-polarization + * radars only. Unitless or in dB. + * + * LR Another form of differential ref LR_INDEX + * called LDR, not sure of units + * + * CZ QC Reflectivity (dBZ), contains + * post-processed QC'd data CZ_INDEX + * + * VR Radial Velocity (m/s) VR_INDEX + * + * SW Spectral Width (m2/s2) SW_INDEX + * + * 2. Fixed some MAX_RADAR_VOLUMES references in the wsr88d_to_radar code. + * + *------------------------------------------------------------------------- + * v0.9 Began 5/25/94. Froze: 5/26/94, 10am. + * Changes: + * 1. Added lassen_to_radar.c + * 2. Added lassen.h + * + *------------------------------------------------------------------------- + * v0.8 Began 5/23/94. Froze: 5/24/94, 10am. + * Changes: + * 1. F and INVF handle APFLAG. + * 2. Image generation creates unsigned char images. + * 3. 255-val for negative dBz (val < 0). + * + *------------------------------------------------------------------------- + * v0.7 Began 4/30/94. Froze: 5/20/94. + * + * Changes: + * + * 1. Uses char storage for data values, to reduce RAM allocation. + * + * 2. F(x) ((x-2)/2. - 64.) + * 0 is for BADVAL. Bad value. + * 1 is for RFVAL. Range folded. + * + * 3. Added functions: + * Vfloat_to_char(float *x, unsigned char *c, int n); + * float F(unsigned char c); + * unsigned char INVF(float x); -- Inverse of F. + * Radar *uf_to_radar(char *infile); + * void radar_to_uf(Radar *radar, char *outfile); + * + * 4. Minor bug fix in wsr88d_to_radar routine. It was setting the + * number of volumes to six even though we were only asking for 3. + * + * 5. Changed the value of BADVAL to 0500 (Octal 500). This is + * a value higher than 255 (the maximum byte value) but small enough + * to that when a scale factor (typically 100) is applied, the result + * does not exceed the I*2 (short) magnitude. I needed this for the + * UF programs. I could have tested for BADVAL, RFVAL, etc., and not + * applied a scale factor when loading the UF buffer, however, changing + * BADVAL and scaling everything was more general. + * + * 6. Made some slight modifications to the Radar header and Volume header. + * + *------------------------------------------------------------------------- + * v0.6 Began 4/16/94. Froze: 4/30/94. + * + * Changes: + * + * 1. Azimuth angles range from -180,180 to 0,360. + * 2. New color index binning function for velocity. -nyquist,nyquist + * using 15 bin values. See Vrebin_velocity_sweep. + * 3. Added the following routines: + * + * Memory management. + * Ray *Vcopy_ray(Ray *r); + * Sweep *Vcopy_sweep(Sweep *s); + * Volume *Vcopy_volume(Volume *v); + * Radar *clear_radar(Radar *r); + * void Vget_groundr_and_h(float slant_r, float elev, float *gr, float *h); + * void Vget_slantr_and_elev(float gr, float h, float *slant_r, float *elev); + * void Vget_slantr_and_h(float gr, float elev, float *slant_r, float *h); + * + * Image generation preparation. + * void Vrebin_velocity_ray (Ray *r); /* Modifies r */ + * void Vrebin_velocity_sweep (Sweep *s); /* Modifies s */ + * void Vrebin_velocity_volume(Volume *v); /* Modifies v */ + * + * Color table functions. + * void load_red_table(char *infile); + * void load_green_table(char *infile); + * void load_blue_table(char *infile); + * + * 4. Added 4/3Re calculation to Vget_slantr_and_elev and Vget_groundr... + * 5. Checked for null in the Vclear routines. + * + *------------------------------------------------------------------------- + * v0.5 Began 4/7/94 + * + * Changes: + * + * 1. Color table functions taken out of the image routines. + * You must call load_refl_table(), load_vel_table(), load_sw_table() + * to load the appropriate color table before making color images. + * There are seperate color tables for R, V, S. See volume.h. + * + * 2. Range is now used in Vsweep_to_cart. + * 3. Gate size (pixel resolution in km) is now used. + * 4. Added range to cappi_at_h function. It is the effective range. + * 5. Added the following routines: + * + * Read radar from disk. + * Ray *read_ray (FILE *fp); + * Sweep *read_sweep (FILE *fp); + * Volume *read_volume(FILE *fp); + * Radar *read_radar (char *infile); + * + * Write radar to disk + * int write_ray (Ray *r, FILE *fp); + * int write_sweep (Sweep *s, FILE *fp); + * int write_volume(Volume *v, FILE *fp); + * int write_radar (Radar *r, char *outfile); + * + * Area calculations + * float Varea_of_ray(Ray *r, float lo, float hi, float range); + * float Vfractional_area_of_sweep(Sweep *s, float lo, float hi, float range); + * + * Pixel fractions + * Vfraction_of_ray(Ray *r, float lo, float hi, float range); + * Vfraction_of_sweep(Sweep *s, float lo, float hi, float range); + * Vfraction_of_volume(Volume *v, float lo, float hi, float range); + * + * + * 6. radar.c calls wsr88d_get_site to get additional wsr88d information + * not included in the file. Routines compliments of Dan Austin. + * 7. Added RFVAL. Range Folded value. Any base data value of 0 is + * data below SNR thresholds set for that specific base data. Any + * data value of 1 is data considered range ambiguous (folded). + * A color table entry needs to be picked to represent this value. + * + * To do: + * o I have to do something about MAX_RADAR_VOLUMES. We really should + * rely on radar->h.nvolumes; + * + * o Add 4/3Rearth calculation to get value routines. + * o Incorporate nsig_to_radar. Dennis Flanigan is writing that interface. + * o Add fraction of area function. + * o Add the following functions: ??? really ??? + * Sweep *Vget_closest_sweep(Volume *v, float elev); + * Ray *Vget_closest_ray(Sweep *s, float azim); + * float Vget_closest_value_in_beam(Ray *ray, float range); + * float Vget_closest_value(Ray *ray, float range); + * (I'm not sure how this will be different than Vget_value) + * + * o Sort the rays so locating azimuth is trivial; instead of a search + * algorithm as it is now. Hey, would a binary search be good enough or + * do we need some hashing function? Is the lookup fast enough already? + * o Add CAPPI at h. (Option for bilinear interpolation about h). + *------------------------------------------------------------------------- + * v0.4 Began 3/23/94 Froze: 4/7/94 + * + * Changes: + * + * 1. Made Sweep (sweep) and Ray (ray) members an array of pointers. + * This changes the syntax of the access to be + * v->sweep[is]->ray[ir]->range[ibin] instead of + * v.sweep[is].ray[ir].range[ibin]. The benifit of this is to + * be able to dynamically specify the number of sweeps or rays, + * even volumes for the Radar structure, and not allocate a maximum. + * This makes Vnew_sweep and Vnew_ray useful. + * + * 2. Added the following functions: + * Volume *Vget_volume(Radar *r, int itype); + * itype = REFLECTIVITY, VELOCITY, or SPECTRUM_WIDTH, etc. + * + * Sweep *Vget_sweep(Volume *v, float theta); + * Ray *Vget_ray (Volume *v, float theta, float azimuth); + * float Vget_value(Volume *v, float theta, float azimuth, float range); + * Ray *Vget_ray_from_sweep(Sweep *s, float azimuth, float range); + * float Vget_value_from_sweep(Sweep *s, float azimuth, float range); + * float Vget_value_from_ray(Ray *r, float range); + * float Vget_value_at_h(Volume *v, float azim, float grnd_r, float h); + * + * Ray *QC_ray (Ray *ray, int radar_type); + * Sweep *QC_sweep (Sweep *sweep, int radar_type); + * Volume *QC_volume(Volume *volume, int radar_type); + * + * Radar *QC_radar (Radar *radar); + * + * void write_gif(char *outfile, char *image, int xdim, int ydim, char c_table[256][3]); + * void write_pict(char *outfile, char *image, int xdim, int ydim, char c_table[256][3]); + * char *Vsweep_to_cart(Sweep *s, int xdim, int ydim, float range); + * void Vsweep_to_gif(Sweep *s, char *outfile, int xdim, int ydim, float range); + * void Vsweep_to_pict(Sweep *s, char *outfile, int xdim, int ydim, float range); + * void Vvolume_to_gif(Volume *v, char *basename, int xdim, int ydim, float range); + * char *Vsweep_to_cart( + * 3. When a sweep does not have any rays with any bins, then NULL is + * assigned to that Sweep pointer. This occurs for reflectivity for + * the 2-nd sweep index (as defined by the data) where the is no + * reflectivity data, only doppler and spectrum width. Velocity and + * spectrum width data do not exist for sweep number 1 (index 0). + * + * 4. Speed ups in Vto_cart_sweep. Math is precomputed and saved in + * arrays for faster lookup. Still the ppmtogif is a snail and it + * overwhelms the runtime. I only saw a 35 second improvment with + * these new arrays when outputting 20 gif images. I think the -O + * compile flag is doing a good job. + * + * 5. Added CAPPI at h. Routine in cappi.c. Cappi type is syntatically + * identical to the Sweep type. + * + * Cappi *cappi_at_h(Volume *v, float h); + * + * 6. Make builds libradar.a which contains radar.c, volume.c, cappi.c and + * image_gen.c. Builds on SGI, SUN and HP. + * + * 7. Add QC routines. See 2. above for the list. Currently they are + * place holding functions with only QC_ray needing to be coded. + * Paul Kucera will take care of that. + * + * 8. Improvments to radar.ez and volume.ez. + * + * To do: + * o Add the following functions: + * Sweep *Vget_closest_sweep(Volume *v, float elev); + * Ray *Vget_closest_ray(Sweep *s, float azim); + * float Vget_closest_value_in_beam(Ray *ray, float range); + * float Vget_closest_value(Ray *ray, float range); + * (I'm not sure how this will be different than Vget_value) + * + * o Add range resolution to the image generation subroutines. + * o Add range resolution to all the 'get_value' routines. + * o Sort the rays so locating azimuth is trivial; instead of a search + * algorithm as it is now. Hey, would a binary search be good enough or + * do we need some hashing function? It the lookup fast enough already? + * o Add CAPPI at h. (Option for bilinear interpolation about h). + * + *------------------------------------------------------------------------- + * v0.3 Began 3/22/94 Froze 3/23/94. + * + * Changes: + * 1. Implimented the Radar structure. The heart of it is an array of + * Volume pointers. + * 2. Using 'data_mask' which is a bitwise ( | operator in C ) of + * REFL_MASK, VEL_MASK, or SW_MASK, you can get any field type volume: + * reflectivity, doppler velocity, or spectrum width respectively. + * 3. Load volume, sweep and ray header information. + * 4. Added Radar header information; need a good definition of say date and + * time. + * + * Work to do: + * - Improve carteasean image generation. + * Input: radar range, pix_width, pix_height. No distortion. + * - Need to specify the output GIF filename as options. + * - Incorporate Vto_fraction (?? name ??) Dave's new function. + *------------------------------------------------------------------------- + * v0.2 Began 3/21/94 Froze 3/22/94. + * + * I am freezing this here because both BSCAN and CARTESEAN image generation + * works. You have to hand edit the source to restrict the number of + * Sweeps that are converted to images, currently only sweep 0. The inclusion + * of sweep/ray header information and the collection of doppler and spectrum + * width data requires substantial effort and will be in the next version. + * This version freeze is a check point. + * + * Changes: + * 1. Name rsphere change to volume. + * 2. File rsphere.c changed to volume.c. (Moved the RCS file rsphere.c,v + * to the graveyard directory in RCS/ + * 3. Added color gif support. Reads red.clr, green.clr, blue.clr files. + * This renamed the Vto_cart_pgm function to Vto_cart_gif. It is likely + * that ppm support is not needed. We'll see. + * 4. Fixes minor glitches in output images where the tan is undefined. + * 5. Added BSCAN production as GIF files. + * 6. Output sweep.xx file names; sweep.00.gif, etc. and bscan.00.gif too. + * + * Work to do: + * - Add routines to get volumes for doppler and spectrum width. (Radar lib?) + * - Improve carteasean image generation. + * Input: radar range, pix_width, pix_height. No distortion. + * - Add sweep header information. + * - Need to specify the output GIF filename as options. + * - Incorporate Vto_fraction (?? name ??) Dave's new function. + * + *------------------------------------------------------------------------- + *v0.1 3/21/94 by John Merritt. + * 1. First development version of the radar and rsphere library. + * Includes test driver. radar.ez and rsphere.ez document the + * functionality of the programs. This version exists to check point + * the development. + *------------------------------------------------------------------------- + */ diff --git a/CHECK_LIST b/CHECK_LIST new file mode 100644 index 0000000..1527b79 --- /dev/null +++ b/CHECK_LIST @@ -0,0 +1,84 @@ +Checklist for Making New Software Release +----------------------------------------- + +Check each item, when completed, when updating the version of RSL. + +1. Change version number reference in index.html, in the directory doc/. + +2. Change README to indicate the new version number and freeze date. + +3. Change CHANGES, change FREEZE date. + +4. In doc/, change version number reference in RSL_radar_intro.html. + +5. In doc/, run 'netscape index.html'. + +6. Check that the structures in RSL_structures.html, RSL_ray_struct.html, + etc., match those in rsl.h. + +7. Change the version number in Makefile.am + +8. Change the version number in configure.in + +============================================================================ +The following are the steps for freezing a new version. + +1. Before freezing: + + a. cd rsl + b. autoreconf + c. configure + d. setenv LD_LIBRARY_PATH `pwd`:$LD_LIBRARY_PATH + e. make + f. cd examples + g. make + h. run_tests + +2. cd rsl + make install + cvs commit (Tagging is done in step 4.) + +3. make dist + Unpack it and try to build it -- 'make distcheck' will not work. + +************************************************************* +*** run_tests contains, at least, the following commands. *** +************************************************************* + any_to_gif /DATA2/merritt/nex.file.{2,1} + xv dz_sweep.gif -- Look familiar? + killer_sweep /DATA2/merritt/nex.file.{2,1} | less -- Check 'OUT OF ORDER'. + wsr88d_to_gif /DATA2/merritt/nex.file.{2,1} + xv dz_sweep.gif -- Look familiar? + wsr_hist_uf_test /DATA2/merritt/nex.file.2 + diff *.dat (There should be no differences.) + bscan /DATA2/merritt/pafb_swap + bscan /DATA2/merritt/pafb_unswap + +4. make install + cvs rtag v1_? rsl (Tag only when step 3 works.) + +5. scp rsl-v1.?.tgz trmm:/public/ftp/pub/software + (Reset rsl-LATEST to point to this new version). + +6. mv rsl-v1.?.tgz distributions/ + +7. Copy the doc/ directory to the http on trmm: + + scp -r doc/* trmm:/public/httpd/htdocs/trmm_office/software/rsl + scp -r README trmm:/public/httpd/htdocs/trmm_office/software/rsl + scp -r CHANGES trmm:/public/httpd/htdocs/trmm_office/software/rsl + +8. Install on trmm + Install on raindrop1 + Install on nyquist + Install on echo + +9. Make a patch. + + cvs rdiff -r v1_10 rsl > rsl.v1.10_to_v1.11.patch + gzip rsl.v1.10_to_v1.11.patch + scp rsl.v1.10_to_v1.11.patch.gz trmm:/public/ftp/pub/software + +10. Change the version number in the mainline distribution (rsl/) to + the next value. That's in Makefile.am and configure.in. + diff --git a/Copyright b/Copyright new file mode 100644 index 0000000..baa40d6 --- /dev/null +++ b/Copyright @@ -0,0 +1,22 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996-1999 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ diff --git a/GPL b/GPL new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/GPL @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/LGPL b/LGPL new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/LGPL @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..361f169 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,73 @@ +## Process w/ automake. Or, autoreconf; make ## +AUTOMAKE_OPTIONS = foreign +SUBDIRS = . colors doc examples +INCLUDES = -I. -I$(srcdir) -I$(prefix)/include -I$(prefix)/toolkit/include + +includedir = $(prefix)/include +colordir = $(libdir)/colors + +lib_LTLIBRARIES = librsl.la + +librsl_la_LDFLAGS = -version-info 1:40 +librsl_la_SOURCES = \ +$(rapic_c) $(radtec_c)\ +dorade.c dorade_print.c dorade_to_radar.c\ +lassen.c lassen_to_radar.c \ +edge_to_radar.c \ + radar.c volume.c image_gen.c cappi.c fraction.c read_write.c farea.c \ + range.c radar_to_uf.c uf_to_radar.c wsr88d_to_radar.c \ + carpi.c cube.c sort_rays.c toga_to_radar.c gts.c histogram.c \ + ray_indexes.c anyformat_to_radar.c get_win.c endian.c mcgill_to_radar.c \ + mcgill.c interp.c toga.c wsr88d.c wsr88d_get_site.c wsr88d_m31.c \ + gzip.c prune.c reverse.c fix_headers.c \ + nsig_to_radar.c nsig.c nsig2_to_radar.c \ + africa_to_radar.c africa.c \ + radar_to_hdf_2.c hdf_to_radar.c toolkit_memory_mgt.c \ + radar_to_hdf_1.c rainbow.c rainbow_to_radar.c $(headers) + +librsl_la_DEPENDENCIES = $(build_headers) + +build_headers = rsl.h wsr88d.h toolkit_1BC-51_appl.h + +headers = africa.h dorade.h lassen.h \ + mcgill.h nsig.h radtec.h rainbow.h \ + rapic_routines.h toga.h \ + $(build_headers) + +rapic_c = rapic_to_radar.c rapic.y rapic-lex.l rapic_routines.c +radtec_c = radtec_to_radar.c radtec.c + + +rsl.h: Makefile + @for h in $(build_headers); do \ + echo -n "Checking substitutions in header file $$h ... "; \ + cp $$h $$h.in; \ + sed -e 's/RSL_VERSION_STR.*/RSL_VERSION_STR \"$(VERSION)\"/' \ + -e 's|#define COLORDIR.*|#define COLORDIR \"$(colordir)\"|' \ + -e 's|#define WSR88D_SITE_INFO_FILE.*|#define WSR88D_SITE_INFO_FILE \"$(libdir)/wsr88d_locations.dat\"|' \ + < $$h.in > $$h.new; \ + if cmp -s $$h $$h.new; then \ + rm $$h.new; \ + echo "$$h remains untouched."; \ + else \ + mv $$h.new $$h; \ + echo "substitutions made in $$h."; \ + fi; \ + rm -f $$h.in; \ + done + +PREFIX = rapic +LFLAGS = -P$(PREFIX) +YFLAGS = -d -p $(PREFIX) +LEX_OUTPUT_ROOT = lex.$(PREFIX) + + +install-exec-hook: + $(INSTALL) -d $(includedir) + $(INSTALL) -m 644 rsl.h $(includedir) + $(INSTALL) -m 644 toolkit_1BC-51_appl.h $(includedir) + $(INSTALL) -m 644 wsr88d_locations.dat $(libdir) + +EXTRA_DIST = CHANGES CHECK_LIST Copyright GPL LGPL wsr88d_locations.dat rapic.h + +DISTCLEANFILES = rapic.c rapic-lex.c diff --git a/README b/README new file mode 100644 index 0000000..33a8b80 --- /dev/null +++ b/README @@ -0,0 +1,237 @@ +v1.40 (Released 10/10/2008) + +This is the README file for the Radar Software Library (RSL). + +The author of RSL is John H. Merritt. + +What is RSL? + This software manipulates NexRad, Lassen, UF, sigmet, kwajalein, +toga, RAPIC, RADTEC, mcgill and EDGE radar formats. + +The radar data is used by the NASA TRMM Office to produce rain +and climatological products. This software +can ingest an entire input data file, representing it in RAM as it +is on disk, manipulate the data and produce simple images. The intent +of this library is to provide you with the tools to manipulate the +data. With those tools you gain easy access to the different radar +fields (reflectivity, velocity, spectral width, etc.) and ancilliary +information (headers: time, beam width, angles, etc). And, with the +tools you can code a scientific application that are radar format +independent. + +COPYRIGHT NOTICE: + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996-1999 + John H. Merritt + SM&A Corp. + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +System Requirements: + HP (755/hpux), Linux, SUN (SparcII), SGI(4D/IRIX). Should run on any +other hardware. + +Memory Requirements: + 16 Mbytes of RAM just to ingest the data. Plus any for your application. + If you expect to use the TSDIS toolkit component, which requires the HDF + library, then you'll need at least 64 MB RAM! + +Software Environment. Additional libraries may be needed for building +or linking, especially if you plan to use the TSDIS Toolkit and HDF. +All the source for wsr88d, lassen, tg, nsig, mcgill, kwajalein, +etc, are included in librsl.a and librsl.so. RSL works on big or +little endian machines. HP, SUN, SGI are examples of big endian machines. +Intel 386/486/Pentium is an example of a little endian machine. + +Additional software needed for executing RSL code is listed below. +Note, RSL can be built without TSDIS toolkit and without HDF and +without PKWARE support. + + pbmplus (Jef Poskanzer) Available via anon ftp to ftp.uu.net. This is + used when making GIF, PPM, PBM, PGM, PICT, etc. + images. Output via pipes. Required for executing + your RSL application, if you plan to output images. + This is not required when + linking your application with the RSL. + + You only need ppmtogif and ppmtopict. + + gcc (GNU cc compiler) Normal cc or acc (sun) will work. Not required, + but, you do need an ansi compilier. + + gzip (GNU compress) Available via anon ftp to ftp.uu.net. Unpacking. + Input and output filters for auto un/compressing. + + + make (GNU make) GNU make version 3.76. Standard make on SGI + IRIX 6.2 doesn't work. It's a good idea + to have GNU make (GNU tar too). + + PKWARE Data Version 1.11. Needed for the RAPIC ingest. + Compression library. Call PKWARE, Inc. at 414-354-8699 or via + http://www.pkware.com. + + libetor The EDGE libraray to decode the EDGE format. + This is available from Enterprise Electronics + Corporation, Enterprise, Alabama, USA 36330 + 334-347-3478. + +Example mainlines are provided in the directory examples. + +INSTALLATION INSTRUCTIONS +-------------------------- + +1. Unpack the GNU compressed tar archive, example: + + gtar -xzf rsl-v1.29.tgz + + -or- + + gzcat rsl-v1.29.tgz | tar xf - + +2. If you DON'T want LASSEN capability or you find that your system + can not compile the lassen routines, you must edit acconfig.h and + change '#define HAVE_LASSEN 1' to '#undef HAVE_LASSEN'. + +3. configure + make install -- Installs the RSL library, and then installs + any_to_gif and any_to_uf. + +NOTE: You can specify the --prefix=/some/other/dir as an option to + the configure command. This will install the librsl.so there + and will install the examples there. Also, when resolving + whether you have hdf, tsdistk, etc. the --prefix instructs + configure to look in the prefix/lib directory for those libraries. + The examples installed are any_to_gif and any_to_uf. + +APPLYING PATCHES +---------------- + +Using patch files saves network transmission times when upgrading +to the next version of RSL. Patch files are context differences +from one RSL release to the next. The patch files are located +in the anonymous ftp directory pub/software on trmm.gsfc.nasa.gov, +and they typically have the name of the form rsl.v1.14_to_v1.15.patch.gz. + +You will be applying the patch files from the directory where 'rsl' is +a subdirectory (from the parent directory of rsl). + +Follow these steps to upgrade using patch files. This demonstrates applying +patches from version 1.11 to 1.15. + +1. Make a symbolic link called 'rsl' that points to the current version + of RSL you have. For example: + + ln -s rsl-v1.11 rsl + +2. Apply patches. Here we'll go from v1.11 to v1.15. + + zcat rsl.v1.11_to_v1.12.patch.gz | patch + zcat rsl.v1.12_to_v1.13.patch.gz | patch + zcat rsl.v1.13_to_v1.14.patch.gz | patch + zcat rsl.v1.14_to_v1.15.patch.gz | patch + +3. Rename the rsl-v1.11 directory to be rsl-v1.15. You no longer + need the 'rsl' directory. + + mv rsl-v1.11 rsl-v1.15 + rm rsl + + +BUILDING APPLICATIONS +--------------------- +Place the following line in your C code: + +#include "rsl.h" + +And link your application with: + + -lrsl -lm + +If you're on a SUN, you might have to specify: + + -lrsl -lnsl -lm + +If you want HDF and TSDIS toolkit libraries (the link line looks messy): + + setenv TSDISTK /usr/local/toolkit (or your top-level directory name) + + -lrsl -L/usr/local/hdf/lib -L/usr/local/toolkit/lib \ + -ltsdistk -lmfhdf -ldf -ljpeg -lz -lm + + Be sure to substitute the appropriate -L specification for the HDF + and the TSDISTK library paths on your system. + +PROBLEMS +-------- + +1. If you don't have ppmtogif nor ppmtopict, you can still make images. The + images will be PPM files. Create two commands called 'ppmtogif' and + 'ppmtopict' that consists of the following two lines: +---- cut ---- +#!/bin/csh -f +cat +---- cut ---- + Make these new commands executable and + place them in a directory that is in your $PATH. No translation + of PPM will happen and you can use 'xv', for instance, to view + the files. + +2. Linking on SUN running SunOS 5.4, you may need to add '-lnsl' to + the link line to link your application. 'libnsl.{a,so}' is where + the 'xdr' routines reside. + +3. On our HP, gcc cannot build a shared library in one fell swoop. You + must use the '-v' option. You'll get an error similiar to that shown + in the following 'make' excerpt. + + +----- cut ----- +gcc -v -shared -W1,-soname,librsl.so.1 -o librsl.so.1.17 rapic_to_radar.o rapic.tab.o lex.rapic.o rapic_routines.o radar.o volume.o image_gen.o cappi.o fraction.o read_write.o farea.o range.o radar_to_uf.o uf_to_radar.o lassen_to_radar.o wsr88d_to_radar.o carpi.o cube.o sort_rays.o toga_to_radar.o gts.o histogram.o ray_indexes.o anyformat_to_radar.o get_win.o endian.o mcgill_to_radar.o mcgill.o interp.o toga.o lassen.o wsr88d.o wsr88d_get_site.o gzip.o prune.o reverse.o fix_headers.o radar_to_hdf_1.o radar_to_hdf_2.o nsig_to_radar.o nsig.o nsig2_to_radar.o hdf_to_radar.o toolkit_memory_mgt.o africa_to_radar.o africa.o +Reading specs from /opt/hppd/lib/gcc/gcc-lib/hppa1.1-hp-hpux9.05/2.7.2.1/specs +gcc version 2.7.2.1 + /opt/hppd/lib/gcc/gcc-lib/hppa1.1-hp-hpux9.05/2.7.2.1/ld -b -o librsl.so.1.17 -L/opt/hppd/lib/gcc/gcc-lib/hppa1.1-hp-hpux9.05/2.7.2.1 -L/opt/hppd/lib/gcc rapic_to_radar.o rapic.tab.o lex.rapic.o rapic_routines.o radar.o volume.o image_gen.o cappi.o fraction.o read_write.o farea.o range.o radar_to_uf.o uf_to_radar.o lassen_to_radar.o wsr88d_to_radar.o carpi.o cube.o sort_rays.o toga_to_radar.o gts.o histogram.o ray_indexes.o anyformat_to_radar.o get_win.o endian.o mcgill_to_radar.o mcgill.o interp.o toga.o lassen.o wsr88d.o wsr88d_get_site.o gzip.o prune.o reverse.o fix_headers.o radar_to_hdf_1.o radar_to_hdf_2.o nsig_to_radar.o nsig.o nsig2_to_radar.o hdf_to_radar.o toolkit_memory_mgt.o africa_to_radar.o africa.o +/bin/ld: DP-Relative Code in file /usr/tmp/cca11778.o - Shared Library must be Position-Independent +collect2: ld returned 1 exit status +make: *** [librsl.so.1.17] Error 1 +----- cut ----- + + Take the 'ld' command that is shown, the second of the two commands, + and execute it directly at the Unix prompt. It will create the + shared library. I don't get it, but, it works. My guess is that + the 'gcc' command is doing something that is not shown. What is + shown are the correct commands. Go figure. + + +Contributions +------------- +Dave Wolff - Most of the specifications for the functionality and feedback + during debugging. +Mike Kolander - The HDF, Mcgill and kwaj to radar routines. +Alan McConnell - The toga_to_radar routine. +Dennis Flanigan - New sorting code. Echo top height routines. Vertical + structure code. +Thuy Nguyen - Bug fixes and testing. +Paul Kucera - Testing, bug reports and SIGMET code. +Michael Whimpy - BMRC, Austrailia. Lassen modifications. +Don Burrows - The edge_to_radar routine. + +QUESTIONS +--------- + +Contact the TRMM Office help at help@radar.gsfc.nasa.gov diff --git a/africa.c b/africa.c new file mode 100644 index 0000000..7348587 --- /dev/null +++ b/africa.c @@ -0,0 +1,141 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include "africa.h" + +int africa_read_buffer(FILE *fp, Africa_buffer *buffer) +{ + int n; + + n = fread(buffer, 1, sizeof(Africa_buffer), fp); + return n; +} + +float africa_bcd_convert(unsigned short bcd) +{ + int val; + + val = + ((bcd >> 12) & 0xf) * 1000 + + ((bcd >> 8) & 0xf) * 100 + + ((bcd >> 4) & 0xf) * 10 + + ( bcd & 0xf); + return val/10.0; +} + +Africa_sweep * africa_new_sweep(int nray) +{ + Africa_sweep *sweep; + + sweep = (Africa_sweep *)calloc(nray, sizeof(Africa_sweep)); + if (! sweep) { + perror("africa_new_sweep:sweep"); + return NULL; + } + sweep->nrays = nray; + sweep->ray = (Africa_ray **) calloc(nray, sizeof(Africa_ray *)); + if (! sweep -> ray) { + perror("africa_new_sweep:ray"); + return NULL; + } + return sweep; +} + +Africa_ray *africa_new_ray(void) +{ + Africa_ray *ray; + ray = (Africa_ray *)calloc(1, sizeof(Africa_ray)); + if (! ray) { + perror("africa_new_ray:ray"); + return NULL; + } + return ray; +} + +void africa_free_ray(Africa_ray *r) +{ + if (! r) return; + free(r); +} + +void africa_free_sweep(Africa_sweep *s) +{ + int i; + if (! s) return; + if (! s->ray) return; + for (i=0; inrays; i++) { + africa_free_ray(s->ray[i]); + } + free(s->ray); + free(s); +} + +Africa_sweep *africa_read_sweep(FILE *fp) +{ + /* This contains the next ray of data, except + * when this is the first ray. This is a + * read-ahead buffer. + */ + static Africa_buffer *buf = NULL; /* The read ahead buffer, too. */ + Africa_sweep *sweep = NULL; + int cur_elev, ielev, iray; + Africa_ray *ray = NULL; + int nray; + + if (! buf) { + buf = (Africa_buffer *) calloc(1, sizeof(Africa_buffer)); + if (! buf) { + perror("allocate buf in read_sweep"); + return NULL; + } + /* (pre)Read a record */ + africa_read_buffer(fp, buf); /* allocates space for buffer */ + + } + /* Allocate 500 (should be enough) ray pointers. */ + + sweep = africa_new_sweep(1000); /* 500 times 2 field types ? */ + /* Determine the elevation step we're on so we know when to + * return the sweep. Basically, the last read will be the + * data for the next sweep; the meaning of the above code. + */ + cur_elev = ielev = buf->raycount/512; + nray = 0; + while(cur_elev == ielev) { + iray = buf->raycount - cur_elev*512; + if (iray != 0) { + ray = sweep->ray[nray]; + if (!ray) sweep->ray[nray] = ray = africa_new_ray(); + memcpy(ray, buf, sizeof(Africa_buffer)); + nray++; + } + if (africa_read_buffer(fp, buf) == 0) break; + cur_elev = buf->raycount/512; + /* isite = buf->xmit_power_site & 0x1f; */ + } + if (nray == 0) return NULL; + sweep->nrays = nray; + + return sweep; +} diff --git a/africa.h b/africa.h new file mode 100644 index 0000000..9b493cb --- /dev/null +++ b/africa.h @@ -0,0 +1,69 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +typedef struct { + unsigned short + yearjday, /* Year * 512 + Julian day. */ + hour, /* Hour. */ + minute_sec, /* Minute * 60 + seconds. */ + bcd_start_azim, /* BCD code for start of azimuth. */ + bcd_end_azim, /* BCD code for end of azimuth. */ + raycount, /* Raycount + elstep * 512. Set to 0 for last ray of ppi */ + bcd_azimuth, /* BCD code for azimuth. */ + bcd_elevation, /* BCD code for elevation. */ + mds, /* Minumum detectable signal (MDS). */ + mus, /* Minumum usable signal (MUS). */ + rvpc_high, + rvpc_low, /* High and low level, in RVPC units. */ + phi, /* PHI - RVPC high level in dbm * 32. */ + plo, /* PLO - RVPC high level in dbm * 32. */ + xmit_power_site, /* Transimitter Power * 32 + Site number. */ + skip_width_azim_avg, /* Skip + Bin width * 256 + + * Azimuth Averaging Factor * 4096. + */ + bin[224], /* RVPC COUNT for range bin[1..224] */ + notused[256-241+1]; /* Not used. */ +} Africa_buffer; + +typedef Africa_buffer Africa_ray; + +typedef struct { + int nrays; + Africa_ray **ray; /* 0..nrays-1 of Africa_rays */ +} Africa_sweep; + + +typedef struct { + int nsweeps; + Africa_sweep **sweep; /*0..nsweeps-1 of Africa_sweeps */ +} Africa_volume; + +/* Prototype routine definitions */ + +int africa_read_buffer(FILE *fp, Africa_buffer *buffer); +float africa_bcd_convert(unsigned short bcd); +Africa_sweep * africa_new_sweep(int nray); +Africa_ray *africa_new_ray(void); +void africa_free_ray(Africa_ray *r); +void africa_free_sweep(Africa_sweep *s); +Africa_sweep *africa_read_sweep(FILE *fp); diff --git a/africa_to_radar.c b/africa_to_radar.c new file mode 100644 index 0000000..a5bffdd --- /dev/null +++ b/africa_to_radar.c @@ -0,0 +1,163 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include +#include "rsl.h" +#include "africa.h" + +static void ymd(int jday, int yy, int *mm, int *dd); + +static int daytab[2][13] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} +}; + +static void ymd(int jday, int year, int *mm, int *dd) +{ + /* Input: jday, yyyy */ + /* Output: mm, dd */ + int leap; + int i; + + leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; + for (i=0; daytab[leap][i]v[DZ_INDEX] = RSL_new_volume(20); + v = radar->v[DZ_INDEX]; + + for(i=0; (sweep = africa_read_sweep(fp)); i++) { + + /* Load the sweep into the radar volume */ + v->sweep[i] = RSL_new_sweep((int)sweep->nrays); + s = v->sweep[i]; + if (radar_verbose_flag) printf("NUMBER OF RAYS: %d\n", sweep->nrays); + for (n=0; n < sweep->nrays; n++) { + ray = sweep->ray[n]; + if (ray == NULL) continue; + year = ray->yearjday/512; + jday = ray->yearjday & 0x1ff; + year += 1900; + if (year < 1970) year += 100; /* >=2000 */ + ymd(jday, year, &month, &day); + hour = ray->hour; + min = ray->minute_sec/60; + sec = ray->minute_sec - min*60; + + elev = africa_bcd_convert (ray->bcd_elevation); + azim = africa_bcd_convert (ray->bcd_azimuth); + s_azim = africa_bcd_convert (ray->bcd_start_azim); + e_azim = africa_bcd_convert (ray->bcd_end_azim); + + /* Values that I CANNOT trust. + * e_azim + * + * DATA ORGANIZATION: + * Usually, 10 ray groups for each field type. Field type is in + * ray->xmit_power_site (Doc wrong?) + * iray == 0 when at the end of the sweep. (Don't need lookahead) + */ + + ielev = ray->raycount/512; + iray = ray->raycount - ielev*512; + isite = ray->xmit_power_site & 0x1f; + printf("Record %d, time = %.2d:%.2d:%.2d %.2d/%.2d/%.2d --> elev,azim = %f, %f. Start: %f, %f, iray/ielev %d %d, site=%d\n", n, + hour, min, sec, month, day, year-1900, elev, azim, s_azim, e_azim, iray, ielev, isite); + + + if (isite != 22) continue; + /* ONLY LOAD from isite==22, for now. */ + r = RSL_new_ray(224); + s->ray[n] = r; + r->h.month = month; + r->h.day = day; + r->h.year = year; + r->h.hour = hour; + r->h.minute = min; + r->h.sec = sec; + r->h.azimuth = azim; + r->h.ray_num = iray; + r->h.elev = elev; + r->h.elev_num = ielev; + r->h.beam_width = 1.0; + r->h.gate_size = 1000; + + /* What are the others? */ + + r->h.invf = DZ_INVF; + r->h.f = DZ_F; + s->h.horz_half_bw = 0.5; + s->h.vert_half_bw = 0.5; + s->h.beam_width = r->h.beam_width; + + for (ibin=0; ibinh.nbins; ibin++) { + r->range[ibin] = r->h.invf(ray->bin[ibin]/8.0/100.0 + 0.5); + } + } + } + fclose(fp); + + sprintf(radar->h.radar_type, "south_africa"); + sprintf(radar->h.name, "SAFRICA"); + sprintf(radar->h.radar_name, "SAFRICA"); + sprintf(radar->h.city, "I don't know"); + sprintf(radar->h.state, "??"); + sprintf(radar->h.country, "South Africa"); + + radar_load_date_time(radar); + return radar; +} diff --git a/anyformat_to_radar.c b/anyformat_to_radar.c new file mode 100644 index 0000000..601a6f3 --- /dev/null +++ b/anyformat_to_radar.c @@ -0,0 +1,171 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * By John H. Merritt + * Science Applications Corporation, Vienna, VA + */ + +#include +#include +#include +#include +#include "rsl.h" +void rsl_readflush(FILE *fp); +/*********************************************************************/ +/* */ +/* RSL_filetype */ +/* */ +/*********************************************************************/ +enum File_type RSL_filetype(char *infile) +{ + /* Open the input file and peek at the first few bytes to determine + * the type of file. + * + * UF - First two bytes 'UF' + * - or 3,4 bytes 'UF' + * - or 5,6 bytes 'UF'. This is the most common. + * + * WSR88D - First 8 bytes: 'ARCHIVE2' or 'AR2V0001' + * + * TOGA - ?? + * NSIG - ?? + * LASSEN - SUNRISE + * RSL - RSL + * MCGILL - P A B + * RAPIC - /IMAGE: + * RADTEC - 320 (decimal, in first two bytes) + * RAINBOW - First two bytes: decimal 1, followed by 'H' + */ + FILE *fp; + char magic[11]; + + if ((fp = fopen(infile, "r")) == NULL) { + perror(infile); + return UNKNOWN; + } + + /* Read the magic bytes. */ + fp = uncompress_pipe(fp); /* If gzip available. */ + if (fread(magic, sizeof(magic), 1, fp) != 1) { + char *magic_str = (char *)calloc(sizeof(magic)+1, sizeof(char)); + memcpy(magic_str, magic, sizeof(magic)); + fprintf(stderr,"Error fread: Magic is %s\n", magic_str); + free (magic_str); + perror("RSL_filetype"); + fclose(fp); + return UNKNOWN; + } + + rsl_readflush(fp); /* Fork, read and exit -- eliminates the 'Broken pipe' */ + + if (strncmp("ARCHIVE2.", magic, 9) == 0) return WSR88D_FILE; + if (strncmp("AR2V000", magic, 7) == 0) return WSR88D_FILE; + if (strncmp("UF", magic, 2) == 0) return UF_FILE; + if (strncmp("UF", &magic[2], 2) == 0) return UF_FILE; + if (strncmp("UF", &magic[4], 2) == 0) return UF_FILE; + if ((int)magic[0] == 0x0e && + (int)magic[1] == 0x03 && + (int)magic[2] == 0x13 && + (int)magic[3] == 0x01 + ) return HDF_FILE; + if (strncmp("RSL", magic, 3) == 0) return RSL_FILE; + if ((int)magic[0] == 7) return NSIG_FILE_V1; + if ((int)magic[1] == 7) return NSIG_FILE_V1; + if ((int)magic[0] == 27) return NSIG_FILE_V2; + if ((int)magic[1] == 27) return NSIG_FILE_V2; + if (strncmp("/IMAGE:", magic, 7) == 0) return RAPIC_FILE; + if ((int)magic[0] == 0x40 && + (int)magic[1] == 0x01 + ) return RADTEC_FILE; + if ((int)magic[0] == 0x01 && magic[1] == 'H') return RAINBOW_FILE; + + if (strncmp("SUNRISE", &magic[4], 7) == 0) return LASSEN_FILE; +/* The 'P A B' is just too specific to be a true magic number, but that's all + * I've got. + */ + if (strncmp("P A B ", magic, 6) == 0) return MCGILL_FILE; + /* Byte swapped ? */ + if (strncmp(" P A B", magic, 6) == 0) return MCGILL_FILE; + if (strncmp("Volume", magic, 6) == 0) return EDGE_FILE; + if (strncmp("VOLD", magic, 4) == 0) return DORADE_FILE; + + return UNKNOWN; +} + + + + + + + +/*********************************************************************/ +/* */ +/* RSL_anyformat_to_radar */ +/* */ +/*********************************************************************/ + +Radar *RSL_anyformat_to_radar(char *infile, ...) +{ + va_list ap; + char *callid_or_file; + Radar *radar; + +/* If it is detected that the input file is WSR88D, use the second argument + * as the call id of the site, or the file name of the tape header file. + * + * Assumption: Input files are seekable. + */ + radar = NULL; + switch (RSL_filetype(infile)) { + case WSR88D_FILE: + callid_or_file = NULL; + va_start(ap, infile); + callid_or_file = va_arg(ap, char *); + va_end(ap); + radar = RSL_wsr88d_to_radar(infile, callid_or_file); + break; + case UF_FILE: radar = RSL_uf_to_radar(infile); break; + case TOGA_FILE: radar = RSL_toga_to_radar(infile); break; + case NSIG_FILE_V1: radar = RSL_nsig_to_radar(infile); break; + case NSIG_FILE_V2: radar = RSL_nsig2_to_radar(infile); break; + case RAPIC_FILE: radar = RSL_rapic_to_radar(infile); break; + case RADTEC_FILE: radar = RSL_radtec_to_radar(infile); break; + case RSL_FILE: radar = RSL_read_radar(infile); break; +#ifdef HAVE_LIBTSDISTK + case HDF_FILE: radar = RSL_hdf_to_radar(infile); break; +#endif + case RAINBOW_FILE: radar = RSL_rainbow_to_radar(infile); break; + case MCGILL_FILE: radar = RSL_mcgill_to_radar(infile); break; + case EDGE_FILE: radar = RSL_EDGE_to_radar(infile); break; + case LASSEN_FILE: radar = RSL_lassen_to_radar(infile); break; + case DORADE_FILE: radar = RSL_dorade_to_radar(infile); break; + + default: + fprintf(stderr, "Unknown input file type. File <%s> is not recognized by RSL.\n", infile); + return NULL; + } + + return radar; +} + + diff --git a/cappi.c b/cappi.c new file mode 100644 index 0000000..6a8ed20 --- /dev/null +++ b/cappi.c @@ -0,0 +1,192 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1995 Dennis F. Flanigan Jr. of Applied Research Corporation, + Landover, Maryland, a NASA/GSFC on-site contractor. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* File: cappi.c + * + * 1/9/95 DFF + * Version 0.29 updates + */ + +#include +#include +#include +#include "rsl.h" + +extern int radar_verbose_flag; + + +/*********************************************************************/ +/* */ +/* RSL_get_value_from_cappi */ +/* */ +/*********************************************************************/ +float RSL_get_value_from_cappi(Cappi *cappi, float rng, float azm) + { + return RSL_get_value_from_sweep(cappi->sweep, azm, rng); + } + +/*********************************************************************/ +/* */ +/* RSL_new_cappi */ +/* RSL_free_cappi */ +/* */ +/* Dennis Flanigan */ +/* Mods by John Merritt 6/14/95 */ +/*********************************************************************/ + +Cappi *RSL_new_cappi(Sweep *sweep, float height) + { + /* Modeled after a sweep structure. */ + int a; + Cappi *c; + float grange; + Ray *ray; + int num_bin; + float start_bin, size_bin; + + if((c = (Cappi *)calloc(1, sizeof(Cappi))) == NULL) + { + fprintf(stderr,"RSL_new_cappi: Calloc failed for Cappi data structure.\n"); + return(NULL); + } + + c->height = height; + ray = RSL_get_first_ray_of_sweep(sweep); + num_bin = ray->h.nbins; + start_bin = ray->h.range_bin1/1000.0; + size_bin = ray->h.gate_size/1000.0; + + /* Allocate space for elev angle,range array */ + if((c->loc =(Er_loc *)calloc(num_bin,sizeof(Er_loc))) == NULL) + { + fprintf(stderr,"RSL_new_cappi: Calloc failed for er_loc array. \n"); + free(c); + return(NULL); + } + + /* Calculate elevation angle verse range array */ + for(a=0;aloc[a].srange,&c->loc[a].elev); + } + + /* Allocate Space for the data */ + c->sweep = RSL_copy_sweep(sweep); + RSL_clear_sweep(c->sweep); /* This maintains header info. */ + + return c; + } + +void RSL_free_cappi(Cappi *c) + { + if (c == NULL) return; + RSL_free_sweep(c->sweep); + free(c->loc); + free(c); + + return; + } + + +/*********************************************************************/ +/* */ +/* RSL_cappi_at_h */ +/* */ +/* DFF 10/28/94 */ +/* Modified by John Merritt 6/14/95 */ +/*********************************************************************/ +Cappi *RSL_cappi_at_h(Volume *v, float height, float max_range) + /* + * h and max_range in KM. + */ + { + int n; + Cappi *c; + Sweep *sweep; + + if (v == NULL) return NULL; + sweep = RSL_get_first_sweep_of_volume(v); /* 1st non-NULL sweep */ + + if((c = RSL_new_cappi(sweep, height)) == NULL) + { + fprintf(stderr,"RSL_cappi_at_h: Vnew_cappi failed\n"); + return (NULL); + } + + if((n = RSL_fill_cappi(v,c,0)) < 0) + { + fprintf(stderr,"RSL_cappi_at_h: Vfill_cappi_at_h failed: returned: %d\n",n); + RSL_free_cappi(c); + return(NULL); + } + + return(c); + } + + +/*********************************************************************/ +/* */ +/* RSL_fill_cappi */ +/* DFF 10/28/94 */ +/*********************************************************************/ +int RSL_fill_cappi(Volume *v, Cappi *cap, int method) + { + int a,b; + float x; + Ray *ray; + Sweep *sweep; + + if (v == NULL) return(-1); + if (cap == NULL) return(-1); + + /* get data from frist ray. */ + ray = RSL_get_first_ray_of_volume(v); + cap->month = ray->h.month; + cap->day = ray->h.day; + cap->year = ray->h.year; + cap->hour = ray->h.hour; + cap->minute = ray->h.minute; + cap->sec = ray->h.sec; + cap->field_type = 1; /** default setting -- PAK **/ + cap->interp_method = method; /* ?? nearest neighbor */ + + ray = RSL_get_first_ray_of_sweep(cap->sweep); + sweep = cap->sweep; + for(a=0;a < sweep->h.nrays; a++) + { + ray = sweep->ray[a]; + for(b=0; b < ray->h.nbins; b++) + { + x = RSL_get_value(v, + cap->loc[b].elev, + cap->sweep->ray[a]->h.azimuth, + cap->loc[b].srange); + + ray->range[b] = ray->h.invf(x); + } + } + + return 1; + } + + + diff --git a/carpi.c b/carpi.c new file mode 100644 index 0000000..211c558 --- /dev/null +++ b/carpi.c @@ -0,0 +1,302 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* Mike Kolander + * Space Applications Corporation + * NASA/Goddard 910.1 + */ + +#include +#include +#include +#include + +#include "rsl.h" + +#define RAD2DEG 57.29578 /* radian to degree conversion */ +#define MAXRAYS 512 /* loop safety valve when traversing a sweep */ + +extern int radar_verbose_flag; + + +/*************************************************************/ +/* */ +/* RSL_free_carpi */ +/* */ +/*************************************************************/ +void RSL_free_carpi(Carpi *carpi) +{ + /* Frees memory allocated to a carpi structure, and associated + pointer and data arrays. + */ + + if (carpi != NULL) + { + if (carpi->data != NULL) + { + if (carpi->data[0] != NULL) + free(carpi->data[0]); /* Free the 2D data array. */ + free(carpi->data); /* Free the vector of pointers. */ + } + free(carpi); /* Free the carpi structure. */ + } +} + +/*************************************************************/ +/* */ +/* RSL_new_carpi */ +/* */ +/*************************************************************/ +Carpi *RSL_new_carpi(int nrows, int ncols) +{ + /* Allocates memory for a carpi structure, and associated pointer + and data arrays. + */ + Carpi *c; + Carpi_value *data; + int row; + + /* Allocate a carpi. */ + c = (Carpi *)calloc(1, sizeof(Carpi)); + if (c == NULL) perror("RSL_new_carpi"); + /* Allocate a vector of 'nrows' pointers. */ + c->data = (Carpi_value **)calloc(nrows, sizeof(Carpi_value *)); + if (c->data == NULL) perror("RSL_new_carpi"); + /* Allocate a 2 dimensional array for the actual data values. */ + data = (Carpi_value *)calloc(nrows*ncols, sizeof(Carpi_value)); + if (data == NULL) perror("RSL_new_carpi"); + /* Fill all the 'nrows' pointer slots created above. */ + for (row=0; rowdata[row] = data + row*ncols; + + return(c); +} + +/*************************************************************/ +/* */ +/* RSL_volume_to_carpi */ +/* */ +/*************************************************************/ +Carpi *RSL_volume_to_carpi(Volume *v, float h, float grnd_r, + float dx, float dy, int nx, int ny, + int radar_x, int radar_y, float lat, float lon) +/* + * Creates a carpi from a volume structure. + * + * +--------------------+ ^ + * | | | + * | | | + * | cell size dx,dy | ny + * | | | + * | | | + * +--------------------+ V + * lat,lon + * <-------- nx --------> + * + * Radar centered at radar_x, radar_y. + */ + +{ + Cappi *cappi; + Carpi *carpi; + + if (v == NULL) return NULL; + cappi = RSL_cappi_at_h(v, h, grnd_r); + cappi->lat = lat; + cappi->lon = lon; + cappi->interp_method = 0; + + carpi = RSL_cappi_to_carpi(cappi, dx, dy, lat, lon, nx, ny, + radar_x, radar_y); + if (carpi == NULL) return NULL; + RSL_free_cappi(cappi); + return carpi; +} + +/*************************************************************/ +/* */ +/* RSL_find_rng_azm */ +/* */ +/*************************************************************/ +void RSL_find_rng_azm(float *r, float *ang, float x, float y) +{ +/* Convert Cartesian coords (x,y) to polar (rng,angle); 0 0.0) + *ang = 90.0 - *ang; + else + *ang = 270.0 - *ang; + } + else /* x is 0.0 */ + { + if (y >= 0.0) *ang = 0.0; + else *ang = 180.0; + } +} + +/*************************************************************/ +/* */ +/* RSL_cappi_to_carpi */ +/* */ +/*************************************************************/ +Carpi *RSL_cappi_to_carpi(Cappi *cappi, float dx, float dy, float lat, + float lon, int nx, int ny, int radar_x, int radar_y) + /****** Simple and straightforward algorithm: + Divide each of the nx*ny carpi cells into scx*scy subcells. + Find the data value for each subcell from the cappi rays. + Average the subcell data values over a cell to obtain the cell value. + Store the cell value into the 2_D carpi array. + ********/ +{ + Carpi *carpi; + Ray *first_ray; + int row, col, j, k, m, n, scx, scy, valid_subcells; + float x, y, rng, azm, cell, cell_diag, gate_size; + float carpi_max_rng, radar_max_rng; + float subcell[3][3]; /* Maximum of 9 subcells per carpi cell*/ + + if (cappi == NULL) return NULL; + if (cappi->sweep == NULL) return NULL; + first_ray = RSL_get_first_ray_of_sweep(cappi->sweep); + if (first_ray == NULL) return NULL; /* No data. */ + + if (radar_verbose_flag) fprintf(stderr,"\nCreating carpi...\n"); + + /* Allcate space for a carpi, and fill in its values. */ + carpi = RSL_new_carpi(ny, nx); + carpi->month = cappi->month; + carpi->day = cappi->day; + carpi->year = cappi->year; + carpi->hour = cappi->hour; + carpi->minute = cappi->minute; + carpi->sec = cappi->sec; + carpi->dx = dx; + carpi->dy = dy; + carpi->nx = nx; + carpi->ny = ny; + carpi->radar_x = radar_x; + carpi->radar_y = radar_y; + carpi->height = cappi->height; + carpi->lat = lat; + carpi->lon = lon; + strncpy(carpi->radar_type, cappi->radar_type, sizeof(cappi->radar_type)); + carpi->field_type = cappi->field_type; + carpi->interp_method = cappi->interp_method; + carpi->f = first_ray->h.f; + carpi->invf = first_ray->h.invf; + + gate_size = first_ray->h.gate_size / 1000.0; /* km */ + cell_diag = sqrt(dx*dx + dy*dy); + /* How many subcells per carpi cell? The larger the carpi cell relative + to gate_size, the more subcells we want. Will have scx*scy subcells + per carpi cell. Note below that the max no. of subcells is 9 . */ + if ((dy - gate_size) < 0.0) + scy = 1; + else if ((dy - gate_size) <= 1.0) + scy = 2; + else + scy = 3; + + if ((dx - gate_size) < 0.0) + scx = 1; + else if ((dx - gate_size) <= 1.0) + scx = 2; + else + scx = 3; + + /* Max range of the radar data */ + radar_max_rng = first_ray->h.nbins * gate_size; /* km */ + /* Max range of desired carpi is max of x and y directions. */ + carpi_max_rng = nx / 2.0 * dx; /* km */ + if ( (ny / 2.0 * dy) > carpi_max_rng ) + carpi_max_rng = ny / 2.0 * dy; + /* carpi_max_rng is smaller of (radar_max_rng, carpi_max_rng) */ + if (radar_max_rng < carpi_max_rng) + carpi_max_rng = radar_max_rng; + + if (radar_verbose_flag) + fprintf(stderr,"carpi_max_rng:%.1f(km) beam_width:%.1f gate_size:%d(m)\n", + carpi_max_rng, cappi->sweep->h.beam_width, first_ray->h.gate_size); + + /* For each cell (row,col) comprising the carpi...*/ + for (row=0; row carpi_max_rng) + { + /* Totality of carpi cell lies outside data range. */ + cell = (float) BADVAL; + goto escape; + } + } /* end if (m == 0) */ + /* cell lies in data range. Get data value from cappi. */ + subcell[n][m] = RSL_get_value_from_cappi(cappi,rng,azm); + } /* end for (m=... */ + } /* end for (n=... */ + + /* All subcell values have now been determined. Average them + to determine the cell value. */ + valid_subcells = 0; /* number subcells having valid data values.*/ + cell = 0.0; + for (j=0; j= NOECHO)) + continue; + else /* valid data value. */ + { + cell = cell + subcell[j][k]; + valid_subcells++; + } + } /* end for (j=0; jdata[row][col] = (Carpi_value) carpi->invf(cell); + } /* end for (col=... */ + } /* end for (row=... */ + + return(carpi); +} diff --git a/colors/Makefile.am b/colors/Makefile.am new file mode 100644 index 0000000..709a367 --- /dev/null +++ b/colors/Makefile.am @@ -0,0 +1,6 @@ +AUTOMAKE_OPTIONS = foreign + +colordir = $(prefix)/lib/colors +color_DATA = *.??? + +EXTRA_DIST = $(color_DATA) diff --git a/colors/blu_dz.clr b/colors/blu_dz.clr new file mode 100644 index 0000000000000000000000000000000000000000..2f06f91c1710ccff6b606846d5574a82f054262a GIT binary patch literal 206 zcmZQ@;1!ngv2^qds%z|@yZZm}tB*haXMh1EFe61vTZchkS)3at45YiKFWI>7zX_7a HU|<3O8gUQ< literal 0 HcmV?d00001 diff --git a/colors/blu_height.clr b/colors/blu_height.clr new file mode 100644 index 0000000000000000000000000000000000000000..0e8d07095146bdfd6841e2696f229a7c05efbccf GIT binary patch literal 236 zcmZQDPMC0D%J$p;85o&ZIJkKE8QA$ml~mN!HMMp03=EA;%q%ReZS5SKoL${LynKB9 z1A{`s!Xu+&;t~>*Q`0gsvvczbii%6iE2?U0>l>R|+S)t2d-^6!oIG{fjG43N&RekP z|I+0vR;^jPe&ePs+qUoAy=UKngNKhEJ8|mt*>e{zUA}t##;rSd?>~I>@;sUkCsI literal 0 HcmV?d00001 diff --git a/colors/blu_hh.clr b/colors/blu_hh.clr new file mode 100644 index 0000000000000000000000000000000000000000..0e8d07095146bdfd6841e2696f229a7c05efbccf GIT binary patch literal 236 zcmZQDPMC0D%J$p;85o&ZIJkKE8QA$ml~mN!HMMp03=EA;%q%ReZS5SKoL${LynKB9 z1A{`s!Xu+&;t~>*Q`0gsvvczbii%6iE2?U0>l>R|+S)t2d-^6!oIG{fjG43N&RekP z|I+0vR;^jPe&ePs+qUoAy=UKngNKhEJ8|mt*>e{zUA}t##;rSd?>~I>@;sUkCsI literal 0 HcmV?d00001 diff --git a/colors/blu_rainfall.clr b/colors/blu_rainfall.clr new file mode 100644 index 0000000000000000000000000000000000000000..4c873a8ba631e8f2fa54883b5cbbf67ed5fcb2bd GIT binary patch literal 216 zcmZShe`?j-90nlx|9|V&mKFvP5E~!(4+pE^;3OQtB@qmu$ut937$P_HFhp+30b(77 P$o>k3$ms?Qk<%Oi80ePQ literal 0 HcmV?d00001 diff --git a/colors/blu_reflectivity.clr b/colors/blu_reflectivity.clr new file mode 100644 index 0000000000000000000000000000000000000000..2f06f91c1710ccff6b606846d5574a82f054262a GIT binary patch literal 206 zcmZQ@;1!ngv2^qds%z|@yZZm}tB*haXMh1EFe61vTZchkS)3at45YiKFWI>7zX_7a HU|<3O8gUQ< literal 0 HcmV?d00001 diff --git a/colors/blu_reflectivity1.clr b/colors/blu_reflectivity1.clr new file mode 100644 index 0000000000000000000000000000000000000000..2f06f91c1710ccff6b606846d5574a82f054262a GIT binary patch literal 206 zcmZQ@;1!ngv2^qds%z|@yZZm}tB*haXMh1EFe61vTZchkS)3at45YiKFWI>7zX_7a HU|<3O8gUQ< literal 0 HcmV?d00001 diff --git a/colors/blu_spectral_width.clr b/colors/blu_spectral_width.clr new file mode 100644 index 0000000000000000000000000000000000000000..9a5cf6c4cee888ec100c76772915de4acdcd5ac1 GIT binary patch literal 236 zcmV}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq0ReDz0000000960{}~w?8yp=TA0QzjBP1mzCnzZ@Dl054E-x@K zGBY$aHa9pqIy*Z&Jw87`K|(`BMMg(RNlHshOifNtP*GA-R8>}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq4Q4P*Td-=&{{IYG+B!&rV5#ouOE&KNZvs&^ GfFuAi#1KUQ literal 0 HcmV?d00001 diff --git a/colors/grn_dz.clr b/colors/grn_dz.clr new file mode 100644 index 0000000000000000000000000000000000000000..826170c65103c5af25c470c64f5ae2a7c9fee13f GIT binary patch literal 206 zcmZQ@;1!Ybv2^qbs^b=w(=fMo^^2Gq7@JuZ-#>fBmIY^TKKt~ar)SRU#B*0}J($1% U1ph$<1A~l3XyJbo2z$_w01a6ey8r+H literal 0 HcmV?d00001 diff --git a/colors/grn_height.clr b/colors/grn_height.clr new file mode 100644 index 0000000000000000000000000000000000000000..bf29d331e11d64aa9bd9c26cd57a0a637c421cd3 GIT binary patch literal 236 zcmZQDPMC0j!J+X`%%l_l8Gzu^$^>yG6*YBDZ5=%WLt_&&3rlNTI|nCcS9cFDA7B5# zppdZe$mp23gv8|3w2aK`+`NLK;?nYps+!vR#-^6G_Rj8}z6ld2Pn|Yn=Ipui7A#^| zx_rf|HEY*z+_Yue_MN-;>^pGq@X=!@PMtn`?!u+ZSFhi=b?5H=hmW2-d;aqEn|B{R se*XIH$FJXi!L9+h2m?3<1-ZZk1w;iK1VrvB2#By&2nhQbz{Ii909k%lV*mgE literal 0 HcmV?d00001 diff --git a/colors/grn_hh.clr b/colors/grn_hh.clr new file mode 100644 index 0000000000000000000000000000000000000000..bf29d331e11d64aa9bd9c26cd57a0a637c421cd3 GIT binary patch literal 236 zcmZQDPMC0j!J+X`%%l_l8Gzu^$^>yG6*YBDZ5=%WLt_&&3rlNTI|nCcS9cFDA7B5# zppdZe$mp23gv8|3w2aK`+`NLK;?nYps+!vR#-^6G_Rj8}z6ld2Pn|Yn=Ipui7A#^| zx_rf|HEY*z+_Yue_MN-;>^pGq@X=!@PMtn`?!u+ZSFhi=b?5H=hmW2-d;aqEn|B{R se*XIH$FJXi!L9+h2m?3<1-ZZk1w;iK1VrvB2#By&2nhQbz{Ii909k%lV*mgE literal 0 HcmV?d00001 diff --git a/colors/grn_rainfall.clr b/colors/grn_rainfall.clr new file mode 100644 index 0000000000000000000000000000000000000000..a06b95644aace0f711933c4538a3737840113b05 GIT binary patch literal 216 zcmZSh|9JO;ssHcqZDat0IdjU&{)51A5afBmIY^TKKt~ar)SRU#B*0}J($1% U1ph$<1A~l3XyJbo2z$_w01a6ey8r+H literal 0 HcmV?d00001 diff --git a/colors/grn_reflectivity1.clr b/colors/grn_reflectivity1.clr new file mode 100644 index 0000000000000000000000000000000000000000..826170c65103c5af25c470c64f5ae2a7c9fee13f GIT binary patch literal 206 zcmZQ@;1!Ybv2^qbs^b=w(=fMo^^2Gq7@JuZ-#>fBmIY^TKKt~ar)SRU#B*0}J($1% U1ph$<1A~l3XyJbo2z$_w01a6ey8r+H literal 0 HcmV?d00001 diff --git a/colors/grn_spectral_width.clr b/colors/grn_spectral_width.clr new file mode 100644 index 0000000000000000000000000000000000000000..df015b41657e2081e9139cd74c8e4d26b8b87d67 GIT binary patch literal 236 zcmV}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq0?H6*F+u literal 0 HcmV?d00001 diff --git a/colors/red_height.clr b/colors/red_height.clr new file mode 100644 index 0000000000000000000000000000000000000000..7bf8fc34fef0850f0a89b108dfd66f9d40cf0fa0 GIT binary patch literal 236 zcmZSZNtkee0Sap8?z{K@)YJqe6*YBDZ5=%WLt_&&3rlNTI|nCcS9cFDA7B5#ppdZe z$mp23gv8|3w2aK`+`NLK;?nYps+!vR#-^6G_Rj8}z6ld2Pn|Yn=Ipui7A*R|boq)^ zYu2vcxM|C_?K^kx*>~XJ;iJb+oH~8>+=WY*uU@}#>(1T#4<9{w_Wb4RH}5`t{QULX Ok6*w4{)f4WYBT_MdsAWn literal 0 HcmV?d00001 diff --git a/colors/red_hh.clr b/colors/red_hh.clr new file mode 100644 index 0000000000000000000000000000000000000000..7bf8fc34fef0850f0a89b108dfd66f9d40cf0fa0 GIT binary patch literal 236 zcmZSZNtkee0Sap8?z{K@)YJqe6*YBDZ5=%WLt_&&3rlNTI|nCcS9cFDA7B5#ppdZe z$mp23gv8|3w2aK`+`NLK;?nYps+!vR#-^6G_Rj8}z6ld2Pn|Yn=Ipui7A*R|boq)^ zYu2vcxM|C_?K^kx*>~XJ;iJb+oH~8>+=WY*uU@}#>(1T#4<9{w_Wb4RH}5`t{QULX Ok6*w4{)f4WYBT_MdsAWn literal 0 HcmV?d00001 diff --git a/colors/red_rainfall.clr b/colors/red_rainfall.clr new file mode 100644 index 0000000000000000000000000000000000000000..ec754ac96633346901812879ac7539a159e462df GIT binary patch literal 216 zcmZQ5bPZHjXMlsFM|bS_j|H3rfkqH`1qTRa8{uFgCSX9QqdE)jZV*F2l*Ivt0Y&DY ARR910 literal 0 HcmV?d00001 diff --git a/colors/red_reflectivity.clr b/colors/red_reflectivity.clr new file mode 100644 index 0000000000000000000000000000000000000000..cdcf7738ee42b52ec3a6d48fd3c229bf24267b86 GIT binary patch literal 206 zcmZQ@;1!ngwRH3hs$&EK22`K~;wtn0|Nnm*5dZ(*H*5Lk|7UJK{RHOy|8Ih-e871C D4Ko>u literal 0 HcmV?d00001 diff --git a/colors/red_reflectivity1.clr b/colors/red_reflectivity1.clr new file mode 100644 index 0000000000000000000000000000000000000000..cdcf7738ee42b52ec3a6d48fd3c229bf24267b86 GIT binary patch literal 206 zcmZQ@;1!ngwRH3hs$&EK22`K~;wtn0|Nnm*5dZ(*H*5Lk|7UJK{RHOy|8Ih-e871C D4Ko>u literal 0 HcmV?d00001 diff --git a/colors/red_spectral_width.clr b/colors/red_spectral_width.clr new file mode 100644 index 0000000000000000000000000000000000000000..7b8a19c8f863436f9ec651640364641a00dcfad2 GIT binary patch literal 236 zcmV}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq}2SXo+ITwPsWUtnQk zV`OD!XJ~0^Yiw<9Zf|gLa&vTbc6WGrdV73*et&;}fr5jCg@%WSiHeJijgF6ykdcy; zl$Dm3n3Lo_tE{cAuduPQva__cwzs&sy1Tr+zQ4f1!o$PF m#m2|T$;!*j&Cbuz(bCh@)YaD4*xB0K+}+;a;Njxq +#include +#include "rsl.h" + +extern int radar_verbose_flag; + +/*************************************************************/ +/* */ +/* RSL_free_slice */ +/* */ +/*************************************************************/ +void RSL_free_slice(Slice *slice) +{ + /* Frees memory allocated to a slice structure, and associated + pointer and data arrays. + */ + + if (slice != NULL) + { + if (slice->data != NULL) + { + if (slice->data[0] != NULL) + free(slice->data[0]); /* Free the 2D data array. */ + free(slice->data); /* Free the vector of pointers. */ + } + free(slice); /* Free the slice structure. */ + } +} + +/*************************************************************/ +/* */ +/* RSL_new_slice */ +/* */ +/*************************************************************/ +Slice *RSL_new_slice(int nrows, int ncols) +{ + /* Allocates memory for a slice structure, and associated pointer + and data arrays. + */ + Slice *s; + Slice_value *data; + int row; + + /* Allocate a slice. */ + s = (Slice *)calloc(1, sizeof(Slice)); + if (s == NULL) perror("RSL_new_slice"); + /* Allocate a vector of 'nrows' pointers. */ + s->data = (Slice_value **)calloc(nrows, sizeof(Slice_value *)); + if (s->data == NULL) perror("RSL_new_slice"); + /* Allocate a 2 dimensional array for the actual data values. */ + data = (Slice_value *)calloc(nrows*ncols, sizeof(Slice_value)); + if (data == NULL) perror("RSL_new_slice"); + /* Fill all the 'nrows' pointer slots created above. */ + for (row=0; rowdata[row] = data + row*ncols; + + return(s); +} + +/*************************************************************/ +/* */ +/* RSL_new_cube */ +/* */ +/*************************************************************/ +Cube *RSL_new_cube(int ncarpi) +{ + /* Allocate memory for a cube structure, and an associated array + of carpi pointers. + */ + Cube *cube; + + cube = (Cube *) calloc(1, sizeof(Cube)); + if (cube == NULL) return(NULL); + cube->carpi = (Carpi **) calloc(ncarpi, sizeof(Carpi *)); + if (cube->carpi == NULL) return(NULL); + return(cube); +} + +/*************************************************************/ +/* */ +/* RSL_free_cube */ +/* */ +/*************************************************************/ +void RSL_free_cube(Cube *cube) +{ + /* Frees memory allocated to a cube structure and associated + carpi structures. + */ + int j; + + if (cube != NULL) + { + if (cube->carpi != NULL) + { + for (j=0; jnz; j++) + if (cube->carpi[j] != NULL) + RSL_free_carpi(cube->carpi[j]); + free(cube->carpi); + } + free(cube); + } +} + +/*************************************************************/ +/* */ +/* RSL_volume_to_cube */ +/* */ +/*************************************************************/ +Cube *RSL_volume_to_cube(Volume *v, float dx, float dy, float dz, + int nx, int ny, int nz, float grnd_r, + int radar_x, int radar_y, int radar_z) +/* radar_z = 0 is the only thing that makes sense. Why pass it? */ +{ + float lat=0; + float lon=0; + int i; + Cube *cube; + + if (v == NULL) return NULL; + /* check validity of radar site coordinates in cube. */ + if (radar_z != 0) return NULL; + if ((radar_x < 0) || (radar_x > nx)) return NULL; + if ((radar_y < 0) || (radar_y > ny)) return NULL; + + cube = (Cube *)RSL_new_cube(nz); + if (cube == NULL) return NULL; + + cube->nx = nx; + cube->ny = ny; + cube->nz = nz; + cube->dx = dx; + cube->dy = dy; + cube->dz = dz; + if (v->h.type_str != (char *) NULL) + cube->data_type = (char *)strdup(v->h.type_str); + cube->lat = lat; + cube->lon = lon; + + /* Create nz carpis */ + for (i=0; icarpi[i] = (Carpi *)RSL_volume_to_carpi(v, (i+1)*dz, grnd_r, + dx, dy, nx, ny, + radar_x, radar_y, + lat, lon); + return cube; +} + +/*************************************************************/ +/* */ +/* RSL_get_slice_from_cube */ +/* */ +/*************************************************************/ +Slice *RSL_get_slice_from_cube(Cube *cube, int x, int y, int z) +/* + Check validity of parameters x,y,z , which define the plane of the + required slice. Two of the three parameters must equal -1 and the + third must be nonnegative; eg, the vertical plane y=100 is + specified by the parameters x=-1, y=100, z=-1 + + Assumes valid ranges for x, y, z are: + 0 <= x <= nx-1 , 0 <= y <= ny-1 , 1 <= z <= nz + The range of z starts at 1 , since a cappi (or carpi) at + height z=0 makes no sense. +*/ +{ + int i, j; + Slice *slice; + + if (cube == NULL) return(NULL); + + /* Slice defined by the plane y = const */ + if ((x == -1) && (z == -1) && (y > -1) && (y < cube->ny)) + { + slice = (Slice *) RSL_new_slice(cube->nz, cube->nx); + slice->data_type = (char *)strdup(cube->data_type); + slice->dx = cube->dx; + slice->dy = cube->dz; + slice->nx = cube->nx; + slice->ny = cube->nz; + slice->f = cube->carpi[0]->f; + slice->invf = cube->carpi[0]->invf; + /* Retrieve the required data values from the cube and place into + the slice structure. */ + for (j=0; jnz; j++) + for (i=0; inx; i++) + slice->data[j][i] = (Slice_value) cube->carpi[j]->data[y][i]; + } + + + /* Slice defined by the plane x = const */ + else if ((y == -1) && (z == -1) && (x > -1) && (x < cube->nx)) + { + slice = (Slice *) RSL_new_slice(cube->nz, cube->ny); + slice->data_type = (char *)strdup(cube->data_type); + slice->dx = cube->dy; + slice->dy = cube->dz; + slice->nx = cube->ny; + slice->ny = cube->nz; + slice->f = cube->carpi[0]->f; + slice->invf = cube->carpi[0]->invf; + /* Retrieve the required data values from the cube and place into + the slice structure. */ + for (j=0; jnz; j++) + for (i=0; iny; i++) + slice->data[j][i] = (Slice_value) cube->carpi[j]->data[i][x]; + } + + + /* Want slice defined by the plane z = const ; ie, a carpi */ + else if ((x == -1) && (y == -1) && (z > 0) && (z <= cube->nz)) + { + slice = (Slice *) RSL_new_slice(cube->ny, cube->nx); + slice->data_type = (char *)strdup(cube->data_type); + slice->dx = cube->dx; + slice->dy = cube->dy; + slice->nx = cube->nx; + slice->ny = cube->ny; + slice->f = cube->carpi[z-1]->f; + slice->invf = cube->carpi[z-1]->invf; + /* Just copy carpi data values into slice structure. */ + for (j=0; jny; j++) + for (i=0; inx; i++) + slice->data[j][i] = (Slice_value) cube->carpi[z-1]->data[j][i]; + } + + + else /* Invalid parameters. */ + { + if (radar_verbose_flag) + { + fprintf(stderr,"\nRSL_get_slice_from_cube(): passed invalid parameters\n"); + fprintf(stderr,"nx:%d ny:%d nz:%d x:%d y:%d z:%d\n",cube->nx, + cube->ny,cube->nz,x,y,z); + } + return(NULL); + } + + return(slice); +} diff --git a/doc/Example_RSL_copy.html b/doc/Example_RSL_copy.html new file mode 100644 index 0000000..94736ff --- /dev/null +++ b/doc/Example_RSL_copy.html @@ -0,0 +1,31 @@ + + + + + +
+ + +
#include "rsl.h"
+
+main()
+{
+Radar *radar;
+Volume *dz_copy;
+Sweep *s1_copy;
+Ray r33_copy;
+
+radar = RSL_wsr88d_to_radar("nex.file.2", "KMLB");
+
+/* Copy of Volume for DZ. */
+dz_copy = RSL_copy_volume(radar->v[DZ_INDEX]);
+
+/* Copy of Sweep 1. */
+s1_copy = RSL_copy_sweep(dz_copy->sweep[0]);
+
+/* Copy of Ray 33. */
+r33_copy = RSL_copy_ray(s1_copy->ray[32]);
+}
+
+ + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..6acc059 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,12 @@ +AUTOMAKE_OPTIONS = foreign + +docdir = $(prefix)/doc/$(PACKAGE) +doc_DATA = *.html *.gif *.jpg + +EXTRA_DIST = $(doc_DATA) *.fig + +install-exec-hook: + -mkdir $(prefix)/doc + -mkdir $(docdir) + $(INSTALL) -m 444 ../README $(docdir) + $(INSTALL) -m 444 ../CHANGES $(docdir) diff --git a/doc/RSL_Er_loc_struct.html b/doc/RSL_Er_loc_struct.html new file mode 100644 index 0000000..f62bfe3 --- /dev/null +++ b/doc/RSL_Er_loc_struct.html @@ -0,0 +1,16 @@ + + + + + +
+ + +
typedef struct 
+{ 
+float elev; /* elevation angle */
+float srange; /* slant range !!! */
+} 
+Er_loc;
+
+ diff --git a/doc/RSL_add_dbz_offset.html b/doc/RSL_add_dbz_offset.html new file mode 100644 index 0000000..813bb41 --- /dev/null +++ b/doc/RSL_add_dbz_offset.html @@ -0,0 +1,43 @@ + + + + + + +  +
+

+RSL_add_dbz_offset...

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_add_dbz_offset_to_ray(Ray *r, float dbz_offset);  +
void RSL_add_dbz_offset_to_sweep(Sweep *s, float dbz_offset);  +
void RSL_add_dbz_offset_to_volume(Volume *v, float dbz_offset);  + +
+

+Description

+ +RSL_add_dbz_offset_to_ray Adds a calibration factor 'dbz_offset' to a ray's range bins +containing valid values. Valid values are those other than NOECHO.  +
+
+ RSL_add_dbz_offset_to_sweep Calls RSL_add_dbz_offset_to_ray for each ray in the sweep.  +
+
+ RSL_add_dbz_offset_to_volume Calls RSL_add_dbz_offset_to_sweep for each sweep in the volume.  +
+
+

+Return value

+None. +
+
+
+ +

Author: Mike Kolander. + + diff --git a/doc/RSL_allocate_histogram.html b/doc/RSL_allocate_histogram.html new file mode 100644 index 0000000..4748290 --- /dev/null +++ b/doc/RSL_allocate_histogram.html @@ -0,0 +1,25 @@ + + + + + +


+ + +

RSL_allocate_histogram

+ +
+ +

Synopsis

+#include "rsl.h"
+Histogram *RSL_allocate_histogram(int low, int hi);
+
+ +

Description

+Allocate space for the structure Histogram. low and hi specify the low and high dBZ bin values. The bin spacing is 1 dBZ. +
+ +

Return value

+Upon successful completion, Vallocate_histogram returns a pointer to the structure Histogram. Otherwise, NULL is returned and errno is set. +
Author: David B. Wolff + diff --git a/doc/RSL_anyformat_to_radar.html b/doc/RSL_anyformat_to_radar.html new file mode 100644 index 0000000..880f339 --- /dev/null +++ b/doc/RSL_anyformat_to_radar.html @@ -0,0 +1,87 @@ + + + + + + Title + + + + +rsl.gif +
+
+

+RSL_anyformat_to_radar

+ +
+

+Synopsis

+#include "rsl.h" +
Radar *RSL_anyformat_to_radar(char +*infile [, char *callid_or_first_file]); +
+
+

+Description

+Reads radar input files. The format of the input file is automatically +determined by using magic numbers. The input file may be compressed (with +old unix compress or GNU gzip) and the magic numbers are +obtained by passing the data through the GNU gzip decompression +filter. Magic numbers are standard for the following file formats and, +thus, are recognized by RSL_anyformat_to_radar: +
  +

WSR-88D (NEXRAD) +

HDF (TSDIS format) +

LASSEN (version 1.3 and version 1.4 files) +

Universal Format (UF) +

NSIG (SIGMET version 1 and version 2 raw product files) +

MCGILL +

RSL output format +

RAPIC (Berrimah Austrailia) +

RADTEC (SPANDAR, requires PKWARE compression tools) +

EDGE +

DORADE +

For TOGA and KWAJALEIN files, there is no standard magic information +available. It may not be possible for RSL_anyformat_to_radar to recognize +them. The optional second argument is valid for reading wsr88d files. See +RSL_wsr88d_to_radar. +Once the file type is determined, the appropriate ingest routine is called. +

In order to reduce the memory requirements during ingest, you can call +RSL_select_fields +to specify the field types. For instance, you can select to read only DZ +from the input file. The input file may contain other fields, but, they +will be ignored. +

PKWARE compression tools are required for the RADTEC module.  The +data has been +
compressed with implode and must be uncompressed with explode +. +
+


+

+Return value

+Upon successful completion, RSL_anyformat_to_radar returns a pointer to +the structure Radar. Otherwise, NULL is returned. +
+
+

+See also

+RSL_wsr88d_to_radar, RSL_lassen_to_radar +, +RSL_read_radar, +RSL_uf_to_radar +, +RSL_toga_to_radar, +RSL_nsig_to_radar +, +RSL_nsig2_to_radar, +RSL_mcgill_to_radar +RSL_kwaj_to_radar, +RSL_rapic_to_radar +, +RSL_radtec_to_radar. +
+
+

Author: John H. Merritt. + + diff --git a/doc/RSL_area_of_ray.html b/doc/RSL_area_of_ray.html new file mode 100644 index 0000000..9946085 --- /dev/null +++ b/doc/RSL_area_of_ray.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_area_of_ray

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_area_of_ray(Ray *r, float lo, float hi, float min_range, float max_range); + +

+
Description

+Compute the volumetric area of a sweep given a range of dBZ, a minimum range and a maximum range in km. Ranges are specified in km. lo and hi are the minimum and maximum dBZ values within which the fractional area is computed. The name of this routine is unfortunately misleading. The area is really a volume. The total volume for pixels present within the range of lo to hi is computed and returned. This routine is used by the routine RSL_fractional_area_of_sweep. +
+ +

Return value

+Upon successful completion, a valid floating point number is returned. +
+ +

See also

+RSL_fractional_area_of_sweep +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_azimuth_hash_struct.html b/doc/RSL_azimuth_hash_struct.html new file mode 100644 index 0000000..c945b18 --- /dev/null +++ b/doc/RSL_azimuth_hash_struct.html @@ -0,0 +1,13 @@ + + + + + +


+ + +
typedef struct _azimuth_hash {
+  Ray *ray;
+  struct _azimuth_hash *next,*ray_high,*ray_low;
+} Azimuth_hash;
+ diff --git a/doc/RSL_bscan.html b/doc/RSL_bscan.html new file mode 100644 index 0000000..4c98b6a --- /dev/null +++ b/doc/RSL_bscan.html @@ -0,0 +1,35 @@ + + + + + +
+ + +

RSL_bscan_...

+ +
+ +

Synopsis

+#include "rsl.h"
+void RSL_bscan_ray(Ray *r, FILE *fp);
+void RSL_bscan_sweep(
Sweep *s, char *outfile);
+void RSL_bscan_volume(
Volume *v, char *basename); + +

+
Description

+Output image format is PPM. If basename is "bscan", RSL_bscan_volume outputs filenames bscan.01.gif, bscan.02.gif, etc. as PPM images. These are simple ray dumps; aka, B-SCANS. The output file is specified as the outfile parameter to RSL_bscan_sweep. These routines assume the color table has been loaded, otherwise you will get a black image. The output image dimensions are nbins by nrays which are determined from sweep and first-ray-of-the-sweep header information. +
+ +

Return value

+None. +
+ +

See also

+RSL_sweep_to_gif, RSL_sweep_to_pict, RSL_sweep_to_pgm, RSL_sweep_to_ppm,
+RSL_load_color_table, RSL_load_green_table, RSL_load_red_table, RSL_load_blue_table,
+RSL_load_refl_color_table, RSL_load_sw_color_table, RSL_load_vel_color_table +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_cappi_at_h.html b/doc/RSL_cappi_at_h.html new file mode 100644 index 0000000..3156f63 --- /dev/null +++ b/doc/RSL_cappi_at_h.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_cappi_at_h

+ +
+ +

Synopsis

+#include "rsl.h"
+Cappi *RSL_cappi_at_h(Volume *v, float h, float max_range); + +

+
Description

+Produce a Constant Altitude PPI at h out to the maximum ground range max_range. h and max_range are expressed in km. Memory is allocated using the system calloc routine. A Sweep structure is used to store the data of the cappi. Thus, it is easy to make images by using RSL_sweep_to_gif. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+RSL_free_cappi, RSL_cappi_to_carpi. + +

+


Author: John H. Merritt + diff --git a/doc/RSL_cappi_struct.html b/doc/RSL_cappi_struct.html new file mode 100644 index 0000000..5b44c01 --- /dev/null +++ b/doc/RSL_cappi_struct.html @@ -0,0 +1,26 @@ + + + + + +
+ + +
typedef struct {
+  int   month;  /* Begin time for this Cappi; month (1-12). */
+  int   day;    /* Begin time for this Cappi; day (1-31). */
+  int   year;   /* Begin time for this Cappi; year (eg. 1993). */
+  int   hour;   /* Begin date for this Cappi; hour (0-23). */
+  int   minute; /* Begin date for this Cappi; minute (0-59).*/
+  float sec;    /* Begin date for this Cappi; second + fraction of  second. */ 
+  float height;      /* Height for this Cappi. */
+  float lat;
+  float lon;         /* Lat/lon of lower left corner of Carpi. */
+  int field_type;
+  char radar_type[50]; /* Value of Constant radar->h.radar_type */ 
+  int interp_method; /* ??? string describing interpolation method. */
+  Er_loc *loc;       /* elevation and range coordinate array */
+  Sweep *sweep;      /* Pointers to rays of data */
+} Cappi; 
+ + diff --git a/doc/RSL_cappi_to_carpi.html b/doc/RSL_cappi_to_carpi.html new file mode 100644 index 0000000..65859be --- /dev/null +++ b/doc/RSL_cappi_to_carpi.html @@ -0,0 +1,31 @@ + + + + + +
+ + +

RSL_cappi_to_carpi

+ +
+ +

Synopsis

+#include "rsl.h"
+Carpi *RSL_cappi_to_carpi(Cappi *cappi, float dx, float dy, float lat, float lon, int nx, int ny, int radar_x, int radar _y); + +

+
Description

+Produce a Constant Altitude Rectangular from Polar Image at h out to the maximum ground range grnd_range. h and grnd_range are expressed in km. The dimensions of the Carpi are given by nx and ny. radar_x and radar_y are the location of the radar within the Carpi structure (the rectangular grid). lat and lon represent the lower left corner (SE) of the rectangular grid. The routine allocates space for the resulting Carpi. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+RSL_free_cappi, RSL_volume_to_carpi, Carpi, Cappi, RSL_new_cappi. + +

+


Author: Mike Kolander + diff --git a/doc/RSL_carpi_struct.html b/doc/RSL_carpi_struct.html new file mode 100644 index 0000000..aa2b388 --- /dev/null +++ b/doc/RSL_carpi_struct.html @@ -0,0 +1,29 @@ + + + + + +
+ + +
typedef struct {
+  int   month;            /* (1-12). */
+  int   day;              /* (1-31).   */
+  int   year;             /* (eg. 1993). */
+  int   hour;             /* (0-23). */
+  int   minute;           /* (0-59).*/
+  float sec;              /* second + fraction of second. */
+  float dx, dy;           /* Size of cell in km. */
+  int   nx, ny;           /* Number of cells. */
+  int   radar_x, radar_y; /* Location of center of radar. */
+  float height;           /* Height of this Carpi. */
+  float lat, lon;         /* Lat/lon of lower left corner of Carpi. */
+  char  radar_type[50];   /* Radar types. */
+  int   field_type;       /* Same as for Radar. */
+  int   interp_method;    /* ??? string describing interpolation method. */
+  float (*f)(Carpi_value x);    /* Data conversion function. f(x). */
+  Carpi_value (*invf)(float x); /* Data conversion function. invf(x). */
+  Carpi_value **data;     /* data[ny][nx] */
+} Carpi; 
+ + diff --git a/doc/RSL_carpi_value.html b/doc/RSL_carpi_value.html new file mode 100644 index 0000000..6b83837 --- /dev/null +++ b/doc/RSL_carpi_value.html @@ -0,0 +1,8 @@ + + + + +t +
+ypedef Range Carpi_value;
+ diff --git a/doc/RSL_carpi_value_struct.html b/doc/RSL_carpi_value_struct.html new file mode 100644 index 0000000..6b83837 --- /dev/null +++ b/doc/RSL_carpi_value_struct.html @@ -0,0 +1,8 @@ + + + + +t +
+ypedef Range Carpi_value;
+ diff --git a/doc/RSL_clear.html b/doc/RSL_clear.html new file mode 100644 index 0000000..ab8e55d --- /dev/null +++ b/doc/RSL_clear.html @@ -0,0 +1,34 @@ + + + + + +
+ + +

RSL_clear_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_clear_ray(Ray *r);
+Sweep *RSL_clear_sweep(Sweep *s);
+Volume *RSL_clear_volume(Volume *v);
+ +

+
Description

+RSL_clear_volume calls RSL_clear_sweep for the number of sweeps. RSL_clear_sweep calls RSL_clear_ray for the number of rays. And RSL_clear_ray clears the array of Range of size nbins. All header information is preserved. This may or may not be a desired capability. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. +
+ +

See also

+Example
+RSL_free_volume, RSL_free_sweep, RSL_free_ray +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_color_table.html b/doc/RSL_color_table.html new file mode 100644 index 0000000..040089d --- /dev/null +++ b/doc/RSL_color_table.html @@ -0,0 +1,77 @@ + + + + + + + + +


+

+RSL_get_color_table
+RSL_set_color_table

+ +

+ +

+ +

+Synopsis

+#include "rsl.h" +
void RSL_get_color_table(int icolor, char buffer[256], int *ncolors) +
void RSL_set_color_table(int icolor, char buffer[256], int ncolors) +

+ +
Description

+RSL_get_color_table: Given a color table index, one of RSL_RED_TABLE, +RSL_GREEN_TABLE or RSL_BLUE_TABLE, return up to 256 color +indexes each containing the color intensity for that color at each index.  +The number of colors in the table is indicated in *ncolors. +

RSL_set_color_table: Given a color table index icolor, one of +RSL_RED_TABLE, RSL_GREEN_TABLE or RSL_BLUE_TABLE,  +and a character buffer, at most 256 color indexes long, and the number +of indexes in the character buffer, set the color table.  Each color +index in buffer contains the color intensity for that color.  +Range of color intensities is 0 to 255. +

You must make three calls to both the get and set functions to change +the entire color table entry for a particular index.  For example, +to change the 5th index of the color table to cyan (Red=0, Green=255, +Blue=255), perform the following (provided a color table is already loaded): +

char r[256], g[256], b[256]; +
RSL_get_color_table(RSL_RED_TABLE,   r, &ncolors); +
RSL_get_color_table(RSL_GREEN_TABLE, g, &ncolors); +
RSL_get_color_table(RSL_BLUE_TABLE,  b, &ncolors); +

r[4] = (char)0;    /* [4] is the 5-th index */ +
g[4] = (char)255; +
b[4] = (char)255; +

RSL_set_color_table(RSL_RED_TABLE,   r, ncolors); +
RSL_set_color_table(RSL_GREEN_TABLE, g, ncolors); +
RSL_set_color_table(RSL_BLUE_TABLE,  b, ncolors); +
  +
  +

+


+

+Return value

+None.  +
+

+See also

+RSL_rebin_velocity_ray, RSL_rebin_velocity_sweep, +RSL_rebin_velocity_volume, +
RSL_sweep_to_gif, RSL_sweep_to_pict, +Vsweep_to_pgm, +Vsweep_to_ppm, +
RSL_load_color_table, RSL_load_green_table, +RSL_load_red_table, +RSL_load_blue_table, +
RSL_load_refl_color_table, +RSL_load_sw_color_table, +RSL_load_vel_color_table, +
RSL_volume_to_gif, RSL_volume_to_pict, +RSL_volume_to_pgm, +RSL_volume_to_ppm.  +
+

Author: John H. Merritt + + diff --git a/doc/RSL_copy.html b/doc/RSL_copy.html new file mode 100644 index 0000000..7a182a8 --- /dev/null +++ b/doc/RSL_copy.html @@ -0,0 +1,34 @@ + + + + + +


+ + +

RSL_copy_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_copy_ray(Ray *r);
+Sweep *RSL_copy_sweep(Sweep *s);
+Volume *RSL_copy_volume(Volume *v);
+ +

+
Description

+RSL_copy_volume calls RSL_copy_sweep for the number of sweeps. RSL_copy_sweep calls RSL_copy_ray for the number of rays. And RSL_copy_ray copies the array of Range of size nbins. All header information is preserved. This may or may not be a desired capability. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. +
+ +

See also

+Example
+RSL_free_volume, RSL_free_sweep, RSL_free_ray +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_copyright.html b/doc/RSL_copyright.html new file mode 100644 index 0000000..6d0d85a --- /dev/null +++ b/doc/RSL_copyright.html @@ -0,0 +1,36 @@ + + + + + + + + +

  
+
+
+
+ +    NASA/TRMM, Code 910.1. +    This is the TRMM Office Radar Software Library. +    Copyright (C) 1996-1999 +            John H. Merritt +            Space Applications Corporation +            Vienna, Virginia + +    This library is free software; you can redistribute it and/or +    modify it under the terms of the GNU Library General Public +    License as published by the Free Software Foundation; either +    version 2 of the License, or (at your option) any later version. + +    This library is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +    Library General Public License for more details. + +    You should have received a copy of the GNU Library General Public +    License along with this library; if not, write to the Free +    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ + + diff --git a/doc/RSL_cube_struct.html b/doc/RSL_cube_struct.html new file mode 100644 index 0000000..13668bd --- /dev/null +++ b/doc/RSL_cube_struct.html @@ -0,0 +1,19 @@ + + + + + +
+ + +
typedef struct
+   {
+   float lat, lon;
+   float dx, dy, dz;
+   int nx, ny, nz;
+   char *data_type;
+   Carpi **carpi;
+   }
+Cube; 
+ + diff --git a/doc/RSL_edge_to_radar.html b/doc/RSL_edge_to_radar.html new file mode 100644 index 0000000..9441cbe --- /dev/null +++ b/doc/RSL_edge_to_radar.html @@ -0,0 +1,48 @@ + + + + + + + + +
+

+RSL_edge_to_radar

+ +
+

+Synopsis

+#include "rsl.h" +
Radar *RSL_edge_to_radar(char +*infile); +
+

+Description

+Reads the EDGE format and returns a pointer to the structure +Radar. +The input file is specified by the string infile. If infile +is NULL, then stdin is read. The input file may be compressed. If the data +is compressed, it is passed through the GNU gunzip filter. Thus, +compressed data can be any format that gzip understands.  However, +the EDGE format uses the lzw compression and requires a supporting +library to decode the file.  The supporting library is called ETOR +and is distributed separately, since it is not free software.  Contact +Enterprise Electronics Corporation to obtain the ETOR library that decodes +the EDGE format. +

 Enterprise  Electronics  Corporation, Enterprise,  +Alabama,  USA  36330 (334) 347-3478. +
+


+

+Return value

+Upon successful completion, RSL_edge_to_radar returns a pointer to the +structure Radar. Otherwise, NULL is returned and errno is set.  +
+

+See also

+RSL_anyformat_to_radar  +
+

Author:  Don Burrows @ Enterprise Electronics Corporation + + diff --git a/doc/RSL_enum_sorted_type.html b/doc/RSL_enum_sorted_type.html new file mode 100644 index 0000000..21a18e6 --- /dev/null +++ b/doc/RSL_enum_sorted_type.html @@ -0,0 +1,10 @@ + + + + + +


+ + +
enum Sorted_type { NOT_SORTED, SORTED_BY_ANGLE, SORTED_BY_TIME};
+ diff --git a/doc/RSL_fill_cappi.html b/doc/RSL_fill_cappi.html new file mode 100644 index 0000000..b27b10c --- /dev/null +++ b/doc/RSL_fill_cappi.html @@ -0,0 +1,31 @@ + + + + + +
+ + +

RSL_fill_cappi

+ +
+ +

Synopsis

+#include "rsl.h"
+int *RSL_fill_cappi(Volume *v, Cappi *cap, int method); + +

+
Description

+Using data from v, and information from cap, this routine fill the cappi structure cap with values from the rays in v. The argument cap is modified. The method passed indicates the interpolation used, however, no interpolation is used, yet. Normally, you should not call this routine unless you're writing an RSL routine, instead, call RSL_cappi_at_h. +
+ +

Return value

+Upon successful completion, 1 is returned. -1 is returned upon failure. The argument cap is modified. +
+ +

See also

+RSL_free_cappi, RSL_cappi_to_carpi, RSL_get_value_from_cappi, RSL_new_cappi + +

+


Author: John H. Merritt + diff --git a/doc/RSL_find_rng_azm.html b/doc/RSL_find_rng_azm.html new file mode 100644 index 0000000..dc026b2 --- /dev/null +++ b/doc/RSL_find_rng_azm.html @@ -0,0 +1,28 @@ + + + + + +
+ + +

RSL_find_rng_azm

+
+ +

Synopsis

+#include "rsl.h"
+void RSL_find_rng_azm(float *r, float *ang, float x, float y); + +

+
Description

+Convert Cartesian coords (x, y) to polar (rng,angle); 0<angle<360. +
+ +

Return value

+None. +
+ +

See also

+ +
Author: Mike Kolander + diff --git a/doc/RSL_fix_time.html b/doc/RSL_fix_time.html new file mode 100644 index 0000000..8defa7c --- /dev/null +++ b/doc/RSL_fix_time.html @@ -0,0 +1,39 @@ + + + + + + +  +
+

+RSL_fix_time

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_fix_time(Ray *ray);  +
+

+Description

+Fixes possible overflow values in month, day, year, +hh, mm, ss.  Normally, ss should be the +overflow.  This code ensures end of  month, year +and century are handled correctly by using the Unix time(2) functions. +
+
+

+Return value

+None. +
+
+

+See also

+mktime(3) +
+
+ +

Author: John H. Merritt. + + diff --git a/doc/RSL_fraction_of.html b/doc/RSL_fraction_of.html new file mode 100644 index 0000000..ce5b4e2 --- /dev/null +++ b/doc/RSL_fraction_of.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_fraction_of...

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_fraction_of_ray(Ray *r, float lo, float hi, float range);
+float RSL_fraction_of_sweep(Sweep *s, float lo, float hi, float range);
+float RSL_fraction_of_volume(Volume *v, float lo, float hi, float range);
+ +

+
Description

+Compute the fraction of the Volume, Sweep, or Ray that contain values between lo and hi out to the range range. This is just a percentage. +
+ +

Return value

+Upon successful completion, a valid floating point number is returned. +
+ +

See also

+ +
Author: John H. Merritt + diff --git a/doc/RSL_fractional_area_of_sweep.html b/doc/RSL_fractional_area_of_sweep.html new file mode 100644 index 0000000..7a28d45 --- /dev/null +++ b/doc/RSL_fractional_area_of_sweep.html @@ -0,0 +1,31 @@ + + + + + +
+ + +

RSL_fractional_area_of_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_fractional_area_of_sweep(Sweep *s, float lo, float hi, float min_rng, float max_rng); + +

+
Description

+Computes the fractional area, of dBz values, between lo and hi, from min_rng to max_rng. This is the fractional area of the 360 degrees. The algorithm used is to compute conic volumes based on beam width and range of the pixels. The routine RSL_area_of_ray computes these volumes. The name of that routine is unfortunate. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, NULL is returned. +
+ +

See also

+RSL_area_of_ray, RSL_fraction_of_sweep. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_free.html b/doc/RSL_free.html new file mode 100644 index 0000000..49b732c --- /dev/null +++ b/doc/RSL_free.html @@ -0,0 +1,33 @@ + + + + + +


+ + +

RSL_free_...

+ +
+ +

Synopsis

+#include "rsl.h"
+void RSL_free_ray(Ray *r);
+void RSL_free_sweep(Sweep *s);
+void RSL_free_volume(Volume *v);
+ +

+
Description

+RSL_free_volume calls RSL_free_sweep for the number of sweeps, then frees the array of Sweep pointers, then frees itself. RSL_free_sweep calls RSL_free_ray for the number of rays, then frees the array of Ray pointers, then frees itself. Finally, RSL_free_ray frees the array of Range, then frees itself. Checks are made that non NULL pointers are freed. +
+ +

Return value

+None. +
+ +

See also

+RSL_clear_volume, RSL_clear_sweep, RSL_clear_ray. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_free_cappi.html b/doc/RSL_free_cappi.html new file mode 100644 index 0000000..a2de9b5 --- /dev/null +++ b/doc/RSL_free_cappi.html @@ -0,0 +1,40 @@ + + + + + + + + +

+


RSL_free_cappi +

+ +

Synopsis

+ +

#include "rsl.h"
+void RSL_free_cappi(Cappi *c); +

+ +

+
Description

+ +

Free the data structure Cappi, previously allocated via RSL_new_cappi, +from memory. +


+ +

Return value

+ +

None. +


+ +

See also

+ +

RSL_new_cappi, RSL_cappi_to_carpi. + +


+ +

Author: John H. Merritt

+ + + diff --git a/doc/RSL_free_histogram.html b/doc/RSL_free_histogram.html new file mode 100644 index 0000000..2f87c06 --- /dev/null +++ b/doc/RSL_free_histogram.html @@ -0,0 +1,26 @@ + + + + + +
+ + +

RSL_free_histogram

+ +

+


+ +

Synopsis

+#include "rsl.h"
+void RSL_free_histogram(Histogram *histogram);
+
+ +

Description

+Deallocate the structure pointed to by histogram. Space for the structure Histogram was previously obtained via RSL_allocate_histogram. +
+ +

Return value

+None. +
Author: David B. Wolff + diff --git a/doc/RSL_free_radar.html b/doc/RSL_free_radar.html new file mode 100644 index 0000000..d2526a9 --- /dev/null +++ b/doc/RSL_free_radar.html @@ -0,0 +1,30 @@ + + + + + +
+ + +

RSL_free_radar

+
+ +

Synopsis

+#include "rsl.h"
+void RSL_free_radar(Radar *r); + +

+
Description

+Frees the space allocated to the Radar structure radar. It frees all substructures, Volume, Sweep, Ray, Range, by calling RSL_free_volume, RSL_free_sweep, RSL_free_ray respectively. +
+ +

Return value

+None. +
+ +

See also

+ +
RSL_free_volume, RSL_free_sweep, RSL_free_ray + +

Author: John H. Merritt + diff --git a/doc/RSL_get_closest_ray_from_sweep.html b/doc/RSL_get_closest_ray_from_sweep.html new file mode 100644 index 0000000..5c2656d --- /dev/null +++ b/doc/RSL_get_closest_ray_from_sweep.html @@ -0,0 +1,32 @@ + + + + + +


+ + +

RSL_get_closest_ray_from_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_get_closest_ray_from_sweep(Sweep *s,float ray_angle,float limit); + +

+
Description

+Return the closest ray within a sweep. Closeness is determined by the minimum absolute difference of ray_angle and the azimuth angle of the ray. The difference must be less than limit. If no such ray can be found, return NULL. +
+ +

Return value

+Upon successful completion, a pointer to the Ray structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_ray, RSL_get_ray_from_sweep, RSL_get_ray_above, RSL_get_ray_below, RSL_get_first_ray_of_sweep, RSL_get_first_ray_of_volume. +
+ +

Author: Dennis Flanigan Jr. + + diff --git a/doc/RSL_get_closest_sweep.html b/doc/RSL_get_closest_sweep.html new file mode 100644 index 0000000..a6c0170 --- /dev/null +++ b/doc/RSL_get_closest_sweep.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_get_closest_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+Sweep *RSL_get_closest_sweep(Volume *v,float sweep_angle,float limit); + +

+
Description

+Return the closest sweep within a volume. Closeness is determined by the minimum absolute difference of sweep_angle and the elevation angle of the ray. The difference must be less than limit. If no such ray can be found, return NULL. +
+ +

Return value

+Upon successful completion, a pointer to the Sweep structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_sweep +
+ +

Author: Dennis Flanigan Jr. + diff --git a/doc/RSL_get_first_ray_of.html b/doc/RSL_get_first_ray_of.html new file mode 100644 index 0000000..045cc49 --- /dev/null +++ b/doc/RSL_get_first_ray_of.html @@ -0,0 +1,32 @@ + + + + + +


+ + +

RSL_get_first_ray_of_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_get_first_ray_of_sweep(Sweep *s);
+Ray *RSL_get_first_ray_of_volume(Volume *v); + +

+
Description

+RSL_get_first_ray_of_sweep returns a pointer to the first ray pointer in the Sweep structure *s, if one exist. Otherwise NULL is returned. Similiarly, for RSL_get_first_ray_of_volume; it finds the first sweep and returns the first ray of that sweep. +
+ +

Return value

+Upon successful completion, a pointer to the Ray structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_first_sweep_of_volume +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_first_sweep_of_volume.html b/doc/RSL_get_first_sweep_of_volume.html new file mode 100644 index 0000000..a4db680 --- /dev/null +++ b/doc/RSL_get_first_sweep_of_volume.html @@ -0,0 +1,32 @@ + + + + + +


+ + +

RSL_get_first_sweep_of_volume

+ +
+ +

Synopsis

+#include "rsl.h"
+Sweep *RSL_get_first_sweep_of_volume(Volume *v); + +

+
Description

+RSL_get_first_sweep_of_volume returns a pointer to the first sweep pointer in the Volume structure *v, if one exist. Otherwise NULL is returned. +
+ +

Return value

+Upon successful completion, a pointer to the Sweep structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_first_ray_of_sweep
+RSL_get_first_ray_of_volume +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_gr_slantr_h.html b/doc/RSL_get_gr_slantr_h.html new file mode 100644 index 0000000..a65b3b6 --- /dev/null +++ b/doc/RSL_get_gr_slantr_h.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_get_gr_slantr_h

+ +
+ +

Synopsis

+#include "rsl.h"
+void RSL_get_gr_slantr_h(Ray *ray, int i, float *gr, float *slantr, float *h) + +

+
Description

+Given a Ray ray and the range index i, calculate the ground range, slant range, and height; gr, slantr and h respectively. +
+ +

Return value

+None. +
+ +

See also

+RSL_get_groundr_and_h +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_groundr_and_h.html b/doc/RSL_get_groundr_and_h.html new file mode 100644 index 0000000..e557253 --- /dev/null +++ b/doc/RSL_get_groundr_and_h.html @@ -0,0 +1,30 @@ + + + + + +


+ + +

RSL_get_groundr_and_h

+
+ +

Synopsis

+#include "rsl.h"
+void RSL_get_groundr_and_h(float slant_r, float elev, float *gr, float *h); + +

+
Description

+Given slant range, slant_r, and the elevation angle, elev, compute the ground range, gr, and height, h. Range and height units are in km. Angles are in degrees. This is the inverse fuction of RSL_get_slantr_and_elev. +
+ +

Return value

+None. +
+ +

See also

+RSL_get_slantr_and_elev, RSL_get_slantr_and_h +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_histogram_from.html b/doc/RSL_get_histogram_from.html new file mode 100644 index 0000000..0dc9f1f --- /dev/null +++ b/doc/RSL_get_histogram_from.html @@ -0,0 +1,33 @@ + + + + + +


+ + +

RSL_get_histogram_from_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Histogram *RSL_get_histogram_from_ray(Ray *ray, Histogram *histogram, int low, int hi, int min_range, int max_range);
+Histogram *RSL_get_histogram_from_sweep(Sweep *sweep, Histogram *histogram, int low, int hi, int min_range, int max_range);
+Histogram *RSL_get_histogram_from_volume(Volume *volume, Histogram *histogram, int low, int hi, int min_range, int max_range);
+
+ +

Description

+Load histogram with the histogram from a Ray, Sweep, or Volume. If histogram is NULL, then space is automatically allocated by RSL_allocate_histogram. Notice that a histogram pointer is passed into the routines. The argument histogram is used as an accumulator. For instance, getting the histogram for an entire sweep involves getting the histogram for ray #1, then adding the histograms for ray #2 through #n. Although, the argument histogram is modified, a pointer to that histogram is returned so that the function interface, that is commonly used throughout the RSL, is maintained. +
+ +

Return value

+Upon successful completion, a pointer to Histogram is returned. NULL is returned if an error occurs and errno is set. +
+ +

See also

+RSL_read_histogram, RSL_write_histogram, RSL_print_histogram, RSL_free_histogram +
+ +

Author: David B. Wolff + diff --git a/doc/RSL_get_linear_value.html b/doc/RSL_get_linear_value.html new file mode 100644 index 0000000..3f2d24b --- /dev/null +++ b/doc/RSL_get_linear_value.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_get_linear_value

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_get_linear_value(Volume *v, float srange, float azimuth, float elev, float limit); + +

+


+ +

Description

+Find a linearly interpolated value in the Volume, v, at the polar coordinate specification (srange, azimuth, elev). The four surrounding data values that are azimuthally within +/- limit degrees are used for the interpolation. Limit is measured in degrees. Srange is the slant range in KM. Azimuth and elev are measured in degrees. +
+ +

Return value

+Upon successful completion, a valid floating point number is returned. Note, the value could be BADVAL. +
+ +

See also

+RSL_get_value +
Author: Dennis Flanigan, Jr. + diff --git a/doc/RSL_get_next_cwise_ray.html b/doc/RSL_get_next_cwise_ray.html new file mode 100644 index 0000000..2604bdd --- /dev/null +++ b/doc/RSL_get_next_cwise_ray.html @@ -0,0 +1,35 @@ + + + + + +
+ + +

RSL_get_next_cwise_ray

+ + +

RSL_get_next_ccwise_ray

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_get_next_cwise_ray(Sweep *s, Ray *r);
+Ray *RSL_get_next_ccwise_ray(Sweep *s, Ray *r); + +

+
Description

+cwise, means clockwise and it is defined to mean "in the direction of increasing azimuth angle (don't ask)." ccwise means counter-clockwise and it is defined to mean "in the direction of decreasing azimuth angle." Dennis Flanigan defined cwise and ccwise. +
+ +

Return value

+Upon successful completion, a pointer to the Ray structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_ray_from_sweep, RSL_get_ray_above, RSL_get_ray_below, RSL_get_first_ray_of_sweep, RSL_get_first_ray_of_volume. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_nyquist_from_radar.html b/doc/RSL_get_nyquist_from_radar.html new file mode 100644 index 0000000..5188433 --- /dev/null +++ b/doc/RSL_get_nyquist_from_radar.html @@ -0,0 +1,32 @@ + + + + + +


+ + +

RSL_get_nyquist_from_radar

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_get_nyquist_from_radar(Radar *radar) + + +

+
Description

+Find a velocity volume. Find first sweep in that volume. Find first ray in that sweep. Return the nyquist velocity, a member of Ray. +
+ +

Return value

+Upon successful completion, a valid floating point number is returned. +
+ +

See also

+ +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_range_of_range_index.html b/doc/RSL_get_range_of_range_index.html new file mode 100644 index 0000000..7589bcf --- /dev/null +++ b/doc/RSL_get_range_of_range_index.html @@ -0,0 +1,27 @@ + + + + + +


+ + +

RSL_get_range_of_range_index

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_get_range_of_range_index (Ray *ray, int index); + +

+
Description

+index represents the bin number of the Ray's range. The geographic range is calculated from the range of the first bin and the bin size. +
+ +

Return value

+Upon successful completion, a pointer to the Ray structure is returned. Otherwise, a NULL pointer is returned. +
+ +

Author: Dennis Flanigan. + diff --git a/doc/RSL_get_ray.html b/doc/RSL_get_ray.html new file mode 100644 index 0000000..7a97321 --- /dev/null +++ b/doc/RSL_get_ray.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_get_ray

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_get_ray(Volume volume, float elev, float azimuth); + +

+
Description

+Extract a Ray from a Volume. Returns a pointer to a Ray. You must copy the Ray returned with RSL_copy_ray, if you want to modify the contents of the Ray without destroying the original Ray. elev is the elevation angle in degrees and is used to find the appropriate Sweep using the routine RSL_get_sweep. The azimuth angle within the appropriate Sweep must be within +/- 1/2 horizontal beam width of the target angle, azimuth. +
+ +

Return value

+Upon successful completion, a pointer to the Ray structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_ray_from_sweep, RSL_get_ray_above, RSL_get_ray_below, RSL_get_first_ray_of_sweep, RSL_get_first_ray_of_volume. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_ray_above-below.html b/doc/RSL_get_ray_above-below.html new file mode 100644 index 0000000..6b1ead8 --- /dev/null +++ b/doc/RSL_get_ray_above-below.html @@ -0,0 +1,35 @@ + + + + + +


+ + +

RSL_get_ray_above
+RSL_get_ray_below

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_get_ray_above(Volume *v, Ray *current_ray);
+Ray *RSL_get_ray_below(Volume *v, Ray *current_ray); + +

+
+ +

Description

+Returns a Ray that is either above or below the current_ray. The elevation angle is extracted from the current_ray and 1.0 is added or subtracted to/from it and the function RSL_get_sweep is called. This algorithm is simple and may not be robust enough; it has already been inadequate for the GT quality control. +
+ +

Return value

+Upon successful completion, a pointer to the Ray structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_ray_from_sweep, RSL_get_first_ray_of_sweep, RSL_get_first_ray_of_volume, RSL_get_ray, RSL_get_sweep. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_ray_from_sweep.html b/doc/RSL_get_ray_from_sweep.html new file mode 100644 index 0000000..7457a5a --- /dev/null +++ b/doc/RSL_get_ray_from_sweep.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_get_ray_from_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_get_ray_from_sweep(Sweep *s, float azim); + +

+
Description

+Return a pointer to a Ray that is in the Sweep *s, for the azimuth angle azim. The search is to find a ray that is within one beam width of the desired angle. The search is +/- 1/2 horizontal beam width. +
+ +

Return value

+Upon successful completion, a pointer to the Ray structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_ray, RSL_get_ray_above, RSL_get_ray_below, RSL_get_first_ray_of_sweep, RSL_get_first_ray_of_volume. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_slantr_and_elev.html b/doc/RSL_get_slantr_and_elev.html new file mode 100644 index 0000000..834e0b5 --- /dev/null +++ b/doc/RSL_get_slantr_and_elev.html @@ -0,0 +1,30 @@ + + + + + +


+ + +

RSL_get_slantr_and_elev

+
+ +

Synopsis

+#include "rsl.h"
+void RSL_get_slantr_and_elev(float gr, float h, float *slant_r, float *elev); + +

+
Description

+Given ground range, gr, and height, h, compute the slant range, slant_r and elevation angle, elev. Range and height units are in km. Angles are in degrees. This is the inverse function of RSL_get_groundr_and_h. +
+ +

Return value

+None. +
+ +

See also

+RSL_get_slantr_and_h, RSL_get_groundr_and_h +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_slantr_and_h.html b/doc/RSL_get_slantr_and_h.html new file mode 100644 index 0000000..020a6f2 --- /dev/null +++ b/doc/RSL_get_slantr_and_h.html @@ -0,0 +1,30 @@ + + + + + +


+ + +

RSL_get_slantr_and_h

+
+ +

Synopsis

+#include "rsl.h"
+void RSL_get_slantr_and_h(float gr, float elev, float *slant_r, float *h); + +

+
Description

+Given ground range, gr, and elevation angle, elev, compute the slant range, slant_r and height, h. Range and height units are in km. Angles are in degrees. +
+ +

Return value

+None. +
+ +

See also

+RSL_get_slantr_and_elev, RSL_get_groundr_and_h +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_slice_from_cube.html b/doc/RSL_get_slice_from_cube.html new file mode 100644 index 0000000..f287e62 --- /dev/null +++ b/doc/RSL_get_slice_from_cube.html @@ -0,0 +1,33 @@ + + + + + +


+ + +

RSL_get_slice_from_cube

+ +
+ +

Synopsis

+#include "rsl.h"
+Slice *RSL_get_slice_from_cube(Cube *cube, int x, int y, int z); + +

+
Description

+Given a Cube structure, extract one slice from it. x, y and z define the plane of the required slice. Two of the three parameters must equal -1 and the third must be nonnegative; eg, the vertical plane y=100 is specified by the parameters x=-1, y=100, z=-1. Assumes valid ranges for x, y, z are:
+0 <= x <= nx-1, 0 <= y <= ny-1, 1 <= z <= nz
+nx, ny and nz specify the dimensions of the cube structure and are members of it. The range of z starts at 1 , since a cappi (or carpi) at height z=0 makes no sense. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+RSL_volume_to_cube + +

+


Author: Mike Kolander + diff --git a/doc/RSL_get_sweep.html b/doc/RSL_get_sweep.html new file mode 100644 index 0000000..a3cea6b --- /dev/null +++ b/doc/RSL_get_sweep.html @@ -0,0 +1,33 @@ + + + + + +
+ + +

RSL_get_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+Sweep *RSL_get_sweep(Volume *v, float elev); + +

+
Description

+Looks in Volume *v for a sweep that has an elevation angle +/- beam width vertically. If found, then that sweep pointer is returned, else NULL is returned. +
+ +

Return value

+Upon successful completion, a pointer to the Sweep structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_get_volume, RSL_get_ray, RSL_get_first_sweep_of_volume, RSL_get_ray_from_sweep, +RSL_get_closest_sweep, +RSL_get_next_closest_sweep +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_sweep_index_from_volume.html b/doc/RSL_get_sweep_index_from_volume.html new file mode 100644 index 0000000..43f73b5 --- /dev/null +++ b/doc/RSL_get_sweep_index_from_volume.html @@ -0,0 +1,29 @@ + + + + + +


+ + +

RSL_get_sweep_index_from_volume

+ +
+ +

Synopsis

+#include "rsl.h"
+int RSL_get_sweep_index_from_volume(Volume *v, float elev,int *next_closest); + +

+
Description

+Return the index of the closest sweep. Also, returns the next closest sweep index. Use the index returned, if called i, in v->sweep[i]. +
+ +

Return value

+Upon successful completion, a valid index into the v->sweep[i] structure is returned. Otherwise, -1 is returned and *next_closest is undefined. +
+ +

See also

+RSL_get_sweep, RSL_get_ray +
Author: Dennis Flanigan Jr. + diff --git a/doc/RSL_get_value.html b/doc/RSL_get_value.html new file mode 100644 index 0000000..0dcc4d1 --- /dev/null +++ b/doc/RSL_get_value.html @@ -0,0 +1,43 @@ + + + + + +
+ + +

RSL_get_value...

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_get_value(Volume *v, float elev, float azimuth, float range);
+float RSL_get_value_at_h(Volume *v, float azim, float grnd_r, float h);
+float RSL_get_value_from_ray(Ray *ray, float r);
+float RSL_get_value_from_sweep(Sweep *s, float azim, float r); + +

+


+ +

+
Description

+RSL_get_value: Find a value in the Volume v using polar coordinate specification. The search returns the closest point. Although there is no restriction concerning azimuth values, other functions rely on the range being 0 to +360. This may change. Nexrad happened to use this range so I use it for now. + +

RSL_get_value_at_h: Returns a value when the coordinate is specified by ground range and height. Both ground range and height are specified in km. + +

RSL_get_value_from_ray: Return a value for the slant range r. Basically, r is converted to an index based on the gate size. + +

Vget_value_from_sweep: Get a value from a Sweep, s, given the azimuth azim and range r. + +

+


+ +

Return value

+Upon successful completion, a valid floating point number is returned. Note, the value could be BADVAL. +
+ +

See also

+ +
Author: John H. Merritt + diff --git a/doc/RSL_get_value_from_cappi.html b/doc/RSL_get_value_from_cappi.html new file mode 100644 index 0000000..fea024b --- /dev/null +++ b/doc/RSL_get_value_from_cappi.html @@ -0,0 +1,31 @@ + + + + + +
+ + +

RSL_get_value_from_cappi

+ +
+ +

Synopsis

+#include "rsl.h"
+float *RSL_get_value_from_cappi(Cappi *cap, float rng, float azm); + +

+
Description

+This routine uses RSL_get_value_from_sweep to get the value. +
+ +

Return value

+Upon successful completion, a valid floating point number is returned. If no value can be found, BADVAL is returned. +
+ +

See also

+RSL_get_value_from_sweep + +

+


Author: John H. Merritt + diff --git a/doc/RSL_get_volume.html b/doc/RSL_get_volume.html new file mode 100644 index 0000000..2095214 --- /dev/null +++ b/doc/RSL_get_volume.html @@ -0,0 +1,69 @@ + + + + + +
+ + +

RSL_get_volume

+ +
+ +

Synopsis

+#include "rsl.h"
+Volume *RSL_get_volume(Radar *r, int type_wanted); + +

+
Description

+RSL_get_volume extracts the desired volume from the Radar *r. type_wanted can be one of: DZ_INDEX, VR_INDEX, SW_INDEX, CZ_INDEX, ZT_INDEX, DR_INDEX or LR_INDEX. Only the pointer is copied for the returned value. If you want to optain a seperate copy of the volume, from the Radar *r, for modification purposes, then use RSL_copy_volume. The different indexes are described as follows: + +
 DZ	Reflectivity (dBZ), may contain some	DZ_INDEX
+ 	signal-processor level QC and/or
+ 	filters. This field would contain
+ 	Darwin's CZ, or WSR88D's standard
+ 	reflectivity. In other words, unless
+ 	the field is described otherwise, it
+ 	should always go here. In essence, this
+ 	is the "cleanest" reflectivity field
+ 	for a radar.
+
+ VR 	Radial Velocity (m/s)		VR_INDEX
+
+ SW 	Spectral Width (m2/s2) 		SW_INDEX
+
+ CZ 	QC Reflectivity (dBZ), contains
+	post-processed QC'd data 		CZ_INDEX
+
+ ZT 	Total Reflectivity (dBZ) 		ZT_INDEX
+ 	May be uncommon, but important
+
+ DR	Differential reflectivity 		DR_INDEX
+ 	DR and LR are for dual-polarization
+ 	radars only. Unitless or in dB.
+
+ LR 	Another form of differential ref	LR_INDEX
+ 	called LDR, not sure of units 
+
+
This function is a one line C function. Observe the following: + +
Radar *radar;
+Volume *v;
+/* The following two lines are identical. */
+v = Vget_volume(radar, DZ_INDEX);
+v = radar->v[DZ_INDEX];
+
+
+ +

Return value

+Upon successful completion, a pointer to the Volume structure is returned; only the pointer is copyied. +
+ +

See also

+RSL_get_sweep, RSL_get_ray
+RSL_copy_volume, RSL_copy_sweep, RSL_copy_ray
+RSL_free_volume, RSL_free_sweep, RSL_free_ray +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_get_win.html b/doc/RSL_get_win.html new file mode 100644 index 0000000..e5019df --- /dev/null +++ b/doc/RSL_get_win.html @@ -0,0 +1,34 @@ + + + + + +


+ + +

RSL_get_window_from_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_get_window_from_ray(Ray *r, float min_range, float max_range, float low_azim, float hi_azim);
+Sweep *RSL_get_window_from_sweep(Sweep *s, float min_range, float max_range, float low_azim, float hi_azim);
+Volume *RSL_get_window_from_volume(Volume *v, float min_range, float max_range, float low_azim, float hi_azim);

+Radar *RSL_get_window_from_radar(Radar *r, float min_range, float max_range, float low_azim, float hi_azim); + +

+
Description

+RSL_get_window_from_radar calls RSL_get_window_from_volume for the number of volumes. RSL_get_window_from_volume calls RSL_get_window_from_sweep for the number of sweeps. RSL_get_window_from_sweep calls RSL_get_window_from_ray for the number of rays. And RSL_get_window_from_ray gets window, between low_azim and hi_azim, from min_range to max_range. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. +
+ +

See also

+Example +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_hash_table_struct.html b/doc/RSL_hash_table_struct.html new file mode 100644 index 0000000..8d1fbde --- /dev/null +++ b/doc/RSL_hash_table_struct.html @@ -0,0 +1,15 @@ + + + + + +


+ + +
typedef struct {
+  Azimuth_hash **indexes;
+  int nindexes;
+} Hash_table;
+
+ + diff --git a/doc/RSL_hdf_to_radar.html b/doc/RSL_hdf_to_radar.html new file mode 100644 index 0000000..ec6304f --- /dev/null +++ b/doc/RSL_hdf_to_radar.html @@ -0,0 +1,59 @@ + + + + + + + + +
+ +

RSL_hdf_to_radar
+RSL_hdf_to_radar_unQC

+ +

+


+ +

Synopsis

+ +

#include "rsl.h"
+Radar *RSL_hdf_to_radar(char *infile);
+
+Radar *RSL_hdf_to_radar_unQC(char +*infile); +


+ +

Description

+ +

Reads an HDF file and returns a pointer to the structure Radar. +The input file is specified by the string infile. If infile +is NULL, then no action is taken. This is different from other ingest routines +where stdin is read. HDF files cannot be stdin, because they require seeking.. +The input file may not be compressed.

+ +

RSL_hdf_to_radar_unQC differs from RSL_hdf_to_radar in +that both DZ (original uncorrected reflectivity) and CZ (corrected) volumes +are extracted from the HDF file. Normally, RSL_hdf_to_radar +returns CZ only. Call one or the other, for ingest efficiency.

+ +

The radar structure is, essentially, an array of Volumes. The number +and type of volumes allocated is automatically determined from the input +HDF file. +


+ +

Return value

+ +

Upon successful completion, RSL_hdf_to_radar returns a pointer +to the structure Radar. Otherwise, NULL is returned and errno is +set. +


+ +

See also

+ +

RSL_anyformat_to_radar +


+ +

Author: Mike Kolander.

+ + + diff --git a/doc/RSL_histogram_struct.html b/doc/RSL_histogram_struct.html new file mode 100644 index 0000000..00576d5 --- /dev/null +++ b/doc/RSL_histogram_struct.html @@ -0,0 +1,17 @@ + + + + + +
+ + +
typedef struct {
+  int nbins;
+  int low;
+  int hi;
+  int ucount;
+  int ccount;
+  int *data;
+} Histogram; 
+ diff --git a/doc/RSL_lassen_to_radar.html b/doc/RSL_lassen_to_radar.html new file mode 100644 index 0000000..96d4d25 --- /dev/null +++ b/doc/RSL_lassen_to_radar.html @@ -0,0 +1,33 @@ + + + + + +
+ + +

RSL_lassen_to_radar

+ +
+ +

Synopsis

+#include "rsl.h"
+Radar *RSL_lassen_to_radar(char *infile);
+
+ +

Description

+Reads a LASSEN (data from Darwin Austrailia) file and returns a pointer to the structure Radar. The input file is specified by the string infile. If infile is NULL, then stdin is read. The input file may be compressed. If the data is compressed, it is passed through the GNU gunzip filter. Thus, compressed data can be any format that gzip understands. + +

The radar structure is, essentially, an array of Volumes. These volumes represent the reflectivity, velocity and spectrum width fields. +


+ +

Return value

+Upon successful completion, lassen_to_radar returns a pointer to the structure Radar. Otherwise, NULL is returned and errno is set. +
+ +

See also

+RSL_anyformat_to_radar +
+ +

Author: John H. Merritt. + diff --git a/doc/RSL_load_color_table.html b/doc/RSL_load_color_table.html new file mode 100644 index 0000000..f1ba8c9 --- /dev/null +++ b/doc/RSL_load_color_table.html @@ -0,0 +1,72 @@ + + + + + + + + +


+

+RSL color table routines

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_load_color_table(char *infile, char buffer[256], int *ncolors); +
void RSL_load_green_table(char *infile); +
void RSL_load_blue_table(char *infile); +
void RSL_load_red_table(char *infile); +
void RSL_load_refl_color_table(); +
void RSL_load_sw_color_table(); +
void RSL_load_vel_color_table(); +
void RSL_load_zdr_color_table(); +
void RSL_load_rainfall_color_table(); +
void RSL_load_height_color_table(); +

+ +
Description

+These are the color table routines. The color table is use when making +images and is merely 256 bytes in size representing red, green and blue +color indexes. The routines RSL_load_refl_color_table, RSL_load_sw_color_table, +RSL_load_vel_color_table,and RSL_load_zdr_color_table each call +the three routines RSL_load_red_table, RSL_load_green_table, +and RSL_load_blue_table with a hard coded (defined during software +installation) color input file. Under normal usage, you only have to call +these routines once prior to any image generation function calls. +

The routines RSL_load_rainfall_color_table and RSL_load_height_color_table +use the default files defined during installation. These routines exist +to simplify the interface when generating height or rainfall images. +

The default input file names are defined in volume.h. When you don't +want to use the default color tables for reflectivity, spectrum width, +or velocity, and have your own color tables, you can use RSL_load_red_table, +RSL_load_green_table, +and RSL_load_blue_table directly. Be sure to call all three routines. +The most general of the routines, and one you should not normally use, +is RSL_load_color_table. It manages a static global color table +array and it is how the color table is remembered throughout your application. +

The organization of the input color table files is binary. They contain, +at most, 256 bytes with no delimeters and represent the color ramp from +index 0 to 255.  +


+

+Return value

+None.  +
+

+See also

+RSL_sweep_to_gif, RSL_sweep_to_pict, +RSL_sweep_to_pgm, +RSL_sweep_to_ppm, +
RSL_bscan_ray, RSL_bscan_sweep, +RSL_bscan_volume, +
RSL_volume_to_gif, RSL_volume_to_pict, +RSL_volume_to_pgm, +RSL_volume_to_ppm, +
RSL_get_color_table, RSL_set_color_table. +
+
+

Author: John H. Merritt + + diff --git a/doc/RSL_mcgill_to_radar.html b/doc/RSL_mcgill_to_radar.html new file mode 100644 index 0000000..d3c0d35 --- /dev/null +++ b/doc/RSL_mcgill_to_radar.html @@ -0,0 +1,34 @@ + + + + + +


+ + +

RSL_mcgill_to_radar

+ +
+ +

Synopsis

+#include "rsl.h"
+Radar *RSL_mcgill_to_radar(char *infile);
+
+ +

Description

+Reads a McGill file and returns a pointer to the Radar structure. The input file is specified by the string infile. The input file may be compressed. If the data is compressed, it is passed through the GNU gunzip filter. Thus, compressed data can be any format that gzip understands. + +

The radar structure is, essentially, an array of Volumes. These volumes represent the reflectivity, velocity and spectrum width fields. +


+ +

Return value

+Upon successful completion, RSL_mcgill_to_radar returns a pointer to the structure Radar. Otherwise, NULL is returned. +
+ +

See also

+RSL_anyformat_to_radar +
+ +

Author: Mike Kolander + + diff --git a/doc/RSL_new.html b/doc/RSL_new.html new file mode 100644 index 0000000..cb15e9b --- /dev/null +++ b/doc/RSL_new.html @@ -0,0 +1,48 @@ + + + + + +


+ + +

RSL_new_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_new_ray(int max_bins);
+Sweep *RSL_new_sweep(int max_rays);
+Volume *RSL_new_volume(
int max_sweeps);
+Radar *RSL_new_radar(int nvolumes); + +

+
Description

+RSL_new_radar allocates memory for a Radar. It allocates space for it's header and space for nvolumes pointers to Volume, it does not assign anything to the new header. It does not allocate any volumes, just the pointers. You have to perform the allocation of volumes yourself. Do this by looping on nvolumes and calling RSL_new_volume. + +

nvolumes does not represent the number of volumes in the radar structure. It represents the number of volume index slots or the maximum volume index. Reserved values DZ_INDEX, VR_INDEX, SW_INDEX, CZ_INDEX, ZT_INDEX, DR_INDEX, and LR_INDEX are the numbers 0 through 6. They are volume indexes. If you have 2 volumes (non NULL pointers) that are SW_INDEX and ZT_INDEX, you must be sure that nvolumes is, at least, ZT_INDEX+1. All the other volume pointers are NULL. It is perfectly valid to have NULL volume pointers. + +

RSL_new_volume allocates memory for a Volume. It allocates space for it's header and space for nsweep pointers to Sweep, it does not assign anything to the new header. It does not allocate any sweeps, just the pointers. You have to perform the allocation of sweeps yourself. Do this by looping on nsweeps and calling RSL_new_sweep. + +

nsweeps does not represent the number of non NULL sweep pointers. It is the number of index slots or the maximum sweep index. It is valid to have NULL sweep pointers. + +

RSL_new_sweep allocates memory for a Sweep. It allocates space for it's header and space for nrays pointers to Ray. It does not allocate any rays, just the pointers, nor does it assign any values to the new header. You have to perform the allocation of rays yourself. Do this by looping on nrays and calling RSL_new_ray. + +

nrays does not represent the number of non NULL ray pointers. It is the number of index slots or the maximum ray index. It is valid to have NULL ray pointers. + +

RSL_new_ray allocates memory for a Ray. It allocates space for it's header and space for a Range array of size nbins. It does not assign any values to the header. Since, the Range type is not a pointer, this function allocates an array of Range of size nbins. Currently, Range is just an alias for unsigned char. +


+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+Example
+RSL_free_volume, RSL_free_sweep, RSL_free_ray
+RSL_copy_volume, RSL_copy_sweep, RSL_copy_ray +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_new_cappi.html b/doc/RSL_new_cappi.html new file mode 100644 index 0000000..f74c1b6 --- /dev/null +++ b/doc/RSL_new_cappi.html @@ -0,0 +1,33 @@ + + + + + +


+ + +

RSL_new_cappi

+ +
+ +

Synopsis

+#include "rsl.h"
+Cappi *RSL_new_cappi(Sweep *sweep, float height); + +

+
Description

+RSL_new_cappi allocates memory for a Cappi. It allocates space for it's header and space for for a Sweep structure. The Sweep allocated is a copy of sweep with all the data cleared. The height argument is copied to the height member of Cappi. No values are assigned to the rays in the sweep. That is done in the routine RSL_fill_cappi. This routine is not, normally, called unless you are developing a new cappi routine for RSL. Call RSL_cappi_at_h instead. + +

+


+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+RSL_free_cappi, RSL_cappi_at_h, RSL_fill_cappi, RSL_get_value_from_cappi + +

+


Author: John H. Merritt + diff --git a/doc/RSL_new_carpi.html b/doc/RSL_new_carpi.html new file mode 100644 index 0000000..82fdb8d --- /dev/null +++ b/doc/RSL_new_carpi.html @@ -0,0 +1,31 @@ + + + + + +
+ + +

RSL_new_carpi

+ +
+ +

Synopsis

+#include "rsl.h"
+Carpi *RSL_new_carpi(int xdim, int ydim); + +

+
Description

+Allocates xdim by ydim of Carpi_value. The entire structure is initialized to 0. + +

+


+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+ +
Author: Mike Kolander + diff --git a/doc/RSL_nsig_to_radar.html b/doc/RSL_nsig_to_radar.html new file mode 100644 index 0000000..8232ce9 --- /dev/null +++ b/doc/RSL_nsig_to_radar.html @@ -0,0 +1,57 @@ + + + + + + + + +

+ +


+ +

RSL_nsig_to_radar

+ +

+


+ +

Synopsis

+ +

#include "rsl.h"
+Radar *RSL_nsig_to_radar(char *infile);
+
+Radar *RSL_nsig2_to_radar(char *infile); + +


+ +

Description

+ +

Reads a new SIGMET (aka nsig) file and returns a pointer to the structure +Radar. The input file is specified by the string infile. +If infile is NULL, then stdin is read. The input file may be compressed. +If the data is compressed, it is passed through the GNU gunzip filter. +Thus, compressed data can be any format that gzip understands. Two +versions of SIGMET files exist: Version 1 files, and Version 2 files. +RSL_nsig_to_radar is used to read version 1 files, and, RSL_nsig2_to_radar +is used to read version 2 files.

+ +

The radar structure is, essentially, an array of Volumes. The number +and type of volumes allocated is automatically determined from the input +nsig file. +


+ +

Return value

+ +

Upon successful completion, RSL_nsig_to_radar returns a pointer to the +structure Radar. Otherwise, NULL is returned and errno is set. +


+ +

See also

+ +

RSL_anyformat_to_radar +


+ +

Author: Paul Kucera.

+ + + diff --git a/doc/RSL_print_histogram.html b/doc/RSL_print_histogram.html new file mode 100644 index 0000000..49d22e4 --- /dev/null +++ b/doc/RSL_print_histogram.html @@ -0,0 +1,31 @@ + + + + + +
+ + +

RSL_print_histogram

+ +

+


+ +

Synopsis

+#include "rsl.h"
+void RSL_print_histogram(Histogram *histogram, int min_range, int max_range, char *filename);
+
+ +

Description

+Print the structure pointed to by histogram to stdout. min_range and max_range specify the minimum and maximum range of the radar that was used to generate the histogram. +
+ +

Return value

+None. +
+ +

See also


+RSL_allocate_histogram, RSL_read_histogram, RSL_write_histogram, RSL_get_histogram_from_ray, RSL_get_histogram_from_sweep, RSL_get_histogram_from_volume + +

Author: David B. Wolff + diff --git a/doc/RSL_print_version.html b/doc/RSL_print_version.html new file mode 100644 index 0000000..10be6a4 --- /dev/null +++ b/doc/RSL_print_version.html @@ -0,0 +1,40 @@ + + + + + + + +


+ +

RSL_print_version

+ +

+


+ +

Synopsis

+ +

#include "rsl.h" +
void RSL_print_version(); +

+ +

+
Description

+ +

Print the current version of the RSL library. Output to stdout.

+ +

+


+ +

Return value

+ +

None. +


+ +

See also

+ +

+


Author: John H. Merritt

+ + + diff --git a/doc/RSL_prune.html b/doc/RSL_prune.html new file mode 100644 index 0000000..cd7a90d --- /dev/null +++ b/doc/RSL_prune.html @@ -0,0 +1,35 @@ + + + + + +
+ + +

RSL_prune_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_prune_ray(Ray *ray);
+Sweep *RSL_prune_sweep(Sweep *s);
+Volume *RSL_prune_volume(Volume *v
);
+Radar *RSL_prune_radar(Radar *radar); + +

+
Description

+These routines eliminates dataless substructures. A search is conducted for any substructures that contain only header information and, when found, are set to NULL. During the initial allocation step for ingest of a data format, substructure header information is minimially filled. It is not generally known if, for instance, a volume is NULL until it can be determined if there have been no rays assigned to it. In such a case, all sweep pointers have been allocated but no ray pointers assigned. Pruning this volume will result in setting the volume to NULL. A ray is pruned if h.nbins is 0. A sweep is pruned if h.nrays is 0. A volume is pruned if h.nsweeps is 0. A radar is pruned if h.nvolumes is 0. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned. +
+ +

See also

+RSL_new_radar, RSL_new_volume, RSL_new_sweep, RSL_new_ray,
+RSL_copy_volume
, RSL_copy_sweep, RSL_copy_ray +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_radar_file_format.html b/doc/RSL_radar_file_format.html new file mode 100644 index 0000000..92e435f --- /dev/null +++ b/doc/RSL_radar_file_format.html @@ -0,0 +1,14 @@ + + + + + +


+ + +

The radar file format is not yet documented. Nor is it supported.

+It is unclear if it will be supported because we will output UF or HDF. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_radar_header_struct.html b/doc/RSL_radar_header_struct.html new file mode 100644 index 0000000..b752bed --- /dev/null +++ b/doc/RSL_radar_header_struct.html @@ -0,0 +1,41 @@ + + + + + + + + +


+
typedef struct { 
+  int month, day, year; 
+  int hour, minute; 
+  float sec; /* Second plus fractional part. */
+  char radar_type[50]; /* Type of radar. Use for QC-ing the data.
+                        * Supported types are:
+                        * "wsr88d", "lassen", "uf",
+                        * "nsig", "nsig2", "mcgill",
+                        * "kwajalein", "rsl", "toga".
+                        * Set by appropriate ingest routine.
+                        */ 
+  int nvolumes;
+  int number;        /* arbitrary number of this radar site */
+  char name[8];      /* Nexrad site name */
+  char radar_name[8]; /* Radar name. */
+  char project[24];   /* Project assocated with data. */
+  char city[15];     /* nearest city to radaar site */
+  char state[2];     /* state of radar site */
+  int latd;   /* degrees of latitude of site */
+  int latm;   /* minutes of latitude of site */
+  int lats;   /* seconds of latitude of site */
+  int lond;   /* degrees of longitude of site */
+  int lonm;   /* minutes of longitude of site */
+  int lons;   /* seconds of longitude of site */
+  int height; /* height of site in meters above sea level*/
+  int spulse; /* length of short pulse (ns)*/
+  int lpulse; /* length of long pulse (ns) */
+  int vcp;    /* Volume Coverage Pattern (for WSR-88D only) */
+} Radar_header;
+ + + diff --git a/doc/RSL_radar_intro.html b/doc/RSL_radar_intro.html new file mode 100644 index 0000000..7838d5b --- /dev/null +++ b/doc/RSL_radar_intro.html @@ -0,0 +1,112 @@ + + + + + + + + +
+
  +
  +
+

+The Radar Software Library (RSL)

+ +

+Introduction

+ +

+By John H. Merritt and David +B. Wolff; NASA/TRMM Office
+Software Verson 1.40 (released 10/10/2008)

+ +
This library is an object oriented programming environment to keep +application programming simple, for the casual C programmer, as well as +for analysis software applicable to all RADAR data related to the TRMM +GV effort. This library reads the wsr88d, lassen, kwajalein, mcgill, toga, +UF, RAPIC and native RSL file formats. The most important functions provided +are those which load any one of the radar file formats into memory; see +RSL_anyformat_to_radar. Additional +functions are provide to mainpulate the RSL objects. Nearly all of the +functions return objects. When they don't, they usually perform actions +like output, making images, etc. The most general object in RSL is Radar. +The structure Radar is the method used to define the ideal or universal +radar representation in RAM while keeping the natural resolution of the +data unchanged. More simply, Radar represents the super set of all +radar file formats. The Radar structure +is hierarchically defined such that it is composed of Volumes, each +containing one field type. Volumes are composed of Sweeps. +Sweeps are composed of Rays and Rays contains a vector +of the field type. Some field types are Reflectivity(DZ), Velocity(VR), +Spectrum Width(SW), etc. There are approximately 20 field types. See the +Users Guide and the what's +new for more information. +

An example of a function that returns the Radar object is the +Lassen ingest function. The function allocates all memory required +to store the values from the lassen file in RAM. +

Radar *radar; radar = RSL_lassen_to_radar("lassen.file.22"); +

Syntactically, the object returned is a pointer. However, the functions +provided in RSL treat this pointer as an object. +

The names of the functions in the library are very descriptive of the +function they perform. In the previous example, you may infer that some +conversion from lassen to radar is taking place. Knowing +that lassen is a file format for the Darwin RADAR datasets and that +radar +refers to the data structure Radar helps you understand that the +function ingests lassen files and loads it into the Radar +data structure. +

The data structure Radar is composed of other objects called +Volumes. +You will notice that throughout this discussion, the natural vocabulary +of the scientists who talk about the different components of the data received +from a RADAR is used. This vocabulary is used to describe each component +of the data structure. The Radar data structure holds RADAR measurements +of a volume of physical space for the smallest unit of time possible. Typically +a RADAR can produce a volume of data in 5 to 8 minutes; that becomes the +smallest unit of time for a volume. This volume of space measured is referred +to as Volume, in the RSL, and represents one particular measurement +type or field type. The types of measurements are: reflectivity, velocity, +spectrum width, quality controlled reflectivity, total reflectivity, differential +reflectivity and LDR (another form of differential reflectivity). Normally, +the RADAR records as many fields that it is designed to record and that +really is one volume. However, I have split the fields into seperate volumes +so that you can concentrate on only one field type. Thus, the Radar +datatype is composed of an array of Volumes; one to the number of +fields. +

The Volume data structure, a single field type, is composed of +several 360 degree revolutions of the RADAR. These revolutions are refered +to as sweeps. The first sweep for a volume, commonly known as the base +scan, is the sweep made by the RADAR pointing nearly horizontally and directing +a RADAR beam toward the horizon. Then, the RADAR is tilted upwards slightly +and another revolution is performed. This process continues 10 to 16 times, +depending on the RADAR. These sweeps are referred to as Sweep in +the RSL. Thus, a Volume is simply composed of an array of Sweeps; +one to the number of elevation steps. +

Similiarly, a Sweep is defined as a collection of rays throughout +the 360 degree revolution. The RADAR takes measurements continually while +it is sweeping. The number of rays collected is typically a function of +the beamwidth. A beam width of .95 degrees will yield 379 rays for each +sweep. For nexrad data the number of rays collected for each sweep is approximately +366. These rays are referred to as Ray in the RSL. Thus, a Sweep +is simply an array of Rays; one to the number of rays. +

And, a Ray is one ray measurement from the RADAR. A ray is a +series of measurements from the minimum to the maximum range of the RADAR. +Think of it as a meaurement from zero to the maximum range while the RADAR +is at one azimuthal angle. In reality, the radar is revolving continuously. +The number of data values in a ray is represented in KM and it defines +the resolution of the RADAR. NEXRAD is typcally 1.0KM and the new SIGMET +RADAR is .25 KM. Thus, a Ray is simply an array of Range +values; one to the number of bin. The number of bins is defined by the +range of measured space divided by the resolution of a measurement less +any to the minimum range. +

Finally, a Range value is simply a floating point number that +represents the data. +

It should be obvious that the Radar data structure is an array +of Volumes which is an array of Sweeps which is an array +of Rays which is and array of Ranges. Whew! This hierarchial +description is easy to understand, when you only think of each object as +an array of the next subobject. Thinking of it as a 4 or 5 dimensional +array is very difficult. + + diff --git a/doc/RSL_radar_struct.html b/doc/RSL_radar_struct.html new file mode 100644 index 0000000..8e3ee7c --- /dev/null +++ b/doc/RSL_radar_struct.html @@ -0,0 +1,92 @@ + + + + + +


+ + +
typedef struct {
+  Radar_header h;
+  Volume **v;   /* Array 0..nvolumes-1 of pointers to Volumes.
+                      * 0 = DZ_INDEX = reflectivity.
+                      * 1 = VR_INDEX = velocity.
+                      * 2 = SW_INDEX = spectrum_width.
+                      * 3 = CZ_INDEX = corrected reflectivity.
+                      * 4 = ZT_INDEX = total reflectivity.
+                      * 5 = DR_INDEX = differential refl.
+                      * 6 = LR_INDEX = another differential refl.
+                      * 7 = ZD_INDEX = another refl form.
+                      * 8 = DM_INDEX = recieved power.
+                      * 9 = RH_INDEX = Rho coefficient.
+                      *10 = PH_INDEX = Phi (MCTEX parameter).
+                      *11 = XZ_INDEX = X-band reflectivity.
+                      *12 = CR_INDEX = Corrected DR.
+                      *13 = MZ_INDEX = DZ mask for 1C-51 HDF.
+                      *14 = MR_INDEX = DR mask for 1C-51 HDF.
+                      *15 = ZE_INDEX = Edited reflectivity.
+                      *16 = VE_INDEX = Edited velocity.
+                      *17 = KD_INDEX = KDP (unknown)  for MCTEX data.
+                      *18 = TI_INDEX = TIME (unknown)  for MCTEX data.
+                */
+} Radar;
+
+/*
+ * DZ     Reflectivity (dBZ), may contain some   DZ_INDEX
+ *        signal-processor level QC and/or      
+ *        filters. This field would contain 
+ *        Darwin's CZ, or WSR88D's standard 
+ *        reflectivity. In other words, unless
+ *        the field is described otherwise, it
+ *        should always go here. In essence, this
+ *        is the "cleanest" reflectivity field
+ *        for a radar.
+ *
+ * VR     Radial Velocity (m/s)                  VR_INDEX
+ *
+ * SW     Spectral Width (m2/s2)                 SW_INDEX
+ *
+ * CZ     QC Reflectivity (dBZ), contains
+ *        post-processed QC'd data               CZ_INDEX
+ *
+ * ZT     Total Reflectivity (dBZ)               ZT_INDEX
+ *        May be uncommon, but important
+ *        This is UZ in UF files.
+ *
+ * DR     Differential reflectivity              DR_INDEX
+ *        DR and LR are for dual-polarization
+ *        radars only. Unitless or in dB.
+ *
+ * LR     Another form of differential ref       LR_INDEX
+ *        called LDR, not sure of units
+ *
+ * ZD     ZDR: Reflectivity Depolarization Ratio ZD_INDEX
+ *        ZDR = 10log(ZH/ZV)  (dB)
+ *
+ * DM     Received power measured by the radar.  DM_INDEX
+ *        Units are dBm.
+ *
+ * RH     Rho : Correlation coefficient (MCTEX)  RH_INDEX
+ *
+ * PH     Phi (MCTEX parameter)                  PH_INDEX
+ *
+ * XZ     X-band reflectivity                    XZ_INDEX
+ *
+ * CD     Corrected ZD reflectivity (differential) CD_INDEX
+ *        contains QC'ed data
+ *
+ * MZ     DZ mask volume for HDF 1C-51 product.  MZ_INDEX
+ *
+ * MD     ZD mask volume for HDF 1C-51 product.  MD_INDEX
+ *
+ * ZE     Edited Reflectivity.                   ZE_INDEX
+ *
+ * VE     Edited Velocity.                       VE_INDEX
+ *
+ * KD     KDP (unknown)  for MCTEX data.         KD_INDEX
+ *
+ * TI     TIME (unknown)  for MCTEX data.        TI_INDEX
+ */
+
+
+ diff --git a/doc/RSL_radar_to_hdf.html b/doc/RSL_radar_to_hdf.html new file mode 100644 index 0000000..0b3de96 --- /dev/null +++ b/doc/RSL_radar_to_hdf.html @@ -0,0 +1,50 @@ + + + + + + + + +
+ +

RSL_radar_to_hdf

+ +

+


+ +

Synopsis

+ +

#include "rsl.h"
+int RSL_radar_to_hdf(Radar *radar, +char *outfile);
+


+ +

Description

+ +

Writes HDF files. The output file is specified by outfile. +The organization of the data within the HDF file is specified in NASA +document TSDIS-P907. This is also known as TSDIS ICS Volume 3 (Release +3/Draft). You must preceed the call to RSL_radar_to_hdf with a call to +RSL_set_hdf_qc_parameters.

+ +

+


+ +

Return value

+ +

Upon successful completion, RSL_radar_to_hdf returns 0. Upon failure, +-1 is returned. +


+ +

See also

+ +

RSL_anyformat_to_radar

+ +

RSL_set_hdf_qc_parameters +


+ +

Author: Mike Kolander.

+ + + diff --git a/doc/RSL_radar_to_uf.html b/doc/RSL_radar_to_uf.html new file mode 100644 index 0000000..483e865 --- /dev/null +++ b/doc/RSL_radar_to_uf.html @@ -0,0 +1,39 @@ + + + + + +
+ + +

RSL_radar_to_uf

+ + +

RSL_radar_to_uf_fp

+ + +

RSL_radar_to_uf_gzip

+ +
+ +

Synopsis

+#include "rsl.h"
+void RSL_radar_to_uf(Radar *r, char *outfile);
+void RSL_radar_to_uf_fp(Radar *r, FILE *fp);
+void RSL_radar_to_uf_gzip(Radar *r, char *outfile); + +

+
Description

+Output the Radar structure, pointed to by r, to disk. The output filename is specified in outfile. The output UF file incorporates the NON-UF conforming NCAR record structure. Each UF record is surrounded by a 4 byte integer leading the UF buffer and a 4 byte integer trailing the UF buffer. The integer value represents the number of bytes for the UF buffer. This comes from the unformatted Fortran record descriptors. No UF library needed; the UF code in part of RSL. The routine RSL_radar_to_uf_fp takes a file pointer and is called by RSL_radar_to_uf and RSL_radar_to_uf_gzip. RSL_radar_to_uf_gzip passes the UF output through the GNU gzip compression filter; basically compressing the output on the fly. +
+ +

Return value

+None. +
+ +

See also

+RSL_uf_to_radar, RSL_write_radar +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_radar_verbose.html b/doc/RSL_radar_verbose.html new file mode 100644 index 0000000..8c3f53d --- /dev/null +++ b/doc/RSL_radar_verbose.html @@ -0,0 +1,29 @@ + + + + + +


+ + +

RSL_radar_verbose...

+
+ +

Synopsis

+#include "rsl.h"
+void RSL_radar_verbose_on(void);
+void RSL_radar_verbose_off(void); +
+ +

Description

+Control the verbosity of messages while using the RSL. After calling radar_verbose_off, the default, the library is quiet. After calling radar_verbose_on, the library writes to stdout informative messages about the current progress. This is useful when using the RSL interactively, since some of the functions take time; it assure you that nothing is hung. +
+ +

Return value

+None. +
+ +

See also

+ +
Author: John Merritt + diff --git a/doc/RSL_radtec_to_radar.html b/doc/RSL_radtec_to_radar.html new file mode 100644 index 0000000..2355bf8 --- /dev/null +++ b/doc/RSL_radtec_to_radar.html @@ -0,0 +1,43 @@ + + + + + + +  +
+

+RSL_radtec_to_radar

+ +
+

+Synopsis

+#include "rsl.h" +
Radar *RSL_radtec_to_radar(char +*infile);  +
+

+Description

+Reads a RADTEC (SPANDAR) file and returns a pointer to the Radar +structure. The input file is specified by the string infile. If +infile is NULL, then stdin is read.  The data is compressed +with PKWARE implode.  RSL needs to be installed with -DHAVE_PKWARE +in order to used RSL_radtec_to_radar. + +

The radar structure is, essentially, an array of Volumes. These volumes +represent the reflectivity, velocity and spectrum width fields.  +


+

+Return value

+Upon successful completion, RSL_radtec_to_radar returns a pointer to the +structure Radar. Otherwise, NULL is returned. A valid Radar +structure will be returned if the infile is valid.  +
+

+See also

+RSL_anyformat_to_radar  +
+ +

Author: John H. Merritt. + + diff --git a/doc/RSL_range_struct.html b/doc/RSL_range_struct.html new file mode 100644 index 0000000..206ace6 --- /dev/null +++ b/doc/RSL_range_struct.html @@ -0,0 +1,20 @@ + + + + + + + + +

+


If #define USE_TWO_BYTE_PRECISION when building and installing RSL, +then

+ +
typedef unsigned short Range;
+ +

else,

+ +
typedef unsigned char Range;
+ + + diff --git a/doc/RSL_rapic_to_radar.html b/doc/RSL_rapic_to_radar.html new file mode 100644 index 0000000..245fbea --- /dev/null +++ b/doc/RSL_rapic_to_radar.html @@ -0,0 +1,44 @@ + + + + + + +   +
+

+RSL_rapic_to_radar

+ +
+

+Synopsis

+#include "rsl.h" +
Radar *RSL_rapic_to_radar(char +*infile);  +
+

+Description

+Reads a RAPIC (data from Berrimah Austrailia) file and returns a pointer +to the structure Radar. The input file is specified by the string +infile. If infile is NULL, then stdin is read. The input +file may be compressed. If the data is compressed, it is passed through +the GNU gunzip filter. Thus, compressed data can be any format that +gzip understands. + +

The radar structure is, essentially, an array of Volumes. These volumes +represent several field types, including but not limited to, reflectivity, +velocity and spectrum width fields.  +


+

+Return value

+Upon successful completion, RSL_rapic_to_radar returns a pointer to the +structure Radar. Otherwise, NULL is returned and errno is set.  +
+

+See also

+RSL_anyformat_to_radar  +
+ +

Author: John H. Merritt. + + diff --git a/doc/RSL_ray_header_struct.html b/doc/RSL_ray_header_struct.html new file mode 100644 index 0000000..2065762 --- /dev/null +++ b/doc/RSL_ray_header_struct.html @@ -0,0 +1,19 @@ + + + + + + + + + + + +   +


+
typedef struct {
  int   month; /* Date for this ray; month (1-12). */
  int   day;   /* Date for this ray; day (1-31).   */
  int   year;  /* Date for this ray; year (eg. 1993). */
  int   hour;  /* Time for this ray; hour (0-23). */
  int   minute;/* Time for this ray; minute (0-59).*/
  float sec;   /* Time for this ray; second + fraction of second. */
  float unam_rng;  /* Unambiguous range. (KM). */
  float azimuth;   /* Azimuth angle. (degrees). Must be positive
                    * 0=North, 90=east, -90/270=west.
                    * This angle is the mean azimuth for the whole ray.
                    * Eg. for NSIG the beginning and end azimuths are
                    * averaged.
                    */
  int   ray_num;   /* Ray no. within elevation scan. */
  float elev;       /* Elevation angle. (degrees). */
  int   elev_num;   /* Elevation no. within volume scan. */
  
  int   range_bin1; /* Range to first gate.(meters) */
  int   gate_size;  /* Data gate size (meters)*/
  
  float  vel_res;    /* Doppler velocity resolution */
  float sweep_rate;   /* Sweep rate. Full sweeps/min. */
  
  int prf;          /* Pulse repitition frequency, in Hz. */
  float azim_rate; /* Sweep rate in degrees/second.*/
  float fix_angle; /* Elevation angle for the sweep. (degrees). */
  float pitch;      /* Pitch angle. */
  float roll;       /* Roll  angle. */
  float heading;    /* Heading. */
  float pitch_rate; /* (angle/sec) */
  float roll_rate;  /* (angle/sec) */
  float heading_rate; /* (angle/sec) */
  float lat;          /* Latitude (degrees) */
  float lon;          /* Longitude (degrees) */
  int   alt;          /* Altitude (m) */
  float rvc;          /* Radial velocity correction (m/sec) */
  float vel_east;     /* Platform velocity to the east  (m/sec) */
  float vel_north;    /* Platform velocity to the north (m/sec) */
  float vel_up;       /* Platform velocity toward up    (m/sec) */
  float pulse_count; /* Pulses used in a single dwell time. */
  float pulse_width; /* Pulse width (micro-sec). */
  float beam_width;  /* Beamwidth in degrees. */
  float frequency;   /* Bandwidth MHz. */
  float wavelength;  /* Wavelength. Meters. */
  float nyq_vel;    /* Nyquist velocity. m/s */
  float (*f)(Range x);       /* Data conversion function. f(x). */
  Range (*invf)(float x);    /* Data conversion function. invf(x). */
  int   nbins;               /* Number of array elements for 'Range'. */
} Ray_header;
+
+ + diff --git a/doc/RSL_ray_struct.html b/doc/RSL_ray_struct.html new file mode 100644 index 0000000..036ecdf --- /dev/null +++ b/doc/RSL_ray_struct.html @@ -0,0 +1,18 @@ + + + + + +
+ + +
typedef struct {
+  Ray_header h;
+  Range *range; /* range[0..nbins-1] */
+                /* For wsr88d file:
+                 * 0..460 for reflectivity, 0..920 for velocity and 
+                 * spectrum width. You must allocate this space.
+                 */
+} Ray; 
+ + diff --git a/doc/RSL_read.html b/doc/RSL_read.html new file mode 100644 index 0000000..e016545 --- /dev/null +++ b/doc/RSL_read.html @@ -0,0 +1,41 @@ + + + + + +
+ + +

RSL_read_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Ray *RSL_read_ray(FILE *fp);
+Sweep *RSL_read_sweep(FILE *fp);

+Volume
*RSL_read_volume
(FILE *fp); + +

+
Description

+RSL_read_volume reads an entire volume structure from the input stream fp. fp is usually assigned inside the routine RSL_read_radar, however, you can assign the stream fp via fopen. RSL_read_volume calls RSL_read_sweep for the number of sweeps, vol->h.nsweeps, as determined from reading fp. Memory is allocated via RSL_new_volume. + +

RSL_read_sweep reads an entire sweep structure from the input stream fp. RSL_read_sweep calls RSL_read_ray for the number of rays, sweep->h.nrays, as determined by reading fp. Memory is allocated via RSL_new_sweep. + +

RSL_read_ray reads an entire ray structure from the input stream fp. RSL_read_ray ingests an entire ray of data and sets ray->h.nbins. Memory is allocated via RSL_new_ray. +


+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+Example
+RSL_new_volume, RSL_new_sweep, RSL_new_ray,
+RSL_write_volume, RSL_write_sweep, RSL_write_ray,
+RSL_read_radar, RSL_write_radar,
+File format. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_read_histogram.html b/doc/RSL_read_histogram.html new file mode 100644 index 0000000..194874a --- /dev/null +++ b/doc/RSL_read_histogram.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_read_histogram

+ +
+ +

Synopsis

+#include "rsl.h"
+Histogram *RSL_read_histogram(char *infile);
+
+ +

Description

+Read the structure Histogram from the disk file infile. +
+ +

Return value

+ +Upon successful completion, a pointer to Histogram is returned. NULL is returned if an error occurs and errno is set. +
+

See also

+RSL_write_histogram +
+ +

Author: David B. Wolff + diff --git a/doc/RSL_read_radar.html b/doc/RSL_read_radar.html new file mode 100644 index 0000000..3e5ab3d --- /dev/null +++ b/doc/RSL_read_radar.html @@ -0,0 +1,33 @@ + + + + + +


+ + +

RSL_read_radar

+ +
+ +

Synopsis

+#include "rsl.h"
+Radar *RSL_read_radar(char *filename); + +

+
Description

+Read the Radar structure from disk. This is the inverse function of RSL_write_radar. The input file may be compressed. If the data is compressed, it is passed through the GNU gunzip filter. Thus, compressed data can be any format that gzip understands. Space for the Radar structure is obtained via calls to the volume routines: RSL_new_volume, RSL_new_sweep, and RSL_new_ray, which obtain their space via the routine malloc. +
+ +

Return value

+Upon successful completion, a Radar structure is returned. Otherwise, NULL. +
+ +

See also

+RSL_read_volume, RSL_read_sweep, RSL_read_ray,
+RSL_write_volume, RSL_write_sweep, RSL_write_ray,
+RSL_read_radar, File format, RSL_anyformat_to_radar +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_read_these_sweeps.html b/doc/RSL_read_these_sweeps.html new file mode 100644 index 0000000..0b690ba --- /dev/null +++ b/doc/RSL_read_these_sweeps.html @@ -0,0 +1,64 @@ + + + + + + +  +


+
  +
  +

+RSL_read_these_sweeps

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_read_these_sweeps(char *sweep#, [char *sweep#...], NULL); +
+
+

+Description

+Call this routine prior to any ingest routine and only the sweeps specified +will be stored in memory.  This drastically reduces memory requirements +and speeds up the ingest, especially, if you're only interesed in a few +sweeps.  This function is useful, for instance, when you're making +images of the base sweeps.  Why bother reading the entire file when +you only need the first sweep? By default, all sweeps are ingested.  +The sweep# is a character string representing the sweep number, "4" for +instance.  Order does not matter.  Specify NULL as the last argument. +This signals this routine when to stop parsing  for sweep numbers.  +The first sweep is "0". + +

The list of possible sweep numbers is: "all", "none", "0", "1", ... + +

Action or side-effects: A second call to this function over-rides any +previous settings. In other words, multiple calls are not additive.  +Therefore, you must list all the sweeps you want in a single call. + +

RSL_read_these_sweeps("1", "2", NULL); + +

which  reads the second and third sweep is not the same as: + +

RSL_read_these_sweeps("1", NULL); +
RSL_read_these_sweeps("2", NULL); + +

wherein, only the third (index 2) sweep is ingested. +
  + +

+


+

+Return value

+Upon successful completion, RSL_read_these_sweeps silently sets a hidden +array that each of the specific radar format ingest routines access. +
+
+

+See also

+RSL_anyformat_to_radar. +
+
Author: John H. Merritt. + + diff --git a/doc/RSL_rebin.html b/doc/RSL_rebin.html new file mode 100644 index 0000000..356483c --- /dev/null +++ b/doc/RSL_rebin.html @@ -0,0 +1,52 @@ + + + + + RSL_rebin... + + +  +
+

+RSL_rebin_...

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_rebin_ray(Ray *r, int +width); +
void RSL_rebin_sweep(Sweep *s, +int width); +
void RSL_rebin_volume(Volume +*v, int width); +

+ +
Description

+Rebin the data from -width to +width, centered at 0, to a positive value, +such that -width corresponds to 1, and +width corresponds to the value +2*width+1. + +

NOTE: This function modifies its argument: Ray, Sweep, or Volume. Use +this function prior RSL_sweep_to_cart. +The actual binning is done in RSL_rebin_ray.  +


+

+Return value

+None.  +
+

+See also

+RSL_sweep_to_gif, RSL_sweep_to_pict, +RSL_sweep_to_pgm, RSL_sweep_to_ppm, +
RSL_load_color_table, RSL_load_green_table, +RSL_load_red_table, RSL_load_blue_table, +
RSL_load_refl_color_table, +RSL_load_sw_color_table, RSL_load_vel_color_table, +
RSL_volume_to_gif, RSL_volume_to_pict, +RSL_volume_to_pgm, RSL_volume_to_ppm.  +
+ +

Author: David B. Wolff + + diff --git a/doc/RSL_rebin_velocity.html b/doc/RSL_rebin_velocity.html new file mode 100644 index 0000000..1083086 --- /dev/null +++ b/doc/RSL_rebin_velocity.html @@ -0,0 +1,49 @@ + + + + + + + + +


+

+RSL_rebin_velocity...

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_rebin_velocity_ray(Ray +*r); +
void RSL_rebin_velocity_sweep(Sweep +*s); +
void RSL_rebin_velocity_volume(Volume +*v); +

+ +
Description

+Rebin the velocity data to the range -nyquist, +nyquist. 14 bins are created +centered at 0. It sets the proper color look up indexes. This function +modifies Volume v. Use this function prior RSL_sweep_to_cart. +The binning is done in RSL_rebin_velocity_ray.  +
+

+Return value

+None.  +
+

+See also

+RSL_sweep_to_gif, RSL_sweep_to_pict, +RSL_sweep_to_pgm, RSL_sweep_to_ppm, +
RSL_load_color_table, RSL_load_green_table, +RSL_load_red_table, RSL_load_blue_table, +
RSL_load_refl_color_table, +RSL_load_sw_color_table, RSL_load_vel_color_table, +
RSL_volume_to_gif, RSL_volume_to_pict, +RSL_volume_to_pgm, RSL_volume_to_ppm, +
RSL_get_color_table, RSL_set_color_table. +
+

Author: John H. Merritt + + diff --git a/doc/RSL_return_eth_sweep.html b/doc/RSL_return_eth_sweep.html new file mode 100644 index 0000000..6ab7b02 --- /dev/null +++ b/doc/RSL_return_eth_sweep.html @@ -0,0 +1,48 @@ + + + + + + +


+ +

RSL_return_eth_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+Sweep *RSL_return_eth_sweep.html( +Vertical_structure *vs,int index); + + +
+

Description

+Given a Vertical_structure data structure created by +RSL_get_vertical_structure and a threshold index, return a Sweep data structure that contains echo top values. The threshold index corresponds +to the original set of threshold values used to create the +Vertical_structure. Index 0 is the first index. +
+ +

Return Value

+Upon seccesful completion, a pointer to a Sweep data structure is +returned. Otherwise a NULL pointer is returned. + +
+ +

See also

+RSL_return_zmax_sweep, +RSL_return_hzmax_sweep, +RSL_get_vertical_structure, +RSL_free_vertical_structure, +RSL_get_column, + + +
+ +

Author: Dennis Flanigan Jr. + + + + + diff --git a/doc/RSL_return_hzmax_sweep.html b/doc/RSL_return_hzmax_sweep.html new file mode 100644 index 0000000..8fcfd18 --- /dev/null +++ b/doc/RSL_return_hzmax_sweep.html @@ -0,0 +1,38 @@ + + + + + +


+ + +

RSL_return_hzmax_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+Sweep *RSL_return_hzmax_sweep.html( Vertical_structure *vs); +
+ +

Description

+Given a Vertical_structure created by RSL_get_vertical_structure, return a Sweep data structure that contains the height of the maximum dBz value found above the bins in the base sweep of a Volume of dBz data. +
+ +

Return Value

+Upon successful completion, a pointer to a Sweep data structure is returned. Otherwise a NULL pointer is returned. +
+ +

See also

+RSL_return_zmax_sweep, +RSL_return_eth_sweep, +RSL_get_vertical_structure, +RSL_free_vertical_structure, +RSL_get_column, + +
+ +

Author: Dennis Flanigan Jr. + + + diff --git a/doc/RSL_return_zmax_sweep.html b/doc/RSL_return_zmax_sweep.html new file mode 100644 index 0000000..04925f4 --- /dev/null +++ b/doc/RSL_return_zmax_sweep.html @@ -0,0 +1,47 @@ + + + + + +


+ +

RSL_return_zmax_sweep

+ +
+ +

Synopsis

+#include "rsl.h"
+Sweep *RSL_return_zmax_sweep.html( +Vertical_structure *vs); + + +
+

Description

+Given a Vertical_structure created by +RSL_get_vertical_structure, return a Sweep data structure +that contains the maximum dBz value found above the bins in the base +sweep of a Volume of dBz data. + +
+ +

Return Value

+Upon seccesful completion, a pointer to a Sweep data structure is +returned. Otherwise a NULL pointer is returned. + +
+ +

See also

+RSL_return_hzmax_sweep, +RSL_return_eth_sweep, +RSL_get_vertical_structure, +RSL_free_vertical_structure, +RSL_get_column, + +
+ +

Author: Dennis Flanigan Jr. + + + + + diff --git a/doc/RSL_reverse.html b/doc/RSL_reverse.html new file mode 100644 index 0000000..f86b4f6 --- /dev/null +++ b/doc/RSL_reverse.html @@ -0,0 +1,17 @@ + +
+


+ +

RSL_reverse_sweep_order

+

Synopsis

+#include "rsl.h"
+
Volume *RSL_reverse_sweep_order(Volume *v)
+

Description

+Reverses the order of the sweeps in a Volume. This function is most useful if the original ingested file provided the sweep elevation angles from high to low. This routine alters the input Volume v. +


Return value

+Upon successful completion, RSL_reverse_sweep_order returns a pointer to the structure Volume. Otherwise, NULL is returned.
+

See also

+RSL_sort_volume
+
Author: John H. Merritt. + + diff --git a/doc/RSL_select_fields.html b/doc/RSL_select_fields.html new file mode 100644 index 0000000..456b476 --- /dev/null +++ b/doc/RSL_select_fields.html @@ -0,0 +1,71 @@ + + + + + + + + +

+ +


+ +


+

+ +

RSL_select_fields

+ +

+


+ +

Synopsis

+ +

#include "rsl.h"
+void RSL_select_fields(char *field_type, [char *field_type...], NULL);

+ +


+ +

Description

+ +

Call this routine prior to any ingest routine and only the field types +specified will be ingested. The drastically reduces memory requirements, +especially if you're only interesed in one field type. Lassen, for instance, +can have more than 5 field types which collectively can occupy an enormous +amount of memory. By default, all field types are ingested. field_type +is not case sensitive. Specify NULL as the last argument. This signals +this routine when to stop parsing the field types.

+ +

The list of possible field types is: "all", "none", +"dz", "vr" "cz", "zt", "dr", +"lr", "zd", "dm", "rh", "ph", +"xz", "cd", "mz", "md", "ze", +"ve", "kd", "ti".

+ +

Action or side-effects: A second call to this function over-rides any +previous settings. In other words, multiple calls are not additive. So, +to get both DZ and VR volumes, use:
+RSL_select_fields("dz", "vr", NULL); -- Read both DZ +and VR.
+and not:
+RSL_select_fields("dz", NULL); -- Read only DZ.
+RSL_select_fields("vr", NULL); -- Read only VR, no DZ.

+ +


+ +


+ +

Return value

+ +

Upon successful completion, RSL_select_fields silently sets a hidden +array that RSL_anyformat_to_radar accesses for memory allocation.
+ +


+ +

See also

+ +

RSL_anyformat_to_radar.
+ +


Author: John H. Merritt.

+ + + diff --git a/doc/RSL_set_hdf_qc_parameters.html b/doc/RSL_set_hdf_qc_parameters.html new file mode 100644 index 0000000..a3005ce --- /dev/null +++ b/doc/RSL_set_hdf_qc_parameters.html @@ -0,0 +1,46 @@ + + + + + + + + +
+ +

RSL_set_hdf_qc_parameters

+ +

+


+ +

Synopsis

+ +

#include "rsl.h"
+void RSL_set_hdf_qc_parameters(float hfreeze, float dbznoise, float hthresh1, +float hthresh2, float hthresh3, float zthresh1, float zthresh2, float zthresh3, +char *outfile);
+


+ +

Description

+ +

Initializes paramters prior to a call to RSL_radar_to_hdf.

+ +

+


+ +

Return value

+ +

None. +


+ +

See also

+ +

RSL_anyformat_to_radar

+ +

RSL_radar_to_hdf +


+ +

Author: Mike Kolander.

+ + + diff --git a/doc/RSL_sort.html b/doc/RSL_sort.html new file mode 100644 index 0000000..7773a32 --- /dev/null +++ b/doc/RSL_sort.html @@ -0,0 +1,41 @@ + + + + + +
+ + +

RSL_sort_...

+ +
+ +

Synopsis

+#include "rsl.h"
+Radar *RSL_sort_radar(Radar *r);
+Volume *RSL_sort_sweeps_in_volume(Volume *v);
+Volume *RSL_sort_volume(Volume *v);
+Sweep *RSL_sort_rays_by_time(Sweep *s);

+Sweep
*RSL_sort_rays_in_sweep(Sweep *s);
+Volume *RSL_sort_rays_in_volume(Volume *v);
+ +

+
Description

+RSL_sort_radar calls RSL_sort_volume for the number of volumes. + +

RSL_sort_volume calls RSL_sort_sweeps_in_volume, then calls RSL_sort_rays_in_volume. This yields a completely sorted, by elevation angle and by azimuth angle, volume. + +

RSL_sort_sweeps_in_volume only orders the sweeps by elevation angle. It does not sort the rays by azimuth angle. + +

RSL_sort_rays_in_sweep orders the rays by azimuth angle: 0 through 360 degrees.
+RSL_sort_rays_in_volume orders the rays in each sweep by calling sort_rays_in_sweep for the number of sweeps. RSL_sort_rays_in_sweep sorts the rays by azimuth angle placing the the smallest azimuth angle first. The input volume or sweep structure is modified and a pointer to the newly organized structure is returned. + +

RSL_sort_rays_by_time orders the rays in a sweep by time. +


+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

Author: Dennis Flanigan Jr. + diff --git a/doc/RSL_structures.html b/doc/RSL_structures.html new file mode 100644 index 0000000..aff40f6 --- /dev/null +++ b/doc/RSL_structures.html @@ -0,0 +1,27 @@ + + + + + + +  +


These are the structures of RSL. + +

Azimuth_hash +
Cappi +
Carpi +
Cube +
Er_loc +
Hash_table +
Histogram +
Radar +
Radar_header +
Range +
Ray +
Ray_header +
Sweep +
Sweep_header +
Volume +
Volume_header + + diff --git a/doc/RSL_sweep_header_struct.html b/doc/RSL_sweep_header_struct.html new file mode 100644 index 0000000..d072dbd --- /dev/null +++ b/doc/RSL_sweep_header_struct.html @@ -0,0 +1,20 @@ + + + + + +


+ + +
typedef struct {
+  int sweep_num;      /* Integer sweep number. */
+  float elev;         /* Elevation angle (mean) for the sweep. */
+  float beam_width;   /* This is in the ray header too. */
+  float vert_half_bw; /* Vertical beam width divided by 2 */
+  float horz_half_bw; /* Horizontal beam width divided by 2 */
+  int nrays;
+  float (*f)(Range x); /* Data conversion function. f(x). */
+  Range (*invf)(float x); /* Data conversion function. invf(x). */ 
+} Sweep_header; 
+ + diff --git a/doc/RSL_sweep_struct.html b/doc/RSL_sweep_struct.html new file mode 100644 index 0000000..5b7ff79 --- /dev/null +++ b/doc/RSL_sweep_struct.html @@ -0,0 +1,13 @@ + + + + + +
+ + +
typedef struct {
+  Sweep_header h;
+  Ray **ray; /* ray[0..nrays-1]. */
+} Sweep; 
+ diff --git a/doc/RSL_sweep_to.html b/doc/RSL_sweep_to.html new file mode 100644 index 0000000..d694d87 --- /dev/null +++ b/doc/RSL_sweep_to.html @@ -0,0 +1,73 @@ + + + + + + + + +
+

+RSL_sweep_to...

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_sweep_to_gif(Sweep +*s, char *outfile, int xdim, int ydim, float range); +
void RSL_sweep_to_pict(Sweep +*s, char *outfile, int xdim, int ydim, float range); +
void RSL_sweep_to_pgm(Sweep +*s, char *outfile, int xdim, int ydim, float range); +
void RSL_sweep_to_ppm(Sweep +*s, char *outfile, int xdim, int ydim, float range); +

+ +
Description

+RSL_sweep_to_gif: Given a Sweep pointer, s, output a GIF +image with the filename specified in outfile. This function calls +RSL_sweep_to_cart +to do the polar to cartesean mapping, then calls RSL_write_gif. +When making images of velocity data, it may be necessary to call RSL_rebin_velocity_sweep +to rebin the values from -nyquist to +nyquist. +

RSL_sweep_to_pict: Identical to RSL_sweep_to_gif except it outputs +a PICT file, by calling RSL_write_pict. +

RSL_sweep_to_ppm: Identical to RSL_sweep_to_gif except it outputs +a PICT file, by calling RSL_write_ppm. +

RSL_sweep_to_pgm: Identical to RSL_sweep_to_gif except it outputs +a PICT file, by calling RSL_write_pgm. +

Efficiency note: The functions RSL_volume_to_gif and RSL_volume_to_pict. +and any other output formats that may arrise, all function identically +with the only difference being the output pipe command (ppmtogif, ppmtopict, +etc.). Each routine performs a polar to cartesean mapping via RSL_sweep_to_cart, +then calls the appropriate write function. If you plan to output many image +formats at once, it will be wise to perform the polar to cartesean mapping +once, then call RSL_write_gif, RSL_write_pict, etc. This could be done, +for instance, in a function called RSL_volume_to_pict_and_gif.  +


+

+Return value

+None.  +
+

+See also

+RSL_rebin_velocity_ray, RSL_rebin_velocity_sweep, +RSL_rebin_velocity_volume, +
RSL_sweep_to_gif, RSL_sweep_to_pict, +Vsweep_to_pgm, +Vsweep_to_ppm, +
RSL_load_color_table, RSL_load_green_table, +RSL_load_red_table, +RSL_load_blue_table, +
RSL_load_refl_color_table, +RSL_load_sw_color_table, +RSL_load_vel_color_table, +
RSL_volume_to_gif, RSL_volume_to_pict, +RSL_volume_to_pgm, +RSL_volume_to_ppm. +
RSL_get_color_table, RSL_set_color_table. +
+

Author: John H. Merritt + + diff --git a/doc/RSL_sweep_to_cart.html b/doc/RSL_sweep_to_cart.html new file mode 100644 index 0000000..441cf4c --- /dev/null +++ b/doc/RSL_sweep_to_cart.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_sweep_to_cart

+ +
+ +

Synopsis

+#include "rsl.h"
+unsigned char *RSL_sweep_to_cart(Sweep *s, int xdim, int ydim, float range); + +

+
Description

+Given a Sweep pointer, s, return a character image of size xdim by ydim representing the mapping of polar to cartesean with the radar at the center of the image. The radial range, range, is mapped to the edge of the image. The space for the returned images is obtained via malloc. It is assumed that range is in units of gate size. +
+ +

Return value

+Upon successful completion a valid pointer to unsigned char is returned, otherwise NULL. +
+ +

See also

+RSL_sweep_to_gif, RSL_sweep_to_pict, RSL_sweep_to_pgm, RSL_sweep_to_ppm +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_toga_to_radar.html b/doc/RSL_toga_to_radar.html new file mode 100644 index 0000000..8b20058 --- /dev/null +++ b/doc/RSL_toga_to_radar.html @@ -0,0 +1,33 @@ + + + + + +


+ + +

RSL_toga_to_radar

+ +
+ +

Synopsis

+#include "rsl.h"
+Radar *RSL_toga_to_radar(char *infile);
+
+ +

Description

+Reads a TOGA file and returns a pointer to the structure Radar. The inpile is specified by the string infile. If infile is NULL, then stdin is read. The input file may be compressed. If the data is compressed, it is passed through the GNU gunzip filter. Thus, compressed data can be any format that gzip understands. + +

The radar structure is, essentially, an array of Volumes. The type of volumes returned is automatically determined from the input file. +


+ +

Return value

+Upon successful completion, RSL_toga_to_radar returns a pointer to the structure Radar. Otherwise, NULL is returned and errno is set. +
+ +

See also

+RSL_anyformat_to_radar +
+ +

Author: Mike Kolander. + diff --git a/doc/RSL_uf_to_radar.html b/doc/RSL_uf_to_radar.html new file mode 100644 index 0000000..6cc38ec --- /dev/null +++ b/doc/RSL_uf_to_radar.html @@ -0,0 +1,37 @@ + + + + + +


+ + +

RSL_uf_to_radar

+ + +

RSL_uf_to_radar_fp

+ +
+ +

Synopsis

+#include "rsl.h"
+Radar *RSL_uf_to_radar(char *infile);
+Radar *RSL_uf_to_radar_fp(FILE *fp); +
+ +

Description

+Read a UF (Universal Format) file and return a pointer to the structure Radar. The input file is specified by the string infile. RSL_uf_to_radar calls RSL_uf_to_radar_fp which is provided as a means of constructing filter programs -- reading stdio, for instance. If infile is NULL, then stdin is used. RSL_uf_to_radar_fp checks the UF magic information to ensure that a valid UF file is being read. The input file may be compressed. If the data is compressed, it is passed through the GNU gunzip filter. Thus, compressed data can be any format that gzip understands. It can handle true UF files, as well as, UF files with 2 and 4 byte Fortran record delimeters. These routines work on big and little endian machines, provided that the input UF file is in big endian format. RSL_radar_to_uf creates UF files in big endian format when run on either big or little endian machines; by definition UF files are in big endian format. + +

The radar structure is, essentially, an array of Volumes. The number and type of volumes allocated is automatically determined from the input UF file. No UF library needed; the UF code is part of RSL. +


+ +

Return value

+Upon successful completion, RSL_uf_to_radar returns a pointer to the structure Radar. Otherwise, NULL is returned and errno is set. +
+ +

See also

+RSL_anyformat_to_radar, RSL_radar_to_uf +
+ +

Author: John H. Merritt. + diff --git a/doc/RSL_volume_header_struct.html b/doc/RSL_volume_header_struct.html new file mode 100644 index 0000000..3cbbc3c --- /dev/null +++ b/doc/RSL_volume_header_struct.html @@ -0,0 +1,18 @@ + + + + + +


+ + +
typedef struct {
+  char *type_str;  /* One of:'Reflectivity', 'Velocity' or 'Spectrum width' */
+  int nsweeps;
+        float calibr_const;        /* Calibration constant. */
+  float (*f)(Range x);       /* Data conversion function. f(x). */
+  Range (*invf)(float x);    /* Data conversion function. invf(x). */
+} Volume_header;
+
+ + diff --git a/doc/RSL_volume_struct.html b/doc/RSL_volume_struct.html new file mode 100644 index 0000000..31bca70 --- /dev/null +++ b/doc/RSL_volume_struct.html @@ -0,0 +1,14 @@ + + + + + +
+ + +
typedef struct {
+  Volume_header h; /* Specific info for each elev. */
+                   /* Includes resolution: km/bin. */
+  Sweep **sweep;   /* sweep[0..nsweeps-1]. */
+} Volume; 
+ diff --git a/doc/RSL_volume_to.html b/doc/RSL_volume_to.html new file mode 100644 index 0000000..d40f29d --- /dev/null +++ b/doc/RSL_volume_to.html @@ -0,0 +1,69 @@ + + + + + + + + +
+

+RSL_volume_to...

+ +
+

+Synopsis

+#include "rsl.h" +
void RSL_volume_to_gif(Volume +*v, char *basename, int xdim, int ydim, float range); +
void RSL_volume_to_pict(Volume +*v, char *basename, int xdim, int ydim, float range) ; +
void RSL_volume_to_pgm(Volume +*v, char *basename, int xdim, int ydim, float range); +
void RSL_volume_to_ppm(Volume +*v, char *basename, int xdim, int ydim, float range); +

+ +
Description

+RSL_volume_to_gif: Given a Volume pointer, v, output a series +of GIF images. Output filenames are basename.00.gif, basename.01.gif, +etc., for the number of sweeps. It calls RSL_sweep_to_gif +once for each sweep. When making images of velocity data, it may be necessary +to call RSL_rebin_velocity_sweep +to rebin the values from -nyquist to +nyquist. +

RSL_volume_to_pict: Identical to RSL_volume_to_gif except it +writes PICT files. +

RSL_volume_to_ppm: Identical to RSL_volume_to_gif except it writes +PPM files. +

RSL_volume_to_pgm: Identical to RSL_volume_to_gif except it writes +PGM files. +

Efficiency note: The functions RSL_volume_to_gif and RSL_volume_to_pict. +and any other output formats that may arrise, all function identically +with the only difference being the output pipe command (ppmtogif, ppmtopict, +etc.). Each routine performs a polar to cartesean mapping via RSL_sweep_to_cart, +then calls the appropriate write function. If you plan to output many image +formats at once, it will be wise to perform the polar to cartesean mapping +once, then call RSL_write_gif, RSL_write_pict, etc. This could be done, +for instance, in a function called RSL_volume_to_pict_and_gif.  +


+

+Return value

+None.  +
+

+See also

+RSL_rebin_velocity_ray, RSL_rebin_velocity_sweep, +RSL_rebin_velocity_volume, +
RSL_sweep_to_gif, RSL_sweep_to_pict, +RSL_sweep_to_pgm, RSL_sweep_to_ppm, +
RSL_load_color_table, RSL_load_green_table, +RSL_load_red_table, RSL_load_blue_table, +
RSL_load_refl_color_table, +RSL_load_sw_color_table, RSL_load_vel_color_table, +
RSL_volume_to_gif, RSL_volume_to_pict, +RSL_volume_to_pgm, RSL_volume_to_ppm, +
RSL_get_color_table, RSL_set_color_table. +
+

Author: John H. Merritt + + diff --git a/doc/RSL_volume_to_carpi.html b/doc/RSL_volume_to_carpi.html new file mode 100644 index 0000000..39abb36 --- /dev/null +++ b/doc/RSL_volume_to_carpi.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_volume_to_carpi

+ +
+ +

Synopsis

+#include "rsl.h"
+Carpi *RSL_volume_to_carpi(Volume *v, float h, float grnd_r, float dx, float dy, int nx, int ny, int radar_x, int radar_y, float lat, float lon); + +

+
Description

+Produce a Constant Altitude Rectangular from Polar Image at h out to the maximum ground range grnd_range. h and grnd_range are expressed in km. The dimensions of the Carpi are given by nx and ny. radar_x and radar_y are the location of the radar within the Carpi structure (the rectangular grid). lat and lon represent the lower left corner (SE) of the rectangular grid. This routine first creates a Cappi. It allocates space for the resulting Carpi when it calls RSL_cappi_to_carpi. +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+RSL_free_cappi, RSL_cappi_to_carpi, Carpi, Cappi, RSL_new_cappi. + +

+


Author: Mike Kolander + diff --git a/doc/RSL_volume_to_cube.html b/doc/RSL_volume_to_cube.html new file mode 100644 index 0000000..72c286e --- /dev/null +++ b/doc/RSL_volume_to_cube.html @@ -0,0 +1,36 @@ + + + + + +
+ + +

RSL_volume_to_cube

+ +
+ +

Synopsis

+#include "rsl.h"
+Cube *RSL_volume_to_cube(Volume *v, float dx, float dy, float dz, int nx, int ny, int nz, float grnd_r, int radar_x, int radar_y, int radar_z) + +

+
Description

+Convert polar coordinate Volume v into cube cartesean coordinates. This routine allocates space for the cube header and an array of pointers to carpi's. The routine RSL_volume_to_carpi is called for each dz. + +

dx, dy, dz specify the kilometer resolution of each cubic cell.
+nx, ny, nz specify the cube dimensions.
+grnd_r specifies the maximum ground range to load from the volume.
+radar_x, radar_y, radar_z specify the location within the cube for the radar. Typically, radar_z equals 0 as there is no data below the radar. Specify dx/2 and dy/2 for radar_x and radar_y to center the radar within the cube. +


+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

See also

+RSL_get_slice_from_cube, RSL_volume_to_carpi + +

+


Author: Mike Kolander + diff --git a/doc/RSL_write.html b/doc/RSL_write.html new file mode 100644 index 0000000..363c924 --- /dev/null +++ b/doc/RSL_write.html @@ -0,0 +1,40 @@ + + + + + +
+ + +

RSL_write...

+
+ +

Synopsis

+#include "rsl.h"
+void RSL_write_gif(char *outfile, unsigned char *image, int xdim, int ydim, char c_t able[256][3]);
+void RSL_write_pict(char *outfile, unsigned char *image, int xdim, int ydim, char c_table[256][3]);
+void RSL_write_pgm(char *outfile, unsigned char *image, int xdim, int ydim);
+void RSL_write_ppm(char *outfile, unsigned char *image, int xdim, int ydim, char c_table[256][3]);
+ +

+
Description

+RSL_write_gif: Writes a GIF file. It uses ppmtogif to convert the image to GIF format, via a pipe.
+RSL_write_pict: Writes a PPM image file.
+RSL_write_pgm: Writes a PGM image file.
+RSL_write_ppm: Writes a PICT image file. It uses ppmtopict to convert the image to PICT format, via a pipe. This is only the image portion of a PICT formated file. Additional programs, like mcvert (when I get it I will automatically place it in the pipeline), need to be run so they are viewable on a MAC. +
+ +

Return value

+None. +
+ +

See also

+RSL_rebin_velocity_ray, RSL_rebin_velocity_sweep, RSL_rebin_velocity_volume,
+RSL_sweep_to_gif, RSL_sweep_to_pict, RSL_sweep_to_pgm, RSL_sweep_to_ppm,
+RSL_load_color_table, RSL_load_green_table, RSL_load_red_table, RSL_load_blue_table,
+RSL_load_refl_color_table, RSL_load_sw_color_table, RSL_load_vel_color_table,
+RSL_volume_to_gif, RSL_volume_to_pict, RSL_volume_to_pgm, RSL_volume_to_ppm. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_write_histogram.html b/doc/RSL_write_histogram.html new file mode 100644 index 0000000..a27c36a --- /dev/null +++ b/doc/RSL_write_histogram.html @@ -0,0 +1,31 @@ + + + + + +


+ + +

RSL_write_histogram

+ +
+ +

Synopsis

+#include "rsl.h"
+void RSL_write_histogram(Histogram *histogram, char *outfile);
+
+ +

Description

+Output the structure Histogram to the disk file outfile. +
+ +

Return value

+Upon successful completion, the number of words written is returned. On error, -1 is returned and errno is set. +
+ +

See also

+RSL_read_histogram +
+ +

Author: David B. Wolff + diff --git a/doc/RSL_write_radar.html b/doc/RSL_write_radar.html new file mode 100644 index 0000000..9812012 --- /dev/null +++ b/doc/RSL_write_radar.html @@ -0,0 +1,41 @@ + + + + + +


+ + +

RSL_write_radar

+ + +

RSL_write_radar_fp

+ + +

RSL_write_radar_gzip

+ +
+ +

Synopsis

+#include "rsl.h"
+int RSL_write_radar(Radar *radar, char *outfile);
+int RSL_write_radar_fp(Radar *radar, FILE *fp);
+int RSL_write_radar_gzip(Radar *radar, char *outfile); + +

+
Description

+Save the Radar structure to disk. This is useful when it take some effort or time to build the Radar structure from data; you can save the Radar as an intermediate result of processing. RSL_write_radar_gzip writes gzip-ed files by passing the data through GNU gzip. +
+ +

Return value

+Upon successful completion, the number of bytes written is returned. +
+ +

See also

+RSL_read_volume, RSL_read_sweep, RSL_read_ray,
+RSL_write_volume, RSL_write_sweep, RSL_write_ray,
+RSL_read_radar, File format. +
+ +

Author: John H. Merritt + diff --git a/doc/RSL_wsr88d_to_radar.html b/doc/RSL_wsr88d_to_radar.html new file mode 100644 index 0000000..9b131b4 --- /dev/null +++ b/doc/RSL_wsr88d_to_radar.html @@ -0,0 +1,33 @@ + + + + + +


+ + +

RSL_wsr88d_to_radar

+ +
+ +

Synopsis

+#include "rsl.h"
+Radar *RSL_wsr88d_to_radar(char *infile, char *callid_or_first_file);
+
+ +

Description

+Reads a wsr88d (NEXRAD) file and returns a pointer to the Radar structure. The input file is specified by the string infile. If infile is NULL, then stdin is read. The input file may be compressed. If the data is compressed, it is passed through the GNU gunzip filter. Thus, compressed data can be any format that gzip understands. + +

The radar structure is, essentially, an array of Volumes. These volumes represent the reflectivity, velocity and spectrum width fields. The string callid_or_first_file contains the filename of the first extracted file from the NEXRAD tape or contains the 4 character callid (eg. KMLB). The first file on the tape is the only place where the site information is stored. A warning will be issued if it is detected that the file callid_or_first_file is not a proper NEXRAD tape header file. +


+ +

Return value

+Upon successful completion, RSL_wsr88d_to_radar returns a pointer to the structure Radar. Otherwise, NULL is returned. A valid Radar structure will be returned if the infile is valid, dispite callid_or_first_file being invalid. Thus, it is not required to have callid_or_first_file. +
+ +

See also

+RSL_anyformat_to_radar +
+ +

Author: John H. Merritt. + diff --git a/doc/RSL_z_to_r.html b/doc/RSL_z_to_r.html new file mode 100644 index 0000000..dc9ee0b --- /dev/null +++ b/doc/RSL_z_to_r.html @@ -0,0 +1,30 @@ + + + + + +


+ + +

RSL_...z_to_r

+ +
+ +

Synopsis

+#include "rsl.h"
+float RSL_z_to_r(float dbz, float k, float a);
+Ray *RSL_ray_z_to_r(Volume *z_volume, float k, float a);
+Sweep *RSL_sweep_z_to_r(Sweep *z_sweep, float k, float a);
+Volume *RSL_volume_z_to_r(Ray *z_ray, float k, float a);
+ +

+
Description

+RSL_volume_z_to_r calls RSL_sweep_z_to_r for the number of sweeps. RSL_sweep_z_to_r calls RSL_ray_z_to_r for the number of rays. RSL_ray_z_to_r calls RSL_z_to_r for the number of bins in the ray. RSL_z_to_r computes the function 1/a*(dbz - 10*log10(k)). +
+ +

Return value

+Upon successful completion, a pointer to the appropriate structure is returned. Otherwise, a NULL pointer is returned and errno is set. +
+ +

Author: John H. Merritt + diff --git a/doc/alan.mcconnell.html b/doc/alan.mcconnell.html new file mode 100644 index 0000000..34f4004 --- /dev/null +++ b/doc/alan.mcconnell.html @@ -0,0 +1,9 @@ + + + + +Alan McConnell
+Pixel Analysis
+alan@pluvius.gsfc.nasa.gov.
+
+ diff --git a/doc/changes.gif b/doc/changes.gif new file mode 100644 index 0000000000000000000000000000000000000000..54443683f9453f462d9caa12e2b0938a47af5c4d GIT binary patch literal 4336 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 literal 0 HcmV?d00001 diff --git a/doc/david.wolff.html b/doc/david.wolff.html new file mode 100644 index 0000000..4526a0d --- /dev/null +++ b/doc/david.wolff.html @@ -0,0 +1,19 @@ + + + +

+

David B. Wolff

+
+
+

Science Systems & Applications, Inc.

+

David is the TRMM Ground Validation Program Manager. He serves as the leader of +both the data processing and science support teams at NASA/GSFC. He began working +with the GV group in May of 1988 after graduation from Texas A&M University. + +

+

E-mail: wolff@radar.gsfc.nasa.gov. +
+ +
+ diff --git a/doc/dennis.flanigan.html b/doc/dennis.flanigan.html new file mode 100644 index 0000000..9d11fcd --- /dev/null +++ b/doc/dennis.flanigan.html @@ -0,0 +1,9 @@ + + + + +Dennis Flanigan Jr.
+Applied Research Corporation
+flanigan@trmm.gsfc.nasa.gov.
+
+ diff --git a/doc/field_but.gif b/doc/field_but.gif new file mode 100644 index 0000000000000000000000000000000000000000..11fb86f7dfb97c97711fc659186b5afaa20ccf1b GIT binary patch literal 2737 zcmd6o`BzhS8i&7kNpiE{O$gzlR1*>~VQbiw#nPJ)NC++v5kur?5KshLWziyZxq*m) zECH!vO>IE1O4Y#@9G#IiD4<1)L8=F9Ya=c&PDgO5TH7;Bdiqby`}^nfJmWw+Z9KBAjQ|VMOs+h2tFnO3<>;{Pm zoWL<0{QphxpGtr3B8f3a#Q-6fh9Pu>orGZw1WTbMV_J;Gs-`n(v?P>{Rx=K~iTKsg z8KH?74bibtHeE}zvl{C` zuKTJyv4!?dE3@jDH;agVdK&WIBeF+tv7U1|n)B!^3&&arYEl2W0?u?P31I&yzW?!c z%SkBUO5}Hm)}4;}CYTb3TRR;bB1#98(n5o`1%~q`29Xp_a2X?6 zNv7WVJfuymqVs5XidQ^cZ|^X|uv(BxTK1)bc)wVM(^X|Y0$QWg=<0(JC>$##3Eg~4 z&*gANE=}Zrw=@rWdoSLjLY8pt6pNm&Xv1ZYlSJZV3N^HB2qh!9rFJL;q9W5^POlZ9 zKBa(U@Y7qUCEl$yN}gva%`r#kX~#Cd-BOYp z)x8AKru05MPykCGWj2g>q!~#R?6AZ< zlP9KRN_-|q*a1Wb6^zQ7g#qKH@!DWSnoaJs`j#~YxBPMDm$2CGN1sNqE-yt`jnu|L zMY~8m0xzEZb}g)(@U$dfL{9_6c{congj1uqf>k`Z=M#`XDDfD^VEA?D)AV(06>50i zI2S)=(l|0N22%iGn6HA6J3h_}%|%g*nJ&Vx-bX&V$hz8D1D;_ zpfe6{N-}!tGSx(+lMlaS)BsZ?@}mYqy-j58V(gDj%CB1BSVFPyCjcji7Nz2KKdv2^ zC(NCFoORH#3o;y*!!EUV>2`=&6ElwOko?3Y=V5uzAN+hJTHzHP6oe0a{q~K2mO(~UuzzlOF1vhL5ou(x}k6CDxE#=pIVRx z1?LtIuKX;&53nT)*E`R)=d zdns?u!!H-37=`ZGl?YZkkFT?+>C0t+MZdv(YhVxfc%zpq{)QZitX`G!>T=Ll^lY!4 z6hyjKH>__L-Z)wA5sh|5(#9;j?N^m?)!y*Kcb2Ia(FhZAw%7!KcL^+!JDD?Ceyk z(z};JG4YUE-ScMl{YujXmnE7mLf$*q6Vc{m_2(BcuU#!_IYR=@Lr;zVM6R$S(!o6O zfK&L(gYdtl?%v~k7N!VwtyRws!|PLFYkQT#@-G_q^29;Spi0?*4`tcP8Z*l_Z$M2H zzx1onk2=Nup@1H21>0!*l)w7=Ltt7&d zDU)6oQNN?peBE!W%Hm$e-QbA!_*7g9$<;s~@f>_QWO0gC<#kU{LP?T|*S=7zh&?@sO z1xsI@=ZTUMXkbNVo<;$Zwvy^lYCO{0UNz!%FK;Tld4H~=k|44XkJ)b?zKR8r2i`=BE%XAh)PtlfYEvXnq8$6$g5Kv!(C# zUWzNL#Qlkj3nWU^5MJ!@w$St;=lLDWYZfm{*t{(* zXS^fw0@)tJ4cPi*;lAf9nO7$lY?f(xW62cw!4GUmNL-`Kw6UY_lGlifOQ%HUtk~x6 zLD5~>p0?$FIIB*;36vHW2{*>WEaUf + + + + + + + +
+

+Index of RSL routines grouped by functionality.

+ +

+Input

+Radar *RSL_anyformat_to_radar(char +*infile [, char *callid_or_first_file]); +
Radar *RSL_edge_to_radar(char *infile); +
Radar *RSL_kwaj_to_radar(char *infile); +
Radar *RSL_lassen_to_radar(char +*infile); +
Radar *RSL_mcgill_to_radar(char +*infile); +
Radar *RSL_nsig_to_radar(char *infile); +
Radar *RSL_nsig2_to_radar(char *infile); +
Radar *RSL_radtec_to_radar(char +*infile); +
Radar *RSL_rapic_to_radar(char *infile); +
Radar *RSL_read_radar(char *infile); +
Radar *RSL_toga_to_radar(char *infile); +
Radar *RSL_uf_to_radar(char *infile); +
Radar *RSL_uf_to_radar_fp(FILE *fp); +
Radar *RSL_wsr88d_to_radar(char +*infile, char *callid_or_first_file); +
Volume *RSL_read_volume(FILE *fp); +
Sweep *RSL_read_sweep (FILE *fp); +
Ray *RSL_read_ray (FILE *fp); +
void RSL_read_these_sweeps(char +*sweep#, ..., NULL); +
void RSL_select_fields(char *field_type, +..., NULL); +
void RSL_set_kwaj_parameters(float +mds, float calibr_slope, float calibr_intercept); +
void RSL_radar_verbose_off(void); +
void RSL_radar_verbose_on(void); +

+Output

+void RSL_radar_to_uf(Radar *r, char *outfile); +
void RSL_radar_to_uf_fp(Radar *r, FILE +*fp); +
void RSL_radar_to_uf_gzip(Radar *r, +char *outfile); +
int RSL_write_histogram(Histogram +*histogram, char *outfile); +
int RSL_write_ray(Ray *r, FILE *fp); +
int RSL_write_sweep(Sweep *s, FILE *fp); +
int RSL_write_volume(Volume *v, FILE *fp); +
int RSL_write_histogram(Histogram +*histogram, char *outfile); +
int RSL_write_radar(Radar *radar, char +*outfile); +
int RSL_write_radar_fp(Radar *radar, +FILE *fp); +
int RSL_write_radar_gzip(Radar *radar, +char *outfile); +
void RSL_print_version(void); +

+Memory management

+Radar *RSL_new_radar(int nvolumes); +
Radar *RSL_prune_radar(Radar *radar); +
Radar *RSL_sort_radar(Radar *r); +
Volume *RSL_clear_volume(Volume *v); +
Volume *RSL_copy_volume(Volume *v); +
Volume *RSL_new_volume(int max_sweeps); +
Volume *RSL_prune_volume(Volume *v); +
Sweep *RSL_clear_sweep(Sweep *s); +
Sweep *RSL_copy_sweep(Sweep *s); +
Sweep *RSL_new_sweep(int max_rays); +
Sweep *RSL_prune_sweep(Sweep *s); +
Ray *RSL_clear_ray(Ray *r); +
Ray *RSL_copy_ray(Ray *r); +
Ray *RSL_new_ray(int max_bins); +
Ray *RSL_prune_ray(Ray *ray); +
Cappi *RSL_new_cappi(Sweep *sweep, float +height); +
Carpi *RSL_new_carpi(int xdim, int ydim); +
void RSL_free_cappi(Cappi *c); +
void RSL_free_histogram(Histogram +*histogram); +
void RSL_free_radar(Radar *r); +
void RSL_free_ray(Ray *r); +
void RSL_free_sweep(Sweep *s); +
void RSL_free_volume(Volume *v); +

+Image generation

+void RSL_bscan_ray(Ray *r, FILE *fp); +
void RSL_bscan_sweep(Sweep *s, char *outfile); +
void RSL_bscan_volume(Volume *v, char *basename); +
void RSL_get_color_table(int icolor, +char buffer[256], int *ncolors); +
void RSL_set_color_table(int icolor, +char buffer[256], int *ncolors); +
void RSL_load_color_table(char +*infile, char buffer[256], int *ncolors); +
void RSL_load_green_table(char +*infile); +
void RSL_load_blue_table(char *infile); +
void RSL_load_height_color_table(); +
void RSL_load_rainfall_color_table(); +
void RSL_load_red_table(char *infile); +
void RSL_load_refl_color_table(); +
void RSL_load_sw_color_table(); +
void RSL_load_vel_color_table(); +
void RSL_load_zdr_color_table(); +
void RSL_rebin_velocity_ray(Ray *r); +
void RSL_rebin_velocity_sweep(Sweep +*s); +
void RSL_rebin_velocity_volume(Volume +*v); +
void RSL_rebin_ray(Ray *r); +
void RSL_rebin_sweep(Sweep *s); +
void RSL_rebin_volume(Volume *v); +
void RSL_sweep_to_gif(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_sweep_to_pgm(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_sweep_to_pict(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_sweep_to_ppm(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_volume_to_gif(Volume *v, char +*basename, int xdim, int ydim, float range); +
void RSL_volume_to_pgm(Volume *v, char +*basename, int xdim, int ydim, float range); +
void RSL_volume_to_pict(Volume *v, char +*basename, int xdim, int ydim, float range) ; +
void RSL_volume_to_ppm(Volume *v, char +*basename, int xdim, int ydim, float range); +
void RSL_write_gif(char *outfile, unsigned +char *image, int xdim, int ydim, char c_t able[256][3]); +
void RSL_write_pict(char *outfile, unsigned +char *image, int xdim, int ydim, char c_ table[256][3]); +
void RSL_write_pgm(char *outfile, unsigned +char *image, int xdim, int ydim); +
void RSL_write_ppm(char *outfile, unsigned +char *image, int xdim, int ydim, char c_t able[256][3]); +
unsigned char *RSL_sweep_to_cart(Sweep +*s, int xdim, int ydim, float range); +

+Get something from objects

+Volume *RSL_get_volume(Radar *r, int type_wanted); +
Volume *RSL_get_window_from_volume(Volume +*v, float min_range, float max_range, float low_azim, float hi_azim); +
Volume *RSL_reverse_sweep_order(Volume *v); +
Sweep *RSL_get_closest_sweep(Volume +*v,float sweep_angle,float limit); +
Sweep *RSL_get_first_sweep_of_volume(Volume +*v); +
Sweep *RSL_get_sweep(Volume *v, float +elev); +
Sweep *RSL_get_window_from_sweep(Sweep *s, +float min_range, float max_range, float low_azim, float hi_azim); +
Ray *RSL_get_closest_ray_from_sweep(Sweep +*s,float ray_angle,float limit); +
Ray *RSL_get_first_ray_of_sweep(Sweep +*s); +
Ray *RSL_get_first_ray_of_volume(Volume +*v); +
Ray *RSL_get_next_ccwise_ray(Sweep +*s, Ray *ray); +
Ray *RSL_get_next_cwise_ray(Sweep +*s, Ray *ray); +
Ray *RSL_get_ray(Volume *v, float elev, +float azimuth); +
Ray *RSL_get_ray_from_sweep(Sweep +*s, float azim); +
Ray *RSL_get_ray_above(Volume +*v, Ray *current_ray); +
Ray *RSL_get_ray_below(Volume +*v, Ray *current_ray); +
Ray *RSL_get_window_from_ray(Ray *r, float +min_range, float max_range, float low_azim, float hi_azim); +
float RSL_get_linear_value(Volume +*v,float srange,float azim,float elev,float limit); +
float RSL_get_nyquist_from_radar(Radar +*radar); +
float RSL_get_range_of_range_index(Ray +*ray, int index); +
float RSL_get_value(Volume *v, float elev, +float azimuth, float range); +
float RSL_get_value_at_h(Volume *v, float +azim, float grnd_r, float h); +
float RSL_get_value_from_cappi(Cappi +*cappi, float rng, float azm); +
float RSL_get_value_from_ray(Ray *ray, +float r); +
float RSL_get_value_from_sweep(Sweep *s, +float elev, float azim, float r); +
Radar *RSL_get_window_from_radar(Radar *r, +float min_range, float max_range, float low_azim, float hi_azim); +
int RSL_get_sweep_index_from_volume(Volume +*v, float elev,int *next_closest); +

+Sorting

+Volume *RSL_sort_rays_in_volume(Volume *v); +
Volume *RSL_sort_sweeps_in_volume(Volume *v); +
Volume *RSL_sort_volume(Volume *v); +
Sweep *RSL_sort_rays_in_sweep(Sweep *s); +
Sweep *RSL_sort_rays_by_time(Sweep *s); +

+Math

+Volume *RSL_volume_z_to_r(Volume *z_volume, float +k, float a); +
Sweep *RSL_sweep_z_to_r(Sweep *z_sweep, float +k, float a); +
Ray *RSL_ray_z_to_r(Ray *z_ray, float k, +float a); +
float RSL_z_to_r(float z, float k, float +a); +
float RSL_area_of_ray(Ray *r, float +lo, float hi, float max_range); +
float RSL_fraction_of_ray(Ray *r, float +lo, float hi, float range); +
float RSL_fraction_of_sweep(Sweep *s, +float lo, float hi, float range); +
float RSL_fraction_of_volume(Volume +*v, float lo, float hi, float range); +
float RSL_fractional_area_of_sweep(Sweep +*s, float lo, float hi, float max_rng); +
void RSL_add_dbz_offset_to_ray(Ray *r, float dbz_offset); +
void RSL_add_dbz_offset_to_sweep(Sweep *s, float dbz_offset); +
void RSL_add_dbz_offset_to_volume(Volume *v, float dbz_offset); +
void RSL_find_rng_azm(float *r, float *ang, float x, float y); +
void RSL_fix_time(Ray *ray); +
void RSL_get_groundr_and_h(float +slant_r, float elev, float *gr, float *h); +
void RSL_get_gr_slantr_h(Ray *ray, +int i, float *gr, float *slantr, float *h) +
void RSL_get_slantr_and_elev(float +gr, float h, float *slant_r, float *elev); +
void RSL_get_slantr_and_h(float +gr, float elev, float *slant_r, float *h); + +

+Cappi/Carpi

+Cappi *RSL_cappi_at_h(Volume *v, float h, +float grnd_range); +
Carpi *RSL_cappi_to_carpi(Cappi *cappi, +float dx, float dy, float lat, float lon, int nx, int ny, int radar_x, +int radar_y); +
Carpi *RSL_volume_to_carpi(Volume +*v, float h, float grnd_r, float dx, float dy, int nx, int ny, int radar_x, +int radar_y, float lat, float lon); +
int RSL_fill_cappi(Volume *v, Cappi *cap, +int method); +

+Cube

+Cube *RSL_volume_to_cube(Volume *v, float +dx, float dy, float dz, int nx, int ny, int nz, float grnd_r, int radar_x, +int radar_y, int radar_z); +

Slice *RSL_get_slice_from_cube(Cube +*cube, int x, int y, int z); +

+Histogram

+Histogram *RSL_allocate_histogram(int +low, int hi); +
Histogram *RSL_get_histogram_from_ray(Ray +*ray, Histogram *histogram, int low, int hi, int min_range, int max_range); +
Histogram *RSL_get_histogram_from_sweep(Sweep +*sweep, Histogram *histogram, int low, int hi, int min_range, int max_range); +
Histogram *RSL_get_histogram_from_volume(Volume +*volume, Histogram *histogram, int low, int hi, int min_range, int max_range); +
void RSL_print_histogram(Histogram +*histogram, int min_range, int max_range, char *filename); +
Histogram *RSL_read_histogram(char +*infile); +
+
Author: John H. Merritt. + + diff --git a/doc/gv_but.gif b/doc/gv_but.gif new file mode 100644 index 0000000000000000000000000000000000000000..c6c5ea9c7fa79c0a0044d12dda5a8978d9de2025 GIT binary patch literal 2726 zcmd6n`BzhC8i2pMpaB%2Ds!^{5m6yP#guVE&;ruag49zMJG}`J z*$I#;Xs}^xv5H10ReS36LL)8%7^-8TV{O0%m-awAv|8&KCOz{{^!xpNp68tRd~eE@ zrR1r)V0H;G>fA#(K>J4gVG26b;Thu+sA1`J0)~gpY@G)69dTZdzS2xdCpgG0 zSHKfKM6hPcm!_%F<_<4*pY=2HWMGjHx$h&{Z)k+NR#xF;3Caz)cp3Fj4ow(27ZU%b z_&p5p1CTB$xXjrO}AWz1<|DzDt@zqqTg@u1#(3Gfra7{Hia$Z zIbD&*;@pUu_uSv4HtN&^5o$Yed{dyM4$NkL2XDjMCuS3kb=6-`!Y20jnc1` zl|lR-N{ssI_#rnnH|xX*KaV;|oRRcW3wL zuF}%Au_UJy8%Q7Hobe!6RaE-v3IabRGim5UzKmA+Nr+poiORAC@}SN z3+V9DXyr_IiA2xg^a*V6b}6fx$(0$&GyH5oZ%z!N0q~!RrE!tTp6&AeOh6I98v()+ zO^Eg3Yb6pYZRx>=j^jd`k;(+Q=`_qwyVn%(IFibY;s}H{IXRKWQMZB^plDFsKW4AS zU-m=uJ~qb=)}%x`DKu|4kni9FB)bA<W_H?uTxYv&@|1MR`H>S`xQCd8~|VDA2MglOkh1O>2+7rvdmI#=)Wofe-~T?d{ttnQGn9jb*k9_#@Dh8FPKwU%&4 zTPTW?=zifg7W+Vhk*~{ss@obGGvd=iIMB1!#=X0MkZ38%`Y| z2{{KL<^(92CP1q*2}oPl+2#0CEm7%LkBMIY>(6EaB4@v3p)m- zT45f3Wd+aP3IZp_qjuqWrIYGAn@NK-+e1TfOZPVaqm+X-+CoDl5GTvJVLl6k1UYm& zTnDOI)$a3rn&UY1ah-`7@oUfJU~&7E&RH0W#IO5pnH$|Do&v$vBeADTtpV0YQ3$Pg zarJ_j$H*%b6L%A89qzu~0<7rtM4)!GFS!#Rsm&o$Z2Z!jW_BqJ1?Bv<9g=+S6uuH(ssV973VdGjDNJHK8(?;W z>*I~s#CRlTAj5Li)ZAxT(DFb7wA%6Y0o+dExyf+!tTc9A35DeZ4SQ&$vst8FkUP$O znxQ|jTi_ZtKe^VWTnf#63U%q`$;%qA8z4Oq&2{)by(fk@8Bek8TSU>V)aQ~6T_i+T zzUPtzPn}<*ysCvWE5X=7t5Htbl||i}*cU}OdfNHdwAUuIFW8I$(vwptb=B%OGX)Af zf_5I3OOI0=M?~7j6TrJZR!A;!DLH2>=>Z}Z!yPqs4~-DR#9%Z0J7Q+?1|Po;=qiz zTuI^aC5Y=DPSC4?*N7Hw*qlR7HPpTCmF=S&xDd6G{-^@#}mxCX0;mesy zL<5*{62A{4%1L2uZA*~e8~ChWKWo#S*$t~N^A=X_ZYfqxLewcAN*m> zq6UkWJZX7XyZ*-NWXty->9Xe}v;K>Z*s`|J2G2%8U~(adZL_b+C`>L`%VAeAw44a9 z>(y?IanAmg<@kLwjo&=z=mlz>fhQ)>xQ$dKue-NuVnb}_HCL0{If^jJ!8H%^=b2yF z=$+PXVv})iP3!S8m(ld6(bBwnS}!+feM+Qytw~9p2VbNcdurZVxzDu)J@NXu`-2k$ zc@*$m2gwe{_G49=XyCiA5q#It9k!d%COSs42J{s` z;z=bXa@m)Fc7Cd$Rp;w#sCJy<_lLCXb;@3`^I#zE^hz>G8 zj>$EpQ|D(&>f_$53{4|N7w+deV7da@?&)eANKHR)H0^zO=4fAoeto&VoVN_~IFLBi NLp%{LfME!1{2yvlyXOD^ literal 0 HcmV?d00001 diff --git a/doc/gv_sites_but.gif b/doc/gv_sites_but.gif new file mode 100644 index 0000000000000000000000000000000000000000..96ae18eaad8c358abaeb92f2900ba0601d6af321 GIT binary patch literal 2771 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 literal 0 HcmV?d00001 diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..113a315 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,164 @@ + + + + + + TRMM Satellite Validation Office Web Site + + +
+ +

TRMM Radar Software Library

+ + + + + +
+ +
+

+


+ +

+Current RSL Version 1.40, released 10/10/2008
+Supports WSR-88D Level II Build 10 Format

+ +In support of the Tropical Rainfall +Measuring Mission's (TRMM) Global +Validation Program, the NASA TRMM Satellite Validation Office has developed a Radar Software +Library for working with the various input radar formats. This is an object-oriented +library written in C. +

This library is an object oriented programming environment for writing +software applicable to all RADAR data related to the TRMM +GV effort. This library reads the WSR88D, Lassen, Sigmet, McGill, UF, +HDF, RAPIC, RADTEC and native RSL file formats. Additional functions are +provided to manipulate the RSL objects. Nearly all of the functions return +objects. When they don't, they usually perform actions like output, making +images, etc. The most general object in RSL is Radar. The structure +Radar +is the method used to define the ideal or universal radar representation +in RAM while keeping the natural resolution of the data unchanged. More +simply, Radar represents the super set of all radar file formats. +The Radar structure is hierarchically +defined such that it is composed of Volumes, each containing one +field type. Volumes are composed of Sweeps. +Sweeps +are composed of Rays and Rays contains a vector of the field +type. Some field types are Reflectivity(DZ), Velocity(VR), Spectrum Width(SW), +etc. There are approximately 20 field types. See the +Users +Guide for more information.  Also, check out What's +New.
+Send questions or comments to help@radar.gsfc.nasa.gov. +

+

+Indexed Reference
+Download latest version +

+ + + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+Supported Radar Data Formats

+
Format TypeInputOutput
LassenYesNo
McGillYesNo
SigmetYesNo
WSR-88DYesNo
RAPICYesNo
UF - Universal FormatYesYes
HDF - Hierarchical Data FormatYesYes
RADTECYesNo
EDGEYesNo
+ +
+ + + + + + diff --git a/doc/internal_routines.html b/doc/internal_routines.html new file mode 100644 index 0000000..a8b1cf1 --- /dev/null +++ b/doc/internal_routines.html @@ -0,0 +1,248 @@ + + + + + +
+
+ +

RSL Internal Routines

+
+
RSL internal routines are routines used within the library and not meant for use in RSL application programs. Most of these routines are used only within the source code file that they exist, but a few are used in several different source code files. + +

The routines are listed by the RSL source code file in which they can be found. + +

As of version 0.39, the source code for the wsr88d (v1.14), lassen (v1.1), nsig (v1.3), tg (v1.1), and mcgill (v1.1) libraries are included in RSL. This precludes the need to specify a long list of additional libraries during the link step when building application. Also, it simplifies the RSL installation procedure. Still needed are two routines: ppmtogif and ppmtopict, from the pbmplus package. +


+ +

New in v0.41

+ + +

gzip.c

+int no_command(char *cmd);
+FILE *uncompress_pipe(FILE *fp);
+FILE *compress_pipe(FILE *fp); +
+ +

column.c

+ +
+
Column *compute_column_products(Column *c); +
Compute the vertical structure values within the Column passed in the parameter list using the data values stored in the Column. Vertical_structure values computed are zmax,hzmax and the eth array (echo tops). The dBz, slant range and height values must exist within the Column before this routine is called. The array for echo top values must be allocated as well. + +

+

Column *get_column_dbz(Volume *v,Column *c,float azim); +
Retrieve the dBz values from the Volume v using the nearest neighbor technique along a straight vertical line. The vertical line is positioned at the azimuth passed in the parameter list and the ground range that should already exist in Column c. The slant range array, height array and memory allocation for the dBz array should already exist as well. + +

+

Column *get_column_range_coord(Volume *v,Column *c, float grange); +
Using the elevation angles from Volume v and the ground range (grange), calculate the slant ranges and heights for all points at the intersections of the Sweeps in Volume v and a straight vertical line at the ground range value grange. + +

+

Column *new_column(int nsteps,float ett_start,float ett_int,int num_ett); +
Allocate space for a Column data structure and arrays within the Column. The value nsteps is the length of the dbz,height and slant range arrays. The lenght of the echo top array, and thus the number of thresholds, is num_ett. The first echo top threshold is ett_start followed by additional thresholds every ett_int. + +

+

void copy_column_range_coord(Column *from,Column *to); +
Copy the range dependent coordinates from Column from to Column to. Range dependent variables in the Column data structure are ground_range, the h array (height) and slant_range array. No memory space is allocated for the Column to.
+ + +

+


+ +

endian.c

+int big_endian(void);
+int little_endian(void);
+void swap_4_bytes(void *word);
+void swap_2_bytes(void *word); +
+ +

image_gen.c

+None. +
+ +

interp.c

+ +double dir_angle_diff(float x,float y); Returns signed difference between angles x and y. Returns a positive value if y > x and a negative value if y +double from_dB(double db); +Convert a decibel scale value to a linear scale value. + +

+double get_linear_value_from_sweep(Sweep *sweep,float srange,float azim,float limit); +Return an interpolate value between two rays within a sweep. Interpolation is done along the azimuth coordinate. No interpolation is done in the range direction. The routine expects to work with values that are in a decibel scale (reflectivity data), but it returns values in linear scale. + +

+double to_dB(double value); +Convert a linear scale value to a decibel scale value. + +

+float get_dist(float r1,float a1,float e1,float r2,float a2,float e2); +Compute the distence between two points in space given their spherical coordinates. r1 (range),a1 (azimuth angle) and e1 (elevation angle) are the coordinates for the first point. Angles are measured in degrees. + +

+void get_surrounding_ray(Ray **ccwise,Ray **cwise,Sweep *s,float ray_angle); +Return the two rays within a sweep that surround the angle ray_angle. The ray that is counter-clockwise to ray_angle is returned in ccwise. The ray that is clockwise to ray_angle is returned in cwise. **ccise and **cwise are pointers to ray pointers. For example, if r is of type *Ray, then &r should be passed for either **ccwise or **cwise. + +

+void get_surrounding_sweep(Sweep **below,Sweep **above, Volume *v,float elev); +Return the sweeps that are above and below the elevation angle elev. **below and **above are pointers to Sweep pointers. if s is of type *Sweep, pass &s as either **above or **below. If the conditionexist where a sweep does not exist for either the above or below case, then a the appropriate pointer is set to NULL. + +

+void get_xyz_coord(double *x,double *y,double *z,double range,double azim,double elev); +Convert a set of spherical coordinates to a set of cartesian coordinates. + +

+


+ +

lassen_to_radar.c

+void lassen_load_sweep(Sweep *s, int isweep_num, unsigned int mask, int early, s truct sweep_index *ptr); +
+ +

mcgill.c

+mcgFile_t *mcgFileOpen(int *code, char *filename);
+int mcgFileClose(mcgFile_t *file);
+int mcgRecordRead(mcgRecord_t *record, mcgFile_t *file);
+mcgSegmentID mcgSegmentKeyIdentify(int key);
+int mcgRayBuild(mcgRay_t *ray, mcgFile_t *file); +
+ +

mcgill_to_radar.c

+void RayFill(Ray *rsl_ray, mcgRay_t *mcg_ray);
+void Ray_headerInit(Ray *ray, mcgHeader_t *head, mcgRay_t *mcg_ray, int ray_num, int num_bins_rsl);
+void Sweep_headerInit(Sweep *sweep, mcgRay_t *mcg_ray, int nrays);
+void Volume_headerInit(Volume *volume, short vol_scan_format);
+void Radar_headerInit(Radar *radar, mcgHeader_t *mcg_head); +
+ +

nsig_to_radar.c

+Radar * nsig_to_radar_headers_only(char * filename);
+Radar * n2r(char * filename, int data_flag, int misc_flag);
+int Rset_header(Radar * Radptr, nsig_file * nsfile);
+int Vset_header( Volume * volptr, int n, char * string);
+int Swset_header( Sweep * sweepptr, int sweepnum, float elev, float beam_width, int nrays);
+int set_mask(int k, int * array);
+void sec2dhms(long sec, int * d, int * h, int * m, int *s);
+int rtype2ntype( int j );
+int ntype2rtype( int j );
+char * get_type_string(int j);
+int Rayset_header(Ray * rayptr, nsig_ray_data * ray_data_ptr, nsig_ingest_data_header * idhdptr, Fixed_Header * fhptr);
+void Set_FixedHeader(Fixed_Header * FHptr, nsig_file * nsfile); +
+ +

print_histogram_catelog.c

+void print_histogram_catalog(Histogram *histogram, int min_range, int max_range, char *da te, char *filename); +
+ +

radar.c

+void print_vect(float v[], int istart, int istop);
+void radar_load_date_time(Radar *radar); + +

+


+ +

radar_to_uf.c

+none. +
+ +

range.c

+none. +
+ +

ray_indexes.c

+static void set_high_and_low_pointers(Sweep *s);
+static Azimuth_hash *hash_add_node(Azimuth_hash *node, Ray *ray); +
+ +

read_write.c

+Radar *set_default_function_pointers(Radar *radar); +
+ +

sort_rays.c

+static int ray_sort_compare(Ray **r1, Ray **r2);
+static int ray_sort_compare_by_time(Ray **r1, Ray **r2);
+static int sweep_sort_compare(Sweep **s1, Sweep **s2); +
+ +

toga_to_radar.c

+void fill_ray(Ray *ray, tg_file_str *tg_file, int datatype);
+void fill_ray_header(Ray *ray, tg_file_str *tg_file, int elev_num, int datatype);
+void fill_sweep_header(Radar *radar, tg_map_head_str *map_head, int sweep_num, int nrays);
+void fill_volume_header(Radar *radar, tg_map_head_str *map_head);
+void fill_radar_header(Radar *radar, tg_map_head_str *map_head); +
+ +

uf_to_radar.c

+Volume *reset_nsweeps_in_volume(Volume *volume);
+Radar *reset_nsweeps_in_all_volumes(Radar *radar);
+Volume *copy_sweeps_into_volume(Volume *new_volume, Volume *old_volume);
+void uf_into_radar(UF_buffer uf, Radar **the_radar);
+void swap_uf_buffer(UF_buffer uf);
+static enum UF_type type_of_uf_file(char *infile); +
+ +

volume.c

+ +
+
Azimuth_hash *the_closest_hash(Azimuth_hash *hash, float ray_angle); +
Return the hash pointer that contains the closest Ray to the angle ray_angle. The hash passed to this routine can be any hash within the a Sweep's hashing table, but for the quickest search it should be the hash pointer with the index returned by the internal routine hash_bin. + +

+

double angle_diff(float x, float y); +
Return the absolute value of the difference between angle x and angle y. Angles are measure in degrees and the return value has a range from 0 to 180. + +

+

double ccwise_angle_diff(float x,float y); +
Returns the counter-clockwise angle difference of x to y. Values returned will always be positive and exist in the range from 0 to 360. Examples: if x = 345 and y = 355 the value returned will be 350. On the other hand if x = 345 and y = 335 then the value returned will be 10. + +

+

double cwise_angle_diff(float x,float y); +
Returns the clockwise angle difference of x to y. Values returned will always be positive and exist in the range from 0 to 360. + +

+

int get_closest_sweep_index(Volume *v,float sweep_angle); +
int hash_bin(Sweep *s,float angle);
+ +
+ +

wsr88d_to_radar.c

+void float_to_range(float *x, Range *c, int n, Range (*function)(float x) );
+int wsr88d_load_sweep_into_volume(Wsr88d_sweep ws, Volume *v, int nsweep, unsigned int vmask); +
+ +

WSR88D library (v1.14)

+wsr88d.c
+wsr88d.h
+wsr88d_get_site.c
+wsr88d_locations.dat +
+ +

Lassen library (v1.1)

+accessvolhead.c
+cvrt.h
+freevol.c
+lassen.h
+portable.h
+radar.h
+radinfo.h
+raw.h
+read_head.c
+readvol.c
+sunrise_head.h
+sunrise_time.h
+xdr.h +
+ +

NSIG library (v1.3)

+nsig.c
+nsig.h + +

+TG library (v1.1)

+toga.c
+toga.h + +

+McGill library (v1.1)

+mcgill.c
+mcgill.h + diff --git a/doc/john.merritt.html b/doc/john.merritt.html new file mode 100644 index 0000000..f5b01c2 --- /dev/null +++ b/doc/john.merritt.html @@ -0,0 +1,10 @@ + + + + +John H. Merritt
+Applied Research Corporation, Landover, MD.
+merritt@trmm.gsfc.nasa.gov.
+
+ + diff --git a/doc/mike.kolander.html b/doc/mike.kolander.html new file mode 100644 index 0000000..d483933 --- /dev/null +++ b/doc/mike.kolander.html @@ -0,0 +1,9 @@ + + + + +Mike Kolander
+Applied Research Corporation, Landover, MD.
+kolander@trmm.gsfc.nasa.gov.
+
+ diff --git a/doc/programmers_guide.html b/doc/programmers_guide.html new file mode 100644 index 0000000..faccca0 --- /dev/null +++ b/doc/programmers_guide.html @@ -0,0 +1,409 @@ + + + + + + + + +
+
  +
  +

+Programming Guide for RSL.

+ +

+Design philosophy:

+The design philosophy is simple. Routines are functions. Routines are short +and simple. And, higher level routines are built upon lower level routines; +a hierarchical modular design. +

Each procedure in the RSL is a function that returns a pointer to an +object that it is designed, or self documented, to return. In the case +of scalar functions, scalar values are returned. There are exceptions to +this rule wherein we have procedures that modify their arguments, but, +these are few. Also, each function does one thing well. This makes the +implementation of each function simple and easy to understand and, therefore, +easy to maintain. The power of the library has come from building higher +level functions from many lower level functions. Eventually, the highest +level function takes a filename as an argument and returns a Radar pointer. +

The Radar data structure is designed to contain values and header information +making it a superset of all the radar data formats currently encountered. +Currently RSL can ingest the following file formats: nexrad, lassen both +1.3 and 1.4 file format versions (MCTEX too), UF, toga, new sigment (nsig) +both version 1 and version 2 file formats, mcgill, kwajalein and rapic +(Berrimah data). +
  +

+What's New?

+ +

+Future plans.

+There are no plans for added functionality to the library. However, there +are always new functions that pop-up. The documentation must be improved. +Other than that, bug fixes and optimizations will be incorporated. Therefore +all furture releases are expected to be minor. +

+Can read compressed files automatically (new since v0.41)

+Transparent, to all ingest routines the capability of filtering the input +data file through the GNU gzip program for decompressing the file has been +added. This feature does not appear to slow the I/O time and, in some cases, +especially on 486 pc's, improves overall throughput time. Two generic, +internal routines, have been added: compress_pipe and uncompress_pipe. +Each routine takes a FILE * and redirects it through gzip. +Each routine returns a new FILE *. Wsr88d files occupy 1/10 the +disk space when compressed and the TRMM Office plans to compress wsr88d +files to CDROM and 8mm tape for overall throughput savings for the production +system. It will no longer be necessary to decompress the data before processing +level 1. +

Similiarly, UF output can be saved using the gzip filter. The new routine +added is RSL_radar_to_uf_gzip which +utilizes the gzip compression filter. +

+Can read stdin (new since v0.39)

+A new routine is provided called RSL_uf_to_radar_fp +which takes an open file descriptor and returns a radar pointer. That file +pointer can be stdin. This special interface syntax, for the UF +ingest, is an exception to the interfaces that the other ingest routines +have. All other ingest routines, including RSL_uf_to_radar, +have been modified to read stdin when the input filename is NULL. The complete +list of routines is: RSL_wsr88d_to_radar, +RSL_nsig_to_radar, +RSL_lassen_to_radar, +RSL_uf_to_radar, +RSL_mcgill_to_radar +and RSL_toga_to_radar. The only routine +that will not accept stdin will be RSL_anyformat_to_radar. +That routine will not be able to handle reading stdin because it needs +to read the first few bytes of the file to determine which ingest routine +to call. If you plan to make a filter program, you'll just have to know +what file format you expect: UF, nsig, wsr88d, etc. +

+Verbose print mode:

+The function RSL_radar_verbose_on() +and RSL_radar_verbose_off() control +whether or not the radar library prints diagnostic messages during execution. +These routines simply toggle an externally defined variable, radar_verbose_flag. +If you're writing a new library function and you want the user (another +programmer) to control the printing of diagnostic messages or not, you +simply place print statement as the consequence of testing the variable +radar_verbose_flag. +For example: +
extern int radar_verbose_flag; /* Define before usage. */
+ /* Somewhere in the code. */
+ if (radar_verbose_flag) printf("I'm here now. Whatever.\n");
+ +

+Writing methods (structure specific interfaces for routines):

+The natural hierarchy of Radar makes it easy to construct routines that +have interfaces that work on each of the substructures. When writing a +function that manipulates the Ray data, it is easy to provide the interface +for the Sweep, Volume and Radar without much extra effort. I will illustrate +with an example that adds two Rays. +
Ray *add_rays(Ray *ray1, Ray *ray2)
+{
+int i;
+Ray *ray_new;
+if (ray1 == NULL) return NULL;
+if (ray2 == NULL) return NULL;
+ray_new = RSL_new_ray(ray1->h.nbins); /* Allocate the new ray. */
+if (ray_new == NULL) return NULL;
+ray_new->h = ray_new->h; /* Copy the header information. */ 
+for (i=0; i <= ray_new->h.nbins; i++) /* Add each range element. */
+  ray_new->range[i] = ray1->range[i] + ray2->range[i];
+return ray_new; /* Return this new ray. */
+}
+It is valid for the routine to accept NULL's. This should be checked and +appropriate values returned. In the case above, we return NULL. We could +easily return the ray that is not NULL, too. The choice is up to you. The +routine is a function and returns a structure pointer similar to those +it manipulates; or self documented to return. Space is allocated and header +information is copied. You might ask, "Why don't we call RSL_copy_ray, +then call RSL_clear_ray?". This is a viable approach and it will work well +at the ray level, however, for the sweep, volume, and radar interfaces +we don't want to recursively copy all substructures because it is more +troublesome to copy, clear and set all the levels, than to simply allocate +and set at each level. To construct the interfaces for Sweeps and Volumes +is easy. For the Sweep interface we recognize that a Sweep is an array +of Rays. You will notice that this routine is coded almost identically +to the ray routine. +
Sweep *add_sweeps(Sweep *s1, Sweep *s2)
+{
+int i;
+Sweep *s_new;
+if (s1 == NULL) return NULL;
+if (s2 == NULL) return NULL;
+s_new = RSL_new_sweep(s1->h.nrays);
+s_new->h = s1->h;
+for (i=0; i <= s1->h.nrays; i++)
+  s_new->ray[i] = add_rays(s1->ray[i], s2->ray[i]);
+return s_new;
+ +
}
+The pattern continues for making the Volume interface. +
Volume *add_volumes(Volume *v1, Volume *v2)
+{
+int i;
+Volume *v_new;
+if (v1 == NULL) return NULL;
+if (v2 == NULL) return NULL;
+v_new = RSL_new_volume(v1->h.nsweeps);
+v_new->h = v1->h;
+for (i=0; i <= v1->h.nsweeps; i++)
+  v_new->sweep[i] = add_sweeps(v1->sweep[i], v2->sweep[i]);
+return v_new;
+}
+And finally, for Radar. +
Radar *add_radars(Radar *r1, Radar *r2)
+{
+int i;
+Radar *r_new;
+if (r1 == NULL) return NULL;
+if (r2 == NULL) return NULL;
+r_new = RSL_new_radar(r1->h.nvolumes);
+r_new->h = r1->h;
+for (i=0; i <= r1->h.nvolumes; i++)
+  r_new->v[i] = add_volumes(r1->v[i], r2->v[i]);
+return r_new;
+}
+These four functions allow us to add two radars, add two volumes, add two +sweeps or add two rays. The development was simple. For the radar routine +we loop on the number of volumes and call the volume routine. For the volume +routine we loop on the number of sweeps and call the sweep routine. For +the sweep routine we loop on the number of rays and call the ray routine. +For the ray routine we loop on the number of bins and perform the work. +Simple. This is how many of the RSL routines were written. +

+Using h.f and h.invf and defining your own function:

+The header members f and invf are provided to allow you to +define the conversion function for internal/float storage. These header +members are in the structures Volume, +Sweep, +and Ray. +f takes a value of type +Range +and returns a value of type +float. invf takes a value of +type float and returns a value of type Range. +f and +invf should be inverse functions. That is, c == invf(f(c)) and x +== f(invf(x)). Range is a datatype that represents the type of data +for internal storage. Typically, +Range will be unsigned char +or unsigned short depending on the configuration option USE_TWO_BYTE_PRECISION +the file makefile during the build and install step of RSL. There are several +predefined functions and they are based on the WSR88D, or NEXRAD, encoding. +There is a function for each field type: reflectivity, velocity, spectral +width, etc. However, only two distinct functions are provided because the +other field types can use these functions as well: DZ_F (and DZ_INVF) and +VR_F (and VR_INVF). DZ_F and DZ_INVF apply to reflectivity data and VR_F +and VR_INVF apply to all remaining field types by default. There are no +restrictions for +f and invf. Typically, you either pick the +default functions DZ_F, DZ_INVF, VR_F and VR_INVF and assign them to the +header member h.f and h.invf, appropriately, in the routine +that is ingesting data from disk and constructing the Radar data structure. +You can define your own encoding functions and assign them to h.f +and h.invf. To illustrate: +
static Range invf(float x) {
+ return (Range) (x/2 + 10);
+}
+
+static float f (Range x) {
+ return (float) (x - 10)*2; /* Not quite a perfect inverse function. */
+}
+
+Volume *volume_routine(Volume *v)
+{
+ v->h.f = f; /* Assign the float function. */
+ v->h.invf = invf; /* Assign the Range function. */
+ return v;
+}
+So far in the construction of RSL, the only location where you assign h.f +and h.invf is in the ingest routine for a particular data format. The routines +RSL_uf_to_radar, +RSL_lassen_to_radar, +RSL_wsr88d_to_radar, +RSL_nsig_to_radar, +RSL_toga_to_radar, +and RSL_mcgill_to_radar each define +the invf and f functions; in some cases the default functions are used. +The file volume.c contains the default specification for DZ_F, DZ_INVF, +etc. +

+Image generation:

+The image generation section was initially written to test and debug the +development of the library. However, some of the image generation capabilities +are becoming a permanent feature of RSL. There are two parts to image generation. +One, defining the color table and two, making PPM images. Assigning colors +is critical to making color images, otherwise the resultant images will +be black. The color table in RSL is global to the image functions and is +statically allocated so that once the color table is defined, that's it. +There are several routines that load color tables, but the main idea is +that there is a red table, a green table and a blue table. Each of these +tables is a separate file on disk stored in /usr/local/trmm/lib/colors +The /usr/local/trmm prefix may be different on your system. These +are the default color files and so you can use any file you like. Each +file can contain up to 256 bytes, each byte represents a color intensity +in the range 0 - 255. The color are ordered, in the file, by color index. +The first byte is for color index 0, the second byte for color index 1, +etc. There is only one type of image made, PPM. Well, I can make PBM and +PGM too, but I consider them similar to PPM. To make other types of images +like GIF, PICT, etc. I pipe the output into the ppmtogif, ppmtopict, command +appropriately. I do this because I don't want to include all the different +conversion sources in RSL. If you don't have the pbmplus software on your +system, you can still use these image functions by either making your own +ppmtogif command which is a csh script with the sole command 'cat' in it +or modify the RSL library routine to not pass the data through the pipe. +Also, when making PGM files, I pipe them into gzip so that the output files +are small. The image generation functions are designed to meet our specific +needs and I cannot say that they will be suitable for your needs. +

+Writing a new ingest routine:

+Here we explain how to interface a new file format into RSL. This means +we read the file format and assign values to the appropriate structure +members. The interface will return a pointer to Radar, allocating all memory. +Or, it will return NULL indicating an error. +
Radar *RSL_something_to_radar(char *infile);
+The file added to RSL will be called something.c. All the code needed to +ingest the file and create the Radar structure will be in that file. It +may be necessary to rely on another library that can ingest the data file +utilizing a nicer interface. That is ok, go ahead and use it. This new +interface definition will be placed in the prototype section of rsl.h so +that other routines are aware of it. Also, code to automatically determine +the type of input file must be placed in anyformat.c. If it is not possible +to automatically determine the type of file, then this must be documented +as such and an explanation that when anyformat_to_radar returns NULL, it +may be necessary to call RSL_something_to_radar directly. Memory allocation +routines you will need are: RSL_new_radar, RSL_new_volume, +RSL_new_sweep +and RSL_new_ray. You may not know ahead of time +just how many substructures to allocate, so allocate some reasonable maximum. +You can reset the value of nvolumes, nsweeps, or nrays after the ingest +is complete. +
radar = RSL_new_radar(20);
+...load radar->v[i] ...
+...keep track of the max index for v[i] ...
+radar->h.nvolumes = max_vol_index;
+return radar;
+You don't have to worry about deallocating the extra memory. Output routines +-- to disk -- will ignore it. And, after re-reading it, the right amount +of memory will be allocated. +

New in v0.41 is the implementation of the radar structure member radar_type. +Assign a descriptive string indicating the origin or the format type of +the data. Currently used strings are: "wsr88d", "lassen", "nsig", "uf", +"mcgill", "toga", "kwajalein". The string may not exceed 50 characters, +including the null character. +

Common problems that have occurred are: +

    +
  1. +Not setting the beamwidth member in the sweep header. This affects image +generation because the pixel size relies on it.
  2. + +
  3. +The number of rays, sweeps, or volumes is not set or exceeds the amount +allocated.
  4. + +
  5. +Not calling RSL_rebin_velocity_... before generating velocity images.
  6. + +
  7. +Not calling the RSL_load_..._color_table(). This results in black images.
  8. +
+ +

+RSL_copy versus RSL_new:

+It is important to note the differences between these two routines. RSL_copy_{radar, +volume, sweep, ray} returns a complete duplicate of the input structure. +It duplicates all of the substructures. This means that it allocates the +exact amount of memory that the argument occupies. If a Radar occupies +15 Mbytes of RAM, then a RSL_copy_radar will result in 15Mbytes of new +memory allocated. The total memory occupied will be 30 Mbytes: 15 for the +original and 15 for the copy. +

On the other hand, RSL_new_{radar, volume, sweep, ray} allocates memory +for the header structure and only the pointers to the substructure. You +have to allocate the substructure yourself. For instance, if you call +

RSL_new_radar(4); /* Four volumes. */
+you will have to call RSL_new_volume four times. Do that with, +
for (i=0; i<=radar->h.nvolumes; i++) {
+  radar->v[i] = RSL_new_volume(40); /* 40 sweep pointers. */
+   ... construct the volume ...
+}
+Here only 40 pointers for the sweeps are allocated and not the space for +the entire sweep which would include all the rays. For each sweep you must +use the code, +
for (i=0; i<volume->h.nsweeps; i++) {
+  volume->sweep[i] = RSL_new_sweep(400);  /* 400 is a good max. */
+
+  ... construct the sweep ...
+
+}
+ +

+Using RSL_new to copy instead of RSL_copy:

+Let's say you want to create the triplet, or quadruplet, set of routines +that function like the RSL_copy function in that they allocate new memory +and return a pointer to the appropriate structure, but, the routines are +executing an algorithm on the data and so the result is a mathematical +manipulation of the input structure. In other words: +
my_new_volume = RSL_some_function_of_volume(volume);
+The natural hierarchical construction will be: +
Radar *RSL_some_function_of_radar(radar);
+Volume *RSL_some_function_of_volume(volume);
+Sweep *RSL_some_function_of_sweep(sweep);
+Ray *RSL_some_function_of_ray(ray);
+As I've stated before, the radar routine will loop on the number of volumes +and call the volume routine. The volume routine will loop on the number +of sweeps and call the sweep routine. The sweep routine will loop on the +number of rays and call the ray routine. The ray routine will perform the +actual function. One approach might be to define the radar routine as: +
Radar *RSL_some_function_of_radar(Radar *radar)
+{
+  int i;
+  Volume *volume;
+  Radar *new_radar;
+  if (radar == NULL) return NULL;
+  new_radar = RSL_copy_radar(radar);  /* This is bad, bad, bad. */
+
+  for (i=0; i<=radar->h.nvolumes; i++)
+    new_radar->v[i] = RSL_some_function_of_volume(radar->v[i]);
+
+  return new_radar;
+}
+Now, why did I place the comment /* bad, bad, bad */ in the code? At first, +it seems, it may not be all that bad. But, remember that RSL_copy_radar +will copy all the volumes and sweeps and rays and bins. The line that assigns +new_radar->v[i] is allocating space for a volume too. Therefore, we are +more than doubling the memory requirements, if we code the volume and sweep +routines similarly. The amount of memory allocated will be nvolumes*space_allocated_to_a_volume ++ nsweeps*space_allocated_to_a_sweep + nrays*space_allocated_to_a_ray. +That is a tremendous amount of memory, you're talking 3*15*15Mbytes (675Mbytes). +In order to use RSL_copy_{radar,volume,sweep,ray} you will need to clear +out all the volumes, sweeps and rays with a call to RSL_clear_{volume,sweep,ray} +and you will have to pass the target structure to the routine which will +make it an argument that is modified. This goes against the design of the +typical RSL interface where a pointer to an object is returned by a function. +A better solution is to allocate a new radar and copy the header information. +Instead of writing, +
new_radar = RSL_copy_radar(radar);
+you write, +
new_radar = RSL_new_radar(radar->h.nvolumes);
+new_radar->h = radar->h;
+The volume, sweep and ray routine can be coded similarly. For example, +here is the sweep routine: +
Sweep *RSL_some_function_of_sweep(Sweep *sweep)
+{
+int i;
+Ray *ray;
+Sweep *new_sweep;
+if (sweep == NULL) return NULL;
+new_sweep = RSL_new_sweep(sweep->h.nrays);
+new_sweep->h = sweep->h;
+
+for (i=0; i<=sweep->h.nrays; i++)
+  new_sweep->ray[i] = RSL_some_function_of_ray(sweep->ray[i]); 
+
+return new_sweep;
+}
+ + + diff --git a/doc/quick_ref.gif b/doc/quick_ref.gif new file mode 100644 index 0000000000000000000000000000000000000000..2cb9ca16d797b2d2889ec46357d63ef237f8ee91 GIT binary patch literal 786 zcmV+t1MU1rNk%w1VT1r70JHx9z`(%0y}ic9#?H>p*4EbE-rncu=kM?D_xJbz00;m8 z00000000000000000000A^8LW00000EC2ui0E7S`06+x)5XecZy*TU5yZ>MaBqT*9 z$YB@Yi2Wr$Wssc(eSaQlOGv1xd9ARnb9D((ZlIK>u}`xnlYG0oPP9KkLth66YjuEq%O#G{ zmb_`1R&`Nvb;&iD+|$7pc%TF=X>Mohed6rVvx)ny7GLbg^Srn^=1sigs0(W(*$R-aJgc6&=V6Q+Y z0RaN!n`EkK8^4$c`4ubYC11~+TMZ2DlC)@&IUnLN?FS?Vjv46)($!sF=rPqgH*Gl6RvGo?g;tFr!eD3wdKXe! zX%#k5Jb@Xeo=h2ek;iI{RYIB?_K>6G32%@g#))H~0MA#1#bpGIwM>);js6ton`&xk zWz8FG4))@RJP3h~ju-qD31pH + + + + + + + +
+ +

+Indexed Reference for RSL

+ +

+Introduction 
+
Structures

+ +

+Users guide

+ +

+Programmers guide

+ +

+Internal Routines

+What's New +
README +
CHANGES +

Copyright(c)1996, 1997, 1998, 1999, 2000 +

+Functionality index to RSL routines

+ +

+Alphabetical index to RSL routines

+ +
+(alphabetical and grouped by object returned)
+Radar *RSL_anyformat_to_radar(char +*infile [, char *callid_or_first_file]); +
Radar *RSL_edge_to_radar(char *infile); +
Radar *RSL_get_window_from_radar(Radar *r, +float min_range, float max_range, float low_azim, float hi_azim); +
Radar *RSL_hdf_to_radar(char *infile); +
Radar *RSL_hdf_to_radar_unQC(char *infile); +
Radar *RSL_lassen_to_radar(char +*infile); +
Radar *RSL_mcgill_to_radar(char +*infile); +
Radar *RSL_new_radar(int nvolumes); +
Radar *RSL_nsig_to_radar(char *infile); +
Radar *RSL_prune_radar(Radar *radar); +
Radar *RSL_radtec_to_radar(char +*infile); +
Radar *RSL_rapic_to_radar(char *infile); +
Radar *RSL_read_radar(char *infile); +
Radar *RSL_sort_radar(Radar *r); +
Radar *RSL_toga_to_radar(char *infile); +
Radar *RSL_uf_to_radar(char *infile); +
Radar *RSL_uf_to_radar_fp(FILE *fp); +
Radar *RSL_wsr88d_to_radar(char +*infile, char *callid_or_first_file); +

Volume *RSL_clear_volume(Volume *v); +
Volume *RSL_copy_volume(Volume *v); +
Volume *RSL_get_volume(Radar *r, int +type_wanted); +
Volume *RSL_get_window_from_volume(Volume +*v, float min_range, float max_range, float low_azim, float hi_azim); +
Volume *RSL_new_volume(int max_sweeps); +
Volume *RSL_prune_volume(Volume *v); +
Volume *RSL_read_volume(FILE *fp); +
Volume *RSL_reverse_sweep_order(Volume *v); +
Volume *RSL_sort_rays_in_volume(Volume *v); +
Volume *RSL_sort_sweeps_in_volume(Volume *v); +
Volume *RSL_sort_volume(Volume *v); +
Volume *RSL_volume_z_to_r(Volume *z_volume, +float k, float a); +

Sweep *RSL_clear_sweep(Sweep *s); +
Sweep *RSL_copy_sweep(Sweep *s); +
Sweep *RSL_get_closest_sweep(Volume +*v,float sweep_angle,float limit); +
Sweep *RSL_get_first_sweep_of_volume(Volume +*v); +
Sweep *RSL_get_sweep(Volume *v, float +elev); +
Sweep *RSL_get_window_from_sweep(Sweep *s, +float min_range, float max_range, float low_azim, float hi_azim); +
Sweep *RSL_new_sweep(int max_rays); +
Sweep *RSL_prune_sweep(Sweep *s); +
Sweep *RSL_read_sweep (FILE *fp); +
Sweep *RSL_sort_rays_in_sweep(Sweep *s); +
Sweep *RSL_sort_rays_by_time(Sweep *s); +
Sweep *RSL_sweep_z_to_r(Sweep *z_sweep, float +k, float a); +

Ray *RSL_clear_ray(Ray *r); +
Ray *RSL_copy_ray(Ray *r); +
Ray *RSL_get_closest_ray_from_sweep(Sweep +*s,float ray_angle,float limit); +
Ray *RSL_get_first_ray_of_sweep(Sweep +*s); +
Ray *RSL_get_first_ray_of_volume(Volume +*v); +
Ray *RSL_get_next_ccwise_ray(Sweep +*s, Ray *ray); +
Ray *RSL_get_next_cwise_ray(Sweep +*s, Ray *ray); +
Ray *RSL_get_ray(Volume *v, float elev, +float azimuth); +
Ray *RSL_get_ray_from_sweep(Sweep +*s, float azim); +
Ray *RSL_get_ray_above(Volume +*v, Ray *current_ray); +
Ray *RSL_get_ray_below(Volume +*v, Ray *current_ray); +
Ray *RSL_get_window_from_ray(Ray *r, float +min_range, float max_range, float low_azim, float hi_azim); +
Ray *RSL_new_ray(int max_bins); +
Ray *RSL_prune_ray(Ray *ray); +
Ray *RSL_ray_z_to_r(Ray *z_ray, float k, +float a); +
Ray *RSL_read_ray (FILE *fp); +

float RSL_area_of_ray(Ray *r, float lo, +float hi, float max_range); +
float RSL_fraction_of_ray(Ray *r, float +lo, float hi, float range); +
float RSL_fraction_of_sweep(Sweep *s, +float lo, float hi, float range); +
float RSL_fraction_of_volume(Volume +*v, float lo, float hi, float range); +
float RSL_fractional_area_of_sweep(Sweep +*s, float lo, float hi, float max_rng); +
float RSL_get_linear_value(Volume +*v,float srange,float azim,float elev,float limit); +
float RSL_get_nyquist_from_radar(Radar +*radar); +
float RSL_get_range_of_range_index(Ray +*ray, int index); +
float RSL_get_value(Volume *v, float elev, +float azimuth, float range); +
float RSL_get_value_at_h(Volume *v, float +azim, float grnd_r, float h); +
float RSL_get_value_from_cappi(Cappi +*cappi, float rng, float azm); +
float RSL_get_value_from_ray(Ray *ray, +float r); +
float RSL_get_value_from_sweep(Sweep *s, +float elev, float azim, float r); +
float RSL_z_to_r(float z, float k, float +a); +

int RSL_fill_cappi(Volume *v, Cappi *cap, +int method); +
int RSL_get_sweep_index_from_volume(Volume +*v, float elev,int *next_closest); +
int RSL_radar_to_hdf(Radar *radar, +char *outfile); +
int RSL_write_histogram(Histogram +*histogram, char *outfile); +
int RSL_write_ray(Ray *r, FILE *fp); +
int RSL_write_sweep(Sweep *s, FILE *fp); +
int RSL_write_volume(Volume *v, FILE *fp); +
int RSL_write_histogram(Histogram +*histogram, char *outfile); +
int RSL_write_radar(Radar *radar, char +*outfile); +
int RSL_write_radar_fp(Radar *radar, +FILE *fp); +
int RSL_write_radar_gzip(Radar *radar, +char *outfile); +

unsigned char *RSL_sweep_to_cart(Sweep +*s, int xdim, int ydim, float range); + +

void RSL_add_dbz_offset_to_ray(Ray *r, float dbz_offset); +
void RSL_add_dbz_offset_to_sweep(Sweep *s, float dbz_offset); +
void RSL_add_dbz_offset_to_volume(Volume *v, float dbz_offset); +
void RSL_bscan_ray(Ray *r, FILE *fp); +
void RSL_bscan_sweep(Sweep *s, char *outfile); +
void RSL_bscan_volume(Volume *v, char *basename); +
void RSL_find_rng_azm(float *r, float +*ang, float x, float y); +
void RSL_fix_time(Ray *ray); +
void RSL_free_cappi(Cappi *c); +
void RSL_free_histogram(Histogram +*histogram); +
void RSL_free_radar(Radar *r); +
void RSL_free_ray(Ray *r); +
void RSL_free_sweep(Sweep *s); +
void RSL_free_volume(Volume *v); +
void RSL_get_color_table(int icolor, +char buffer[256], int *ncolors); +
void RSL_get_groundr_and_h(float +slant_r, float elev, float *gr, float *h); +
void RSL_get_gr_slantr_h(Ray *ray, +int i, float *gr, float *slantr, float *h) +
void RSL_get_slantr_and_elev(float +gr, float h, float *slant_r, float *elev); +
void RSL_get_slantr_and_h(float +gr, float elev, float *slant_r, float *h); +
void RSL_load_color_table(char +*infile, char buffer[256], int *ncolors); +
void RSL_load_green_table(char +*infile); +
void RSL_load_blue_table(char *infile); +
void RSL_load_height_color_table(); +
void RSL_load_rainfall_color_table(); +
void RSL_load_red_table(char *infile); +
void RSL_load_refl_color_table(); +
void RSL_load_sw_color_table(); +
void RSL_load_vel_color_table(); +
void RSL_load_zdr_color_table(); +
void RSL_print_histogram(Histogram +*histogram, int min_range, int max_range, char *filename); +
void RSL_print_version(); +
void RSL_radar_to_uf(Radar *r, char +*outfile); +
void RSL_radar_to_uf_fp(Radar *r, FILE +*fp); +
void RSL_radar_to_uf_gzip(Radar *r, +char *outfile); +
void RSL_radar_verbose_off(void); +
void RSL_radar_verbose_on(void); +
void RSL_read_these_sweeps(char +*sweep#, ..., NULL); +
void RSL_rebin_velocity_ray(Ray *r); +
void RSL_rebin_velocity_sweep(Sweep +*s); +
void RSL_rebin_velocity_volume(Volume +*v); +
void RSL_rebin_ray(Ray *r); +
void RSL_rebin_sweep(Sweep *s); +
void RSL_rebin_volume(Volume *v); +
void RSL_set_color_table(int icolor, +char buffer[256], int *ncolors); +
void RSL_set_hdf_qc_parameters(float +hfreeze, float dbznoise, float hthresh1, float hthresh2, float hthresh3, +float zthresh1, float zthresh2, float zthresh3, char *outfile); +
void RSL_select_fields(char *field_type, +..., NULL); +
void RSL_sweep_to_gif(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_sweep_to_pgm(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_sweep_to_pict(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_sweep_to_ppm(Sweep *s, char *outfile, +int xdim, int ydim, float range); +
void RSL_volume_to_gif(Volume *v, char +*basename, int xdim, int ydim, float range); +
void RSL_volume_to_pgm(Volume *v, char +*basename, int xdim, int ydim, float range); +
void RSL_volume_to_pict(Volume *v, char +*basename, int xdim, int ydim, float range) ; +
void RSL_volume_to_ppm(Volume *v, char +*basename, int xdim, int ydim, float range); +
void RSL_write_gif(char *outfile, unsigned +char *image, int xdim, int ydim, char c_t able[256][3]); +
void RSL_write_pict(char *outfile, unsigned +char *image, int xdim, int ydim, char c_ table[256][3]); +
void RSL_write_pgm(char *outfile, unsigned +char *image, int xdim, int ydim); +
void RSL_write_ppm(char *outfile, unsigned +char *image, int xdim, int ydim, char c_t able[256][3]); +
Cappi *RSL_cappi_at_h(Volume *v, float +h, float grnd_range); +
Cappi *RSL_new_cappi(Sweep *sweep, float +height); +

Carpi *RSL_cappi_to_carpi(Cappi *cappi, +float dx, float dy, float lat, float lon, int nx, int ny, int radar_x, +int radar_y); +
Carpi *RSL_new_carpi(int xdim, int ydim); +
Carpi *RSL_volume_to_carpi(Volume +*v, float h, float grnd_r, float dx, float dy, int nx, int ny, int radar_x, +int radar_y, float lat, float lon); +

Cube *RSL_volume_to_cube(Volume *v, +float dx, float dy, float dz, int nx, int ny, int nz, float grnd_r, int +radar_x, int radar_y, int radar_z); +

Slice *RSL_get_slice_from_cube(Cube +*cube, int x, int y, int z); +
Histogram *RSL_allocate_histogram(int +low, int hi); +
Histogram *RSL_get_histogram_from_ray(Ray +*ray, Histogram *histogram, int low, int hi, int min_range, int max_range); +
Histogram *RSL_get_histogram_from_sweep(Sweep +*sweep, Histogram *histogram, int low, int hi, int min_range, int max_range); +
Histogram *RSL_get_histogram_from_volume(Volume +*volume, Histogram *histogram, int low, int hi, int min_range, int max_range); +
Histogram *RSL_read_histogram(char +*infile); +
+


Author: John H. Merritt. + + diff --git a/doc/quickref.gif b/doc/quickref.gif new file mode 100644 index 0000000000000000000000000000000000000000..91695d4f78ff49695d1220cbf2ff89526ea9e288 GIT binary patch literal 4176 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 MzG+0^7JA^8LW00000 zEC2ui0JH#j073)*NV?qBFv>}*y*SsWyI;lt8QfGDX!v!*S*`>MOYc%gXDZH78UO)7 zjKsqfa)wDO#S;v6gr_LE@&SdiqE>@UQ7vCC>A7V<%SLaOvJ0c%@XRq)Dgm>jvcq>P8gK~UVhkqSw9yyB&g=Z@QPGnMy6^JHk7D@Bou3+7!btYQ8T5SA|enK219>MwSKtdWX6MzVx6W65+tkxC|6gw z<>xWq&k>AT&;m&}u8M)CvXa^>4;wozJi*FkS?t+hqhJoFm18MN;>nmh<@*Q2fPl7f z7n}*#$y4ZlUpTMw44Tlytd@_=VpuoxCDBf5cY1B61r5%+`9Te03F9-b8-r)|kc7CC z%CMKe$)+$s0OivE%$*T{dJc?bso{(+LCEDt+sTV1Og+0+_MZfq#O@vrr1_^eK=a2& zB=q|K(mWthduI5T9t-zeN7^o09B~~9Dt(ig2qN+HM1I9I7l1BIKr&f{x%ftuWJnnR zKuG|aAqZ901@X`^!4Py2eeXPAP;mj$*w`HT9EghoH7fbi7vWplZGdcvms5d`axG4MBEJa*wg>vHwLgxL=N zlSCR+J5%84EE;zF)6NWVEop#)+39uN5b9;XrdJBZ1!$%j+HuEGbLiFR7T%dFr3WHT zt5v<3eP>;9kjzpF2k72J2a8j9iU=RXVT#AG%KBKYmRKRxV4Tw0;EXP^5QS+va}^{2 zr1q9bC0|2=6EZFiN19B^Cj%y~CsY`0#AgRtLr|SNBG&86G5~xnwh!!EhA}M=Qx2Xo z>1ayORdK=1h)isZt``+!*#%6_q*Zmxz;3M?*K}ExnVUnz0t(n^0)TZiCQ=+MJ;bCU z5zCH7+pA2A&Yg!xkt|_cz-TuBYJrjLO3~gl#Qm;Wyp$xHR|PH3k@KkvsM5UrvpP#7 z@oO$*OK;r(gx;W5Y>K|i42*nb{zlU|+l&tVUOO-OlaQE^@L5%dv|t_J)zR~18{yJv z<+=p=bP?aW*Gw*lqsgeL6EQMNMCNog>7-{nQ_;%~@MXCQ zn&4|K$c^$)7YOO0jVGaLK?l(nAeULtVl?X>3u-{ZRv1Vi=SWsJ9O6MXhz^EO%OAz? z)+X8%BRxkO-Xoe7AnPc3i-wJ)a1iVq zVS$!G0|2UIonZ-5CnRyg8m)rJ3q7okQ)EY`=x~KMd8s8lnxsE8xk(vZp==JYV&S+a z$fF%`L$`rJaWY~g(OlqMS(}~?E%rneK8*_QAd(Cl#HTUdGM6S`4f&jA%$$hr5VR1Y zSExcCERH}8()?6?#`VWPuH{nQw3p3}xyx`uV4S{CkQ_fjgGB;pTXPUo2p3`%Jepx7 zKobn(+BXlY@F*bo>`V<9#sxC*a1}SC<(4`Kyjw1apknwZx$px2xmzWwDP=mAJzqjm zLby?z&iqhVve_++HWZW@YmgOqS4pe@7 n()L7&l`;4a3*6NMQcv>OlSwUsPB|cA*MZ#ix|ab6pacLr5+Yz~ literal 0 HcmV?d00001 diff --git a/doc/rsl.fig b/doc/rsl.fig new file mode 100644 index 0000000..8ba72f5 --- /dev/null +++ b/doc/rsl.fig @@ -0,0 +1,79 @@ +#FIG 2.1 +80 2 +5 1 0 1 -1 0 0 0 0.000 1 0 0 259.248 -208.678 120 221 259 243 382 226 +5 1 0 1 -1 0 0 0 0.000 1 0 0 261.382 -11.697 195 259 258 267 319 261 +5 1 0 1 -1 0 0 0 0.000 0 0 1 294.102 289.759 306 270 315 280 316 297 + 0 0 1.000 4.000 8.000 +5 1 0 1 -1 0 0 0 0.000 1 1 0 263.500 1480.300 295 149 232 149 144 154 + 0 0 1.000 4.000 8.000 +5 1 0 1 -1 0 0 0 0.000 0 0 0 382.738 656.566 139 528 382 381 627 529 +5 1 0 1 -1 0 0 0 0.000 1 1 0 646.396 318.672 655 325 656 314 646 308 + 0 0 1.000 4.000 8.000 +5 1 0 1 -1 0 0 0 0.000 1 1 0 653.705 330.000 644 341 666 338 666 322 + 0 0 1.000 4.000 8.000 +5 1 0 1 -1 0 0 0 0.000 1 0 0 442.278 600.608 384 382 279 444 222 549 +5 1 0 1 -1 0 0 0 0.000 1 1 0 392.906 522.548 407 534 411 521 405 509 + 0 0 1.000 4.000 8.000 +5 1 0 1 -1 0 0 0 0.000 1 1 0 378.000 503.333 352 535 383 544 404 535 + 0 0 1.000 4.000 8.000 +5 1 1 1 -1 0 0 0 4.000 1 0 0 449.999 552.154 385 383 318 428 274 509 +5 1 1 1 -1 0 0 0 4.000 0 0 0 307.559 553.507 388 383 450 430 491 510 +5 1 0 1 -1 0 0 0 0.000 0 0 0 323.076 595.400 387 384 478 438 539 549 +1 1 0 1 -1 0 0 0 0.00000 1 0.000 254 184 200 25 254 184 454 209 +1 1 0 1 -1 0 0 0 0.00000 1 0.000 382 531 246 23 382 531 628 554 +1 3 0 1 -1 0 0 21 0.00000 1 0.000 450 458 4 4 450 458 454 462 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 54 184 259 294 454 184 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 121 203 256 291 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 188 208 258 294 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 346 206 259 294 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 270 209 259 295 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 121 165 159 205 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 209 160 226 209 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 293 159 280 210 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 376 165 334 207 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 69 297 452 296 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 624 178 624 371 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 520 332 749 332 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 568 358 772 261 773 261 9999 9999 +2 1 1 1 -1 0 0 0 4.000 -1 0 0 + 625 331 743 306 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 624 331 742 215 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 744 215 745 305 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 745 295 735 297 735 309 9999 9999 +2 1 1 1 -1 0 0 0 4.000 -1 0 0 + 626 332 718 380 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 384 529 449 544 449 459 384 529 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 440 541 440 533 449 536 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 0 0 + 385 529 250 549 9999 9999 +4 0 0 12 0 -1 0 0.00000 4 17 53 183 142 Azimuth. +4 0 0 12 0 -1 0 0.00000 4 17 58 330 286 Elevation. +4 1 0 30 0 -1 0 0.00000 4 37 89 260 116 Sweep +4 1 0 30 0 -1 0 0.00000 4 37 106 387 359 Volume +4 1 0 10 0 -1 0 0.00000 4 12 4 668 277 r +4 1 0 10 0 -1 0 0.00000 4 12 9 689 326 gr +4 1 0 10 0 -1 0 0.00000 4 12 5 749 249 h +4 0 0 12 0 -1 0 0.00000 4 17 7 456 500 h +4 0 0 12 0 -1 0 0.97738 4 17 5 405 497 r +4 0 32 12 0 -1 0 0.00000 4 15 9 380 541 f +4 0 32 12 0 -1 0 0.00000 4 15 7 417 527 q +4 1 32 10 0 -1 0 0.00000 4 15 6 675 346 f +4 1 32 10 0 -1 0 0.00000 4 15 5 661 311 q diff --git a/doc/rsl.gif b/doc/rsl.gif new file mode 100644 index 0000000000000000000000000000000000000000..1194b9db7653b9c830754eb08ff67ad813d45d49 GIT binary patch literal 2194 zcmZvdYfw}98OHzTk_$;rt`K8DdbnQ%42A_1wI|^kHZp)q!lf}utZ@MEo%W?Hz>Ml)eUa9b;m9#cKWf;$9JCRnR$Qjhc{i7 zmbj=`3$);8@KG3siM&NpsdUkzMFc^B8~_RdC<34ifSmy2XcY>DDpR#wt*AEoCDx80K))`1Mm!hcK~<*xLOQABLK$%I1fM%2($!(Z~p6e{y#^M2Y5`t(-7%t zo$u+0^0?TZi8-Fx;hhDZ(IALTK|YO;{|P9(10)TC1P@647GymI1=HZ@Z2kXHz)Tp9 zt2XPmY}>J3i*MMrWiy_xO2f-G7niJGjB9rnZQoq1)5VmOZ2(ap;~&=s^cjNGXGBRG zoo(B0=@y?FIlm+G;%8rtb?zK`v->YDYlS-I_}v#hyT2*F_PyIynf2AfAK&-xz5C+_ z&q|myR;9s)eQRidTe}LWhYoWO9L%c8fB;ORnVWNIFm#3sAqW>OuHSa5ZI;71E(Xwx zg-5p_P*WT9C5&F@%D6OVk!%MS>FPdy0mTrQf6bC+K6m3ful<0HhG4Rj6B&*p4!8;7 z(NHeT<1M)RQfcmo+YuXcc)QpN8t4nozf4l9{6EQbNaIK_300I zEt3O%)!6a6mcX#?wbY#Fptoic^t0P)R+dlel}09WjkqIEC6^V-Mrzlkqx+ z>b5I*>Ic!4>PCXFu1|qcW;v%_@ZMy|s(mxQ_!nSX>WiN~BK78uxllB+6oMImv{KPb z2~Kh5)d;f|{?v;j>gkz^kXgpAGphLI4oiUuYqF%mEIlx=`KAYUY+m2GJV?F-Of2$W z6`Wl1-Q1&j#bMGzY{AtQ8?QF4$}&I?@5wf>A}aCP6mK$Fz) z&ma*NcTR~@jVd@Yr<>sLMn?)UzNu_zD@S#RWJ-E0Q$FlUnSEWfRi;2~s}a~TgJ?v& zQwzp`X!XKT{5d1rgwo(}-JX3=UNcV7Vw&^@LUP@0kA1rXo?y#LC7X9W3;DZUw9sLC zEDXi_>;w5Y-@poL&?`|v;?qWc)W4ZtCldsH?M3en(-j!KN2n0Ni|i09GOm}#nctRe zSSRFgsG)!s4Z-Fy-7sy&mTXKO-kAWnS6c>CWa>wnWL9V%{=GOP+ofbkfyDsBvZrON z*h=!=*#K9wNgZ|;eh@k}l}9_s?6p#yM4i=eM2ol-OuWIeDLODkW`G@~zmRk%@XpO> z%h@LmO9+4EVEfM}3C5krq>-g9FYbVSgH2CnLPg^PwYRRE=vOV|%0`C5HbU9*!3)t{ z{y@uh+Zp1Ddo>(+gT`A3BfWb!C zO&Pg39_w9dMrP_sz^ic4O+>C>Zw-pI;`@r+-i$~->|05oz)C?vH{`Rm4~feF)@&

}Kb%~V zXj`X&-D=PvZ%8Y3ARIj;?*m)e5-)ic z^==xVJ(={^3T22?7B3&h18f-zrhx|Jkt8fVPhs0;v}7%o%@hHO{=Br|9^cCB`s*{W z(yfY1Bp|7YfN$FGvf%_Gbg(>|>noCLz3!;_)?*bKOn3+N2JOoec9YB`N6$CA8sapw%9sT{uE( z(9i-U3Z|G3(-QM}!OqSND$CJST|5xDbXff7upi!|xNK7dnaiq&h4w2K_0d5r%Xolx zClb*zd)^TANpbUK9W7=v)gj5zJ}BcmJC{^`V2n>RqbK!mmzDamA-{yiW>XB%?s*iX z54wCHBP+0H=t$ucE+kftTncisA5Glp-*Pt^9dstKOKkt@?UGzt)|v$V`8eUm%dyT) ze+qZ~&75$}vD7Vi+wpkX{5yM^ev6SE@ST@$;&uKX-9~xk@DP_C)!!!SpS0IaZk7HCOM|7e)yq?$F>c!y}C`+>Zw5AUz{0P-G`42PvHy* GB>e~FsVO1= literal 0 HcmV?d00001 diff --git a/doc/rsl3.gif b/doc/rsl3.gif new file mode 100644 index 0000000000000000000000000000000000000000..9d093b70628abdefc703a0a2ed205296e5d135fc GIT binary patch literal 15701 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 literal 0 HcmV?d00001 diff --git a/doc/rsl_big.jpg b/doc/rsl_big.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a20193fcfd4d0bf59567031bce1ae2f9e8a43eb2 GIT binary patch literal 51776 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 literal 0 HcmV?d00001 diff --git a/doc/search_rsl.html b/doc/search_rsl.html new file mode 100644 index 0000000..171175c --- /dev/null +++ b/doc/search_rsl.html @@ -0,0 +1,20 @@ + + Search Page + + +

RSL Search Page

+

+
+Search RSL library for string in +

+Search variable: + +

+

+ + diff --git a/doc/software_but.gif b/doc/software_but.gif new file mode 100644 index 0000000000000000000000000000000000000000..d24651fef867cd1f38d43f8df5cf42583978811c GIT binary patch literal 1707 zcmV;c22}Y+Nk%v~VPpUv0K@SjQ>hPtx`&q z*3SR;@BedadjJ3cEC2ui0Av6j000I5V8)Hc!YoU&I7i~F$?+svc3=yR?K!GDJ0K>5 zaTpQ|9F10dl`w~cq4d}lF%Q%$dR;*ej2kM`P)HC6P6yDL8W>1MGL}Ll!!lI$w0PVe zau{+CS%eQICRryZ88b->QBe;HfP*M9mQg)@Nm&LC4i*Xs6A%U&1gRMc3RVmX3vUPs zfRufle2RmXJ}ADFVJ2@i40gb;a)Bp)dV-a&m4vU52MQAr5vB*ID-IP72`&{m4GlXM z-d3SHMc)_e>KE-+6&Ug_IZ{Ov-l6^9>;k&;_pP1}3KFtGSO`T+1q&7^NVFi2!h{PC zEL6C_@xg_S9_>}w_)#83jvp!iKHON(V+D^CE@(oD5+qG~_AsKv;*q1ukrpOQkRaia z0*)&$!kl2CkH(V^J$hX5(82?d6sHpEb3tWEmohYNTA))ZA)dDkVL@qDCpw`-lPU0~ zF=p2a6kcXTc`_?Tl|5-2k$)*@ z)Y(y<2M+>L3-AECD`}SkG|+^&_v2K>ce4^I+m_~S6nr5<#7h*L90d%3{#`lyf(8Kt zqDzmy;brON9tOzv*q3(K%5F!OCJR(JMAxp(t0#_4!k*;8&vzwcA^UXI(Y=+VDLQ&! z2LWur9cFChHWhgf3C5TIPZSOJSzQq%6afQjJxEeUfl22<0v(+uQCCe#mDdIXYyhGK zsWpe#NiK~ul}#spR+VrvmM4*f5%hsvRUS z$PpYEQ5BzW3~KbCdF(|0dr9fp)?p{f)0k$fO|g3Lz-e_%@*&F)YYRT z2DHw4(g7u6q%5??<_GS$pkClXkfdIKK#8c4lqFQdQKUfvjZ&C}J(LzwC6o<9S3!0h zL8oSPr~*8|N&YF2AHf*-`A&2cDG&g_7&RGyZ0{%<9FK}wQ!yVH)1-$yM2g2GboJ5c zt&+teKx&E$oJ#PL-wtpAiEA3{0a*eBaP0sj9W2>wG`_ULP!YZXi?F`=FzRWit*Ie8 zenPiFE7NTqowM4K8l3T3&4^SVuivw-QGH7 zCqM!e9Sk752_!q?HqrzMtV=}>3RX$`=Bpi5 zT13LyX)vAj2^g7tzv|3UD{g^w`|SrZV*q!fh4oSI3As^1a~R=3v<4Fgk0wVgTcv!D zf05N4Ta!ID+E!b+%atLJaQBc?T~PqVB+!6I>|lFtIZ(Xbb*8)6WL#YtKt^JMp%9@* zD&XPEVX{CPbG0pA6hXmxOfZ3RI7$u)m_P+&kU)6tMnV2_m<7g_o$9p4T#RGfycqNu z$JkFelVKbOZZ07s)BB7wZvDlZOTMM3_7jvCpq00ltEQ1YU} zNaz|6*o-SzsmfHkvXyXYlqpk*OQI|!LMe1qI5rTDRgSU%6kFH2-~xdNMMy%$AxiJo z)u?I~CmY!KEw;>NIJD7D7)zN}vD`NNG+fdeZ_#AORr&06QoN BwtoNs literal 0 HcmV?d00001 diff --git a/doc/t2do.gif b/doc/t2do.gif new file mode 100644 index 0000000000000000000000000000000000000000..26a662bd7337577d8823f034162fbb5e96e2883c GIT binary patch literal 8395 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 B!y^Cy literal 0 HcmV?d00001 diff --git a/doc/users_guide.html b/doc/users_guide.html new file mode 100644 index 0000000..9f582a0 --- /dev/null +++ b/doc/users_guide.html @@ -0,0 +1,751 @@ + + + + + + + + +


+
  +
  +

+Users Guide to RSL.

+ +

+What is RSL good for?

+The best feature of RSL is the ability to ingest many different RADAR data +file formats with a single library call. It can, also, read compressed +files -- compressed with GZIP or the older COMPRESS. The routine is called +RSL_anyformat_to_radar. +You give it a filename and it will return a pointer to a C structure called +Radar. +The structure Radar contains all the information found in the input file. +The structure is intended to represent a superset of all RADAR data formats. +

Below, is a table listing the input/output routines supplied in RSL. +You will notice that there are only two output routines. RSL, by design, +is not a format converter, but, a library to facilitate reading and manipulation +of RADAR data. Output for UF and HDF are supplied because of the popularity +of those two formats. +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+Data format

+
+

+Input routine

+
+

+Output routine

+
HDF 1B-51 and 1C-51RSL_hdf_to_radarRSL_radar_to_hdf
Lassen (Darwin)RSL_lassen_to_radarNone
WSR-88d (Nexrad)RSL_wsr88d_to_radarNone
UF (Universal Format from NCAR)RSL_uf_to_radarRSL_radar_to_uf
SIGMET (Version 1)RSL_nsig_to_radarNone
SIGMET (Version 2)RSL_nsig2_to_radarNone
McGill RSL_mcgill_to_radarNone
TOGA RSL_toga_to_radarNone
RAPIC (Berrimah) RSL_rapic_to_radarNone
RADTEC (SPANDAR)RSL_radtec_to_radarNone
EDGERSL_edge_to_radarNone
+RSL is designed to provide you with a uniform data structure so that you +can design RADAR independent science applications. You no longer need to +wrestle over the input data format and have a different version of your +algorithm for each different RADAR format you may need to analyze. +

This paper presents RSL from a science application developer's point +of view. It will present some of the more useful routines and which fields +in the Radar structure that will be +important to you and it will attempt to cover some of the programming pitfalls +associated with RSL usage. One of the most difficult hurdles to overcome +is that RSL makes extensive use of pointer syntax. You will find yourself +becoming expert with C pointers. However, the design of RSL makes it possible +to use C pointers painlessly. +

+Ok, I have some data, how do I look at it?

+Let's first make some images. To do that you need only 3 RSL functions: +

RSL_anyformat_to_radar +
RSL_load_refl_color_table +
RSL_volume_to_gif +

The C program you need is incredibly short. It illustrates how to ingest +radar data and create a GIF image of the DZ (reflectivity) field: +

#include "rsl.h"
+void main(int argc, char **argv)
+{
+  Radar *radar;
+  radar = RSL_anyformat_to_radar("radar.dat", NULL);
+  RSL_load_refl_color_table();
+  RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0);
+}
+The line: +

#include "rsl.h" +

is required when using the RSL. It defines important constants and declares +all the RSL functions that your application may need. +

The line: +

Radar *radar;
+declares the radar pointer. Only a pointer to a radar should be declared, +because, the ingest routines allocate all the space to hold all the appropriate +substructures: Volume, Sweep, +Ray, +and Range. +

The line: +

radar = RSL_anyformat_to_radar("radar.dat", NULL);
+performs the actual ingest of data. The input file is called radar.dat. +RSL_anyformat_to_radar +automatically +determines the type of radar data being read. It can handle *.gz or *.Z +files transparently. Reading gzip or compress files is faster, especially +over NFS.   Generally, reading compressed radar files is faster +because of how UNIX pipes are implemented and that the compression is nearly +90%.   The second argument, NULL, is optional. A second argument +is needed only when reading WSR-88D data. The WSR-88D site information +is provided in the first physical file on the 8mm tape, but, it is used +to fill lat/lon and other radar-site specific information when reading +the 2nd through last physical files on the tape. +

Note: RSL_anyformat_to_radar +can't handle every radar format for which there is an RSL ingest routine. +But, it does a good job at recognizing most formats. Currently, TOGA and +MCGILL files cannot be automatically detected. In those cases, use: RSL_toga_to_radar +and RSL_mcgill_to_radar. +

While basic image generation is provided in RSL, it is never intended +to be anything more than a diagnostic tool. Several assumptions are made, +but, the image generation functions provided are useful. This is what the +last two lines illustrate. First you must define a color table. That is +done with: +

RSL_load_refl_color_table();
+then, to generate disk files, gif images, you must call one of the image +generation functions, as in: +
RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0);
+This routine will generate several images, one for each sweep, mapping +the image to a 400 x 400 km grid, using a 1 x 1 km spacing, by collecting +data out to 200 km. +

Making images of velocity data, VR_INDEX, involves two more +steps that are not very obvious. Because of the limited range of the values +presented in velocity data, you must re-bin the data. Do that with any +one of the following: +

RSL_rebin_velocity_sweep,
+RSL_rebin_velocity_volume
+The second step is that you must call: +
RSL_load_vel_color_table();
+The nyquist velocity is used to determine the limits of the re-binning. +These +functions modify the data in a sweep, or volume. So, it is wise to +make copies of the sweep, or volume, if you plan on using the data later +in your application. Normally, though, making velocity images is the last +step of a program, therefore, you don't need to copy the velocity volume +as your program will be exiting shortly. RSL provides a number of color +table manipulation functions. You are not limited by the default settings +for DZ, VR, and SW color tables. You can specify any color table mapping +you wish. +

+Whoopty doo, I really wanted to examine the values.

+In order to get to values in the Radar +structure, you have to trickle down all the substructues. The structures, +in order of nesting are: Radar, Volume, +Sweep, +Ray, +Range. +Each of these structures is presented in that order. You will notice a +common organization across all of the structures -- each structure contains +a header and contains an array of pointers to the next substructure. +

+The Radar structure

+Ok, make the call to RSL_anyformat_to_radar +as above, so that you get a pointer to a radar. The structure Radar +is the most general structure in RSL. Radar is composed of two parts: +
    +
  • +Radar header.
  • + +
  • +Array of pointers to Volumes.
  • +
+The radar header, will be presented and described fully later, but, it +contains general information about the entire structure. To access the +radar header use the syntax: +
Radar *radar;
+radar->h.member;
+The array of pointers to Volumes contains +either pointers to Volumes of data +or NULL. The number of possible Volumes +in the radar is specified by radar->h.nvolumes. This number represents +the length of the array of pointers to Volumes +and not the number of actual (non-NULL) volumes in the radar. The index +of this array of pointers to Volumes +is the field type index. There are MAX_RADAR_VOLUMES (currently set to +19) field types defined in RSL. Each field type index has a specific value. +That value is illustrated in the table below. RSL ingest routines guarentee +that the length of the array of pointers to Volumes, +radar->v, +is exactly the maximum number of field types, MAX_RADAR_VOLUMES. This is +done so that you can check for the existance of a field type with the syntax: +
if (radar->v[XZ_INDEX]) /* XZ exists */
+Normally, radar->h.nvolumes is set to the length of the array +of pointers to Volumes, radar->v. +Because C array indexes start at 0, you should use a test similiar to: +ivol < radar->h.nvolumes. The maximum value for radar->h.nvolumes +is MAX_RADAR_VOLUMES which is a constant in RSL. The value for radar->h.nvolumes +could be less though. But, you can rest assured that you can test for the +existance of a field type simply by using the hard coded index name as +specified in the table below. +

There are basically two methods for indexing the array of pointers to +Volumes: +

    +
  • +Use the index name, eg. CZ_INDEX or its value.
  • + +
  • +Use a variable that ranges from 0 to radar->h.nvolumes-1.
  • +
+Here are two coding examples that demonstrate how to access the array of +pointers to volumes. +

Example 1: +

Radar *radar;
+Volume *volume;
+
+volume = radar->v[CZ_INDEX];
+if (volume != NULL) {
+   /* Do something with volume. */
+}
+Example 2: +
Radar *radar;
+Volume *volume;
+int i;
+
+for (i=0; i<radar->h.nvolumes) {
+   volume = radar->v[i];
+   if (volume == NULL) continue; /* skip this NULL volume */
+   /* Do something with volume. */
+}
+It is very important that you check for the volume pointer being NULL. +It is very common that radar->h.nvolumes is larger than the number +of non-NULL volumes present in radar. By default, radar->h.nvolumes +is the length of array of pointers to Volumes. +The volumes are also known as field types. There are several field types +and a Volume can be only one field +type. The entire list of field types is presented in the table below. To +reference a particular field, you use a simple syntax: +

radar->v[DZ_INDEX] +
radar->v[VR_INDEX] +

Each field type encountered has a specific index within the radar->v +array of pointers to Volumes. The +field type indexes are hard-coded and are defined to be specific numbers +starting at 0. Hard-coded field type indexes simplifies the syntax for +accessing volumes. When there is no volume for a particular field type, +the volume pointer is NULL. This is ok, as NULL is a perfectly acceptable, +albeit useless, volume. Here is a table of all the field type indexes used +in RSL. +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+INDEX NAME

+
+

+Value

+
+

+Description

+
DZ_INDEX0Reflectivity (dBZ)
VR_INDEX1Radial Velocity (m/s)
SW_INDEX2Spectral Width (m2/s2)
CZ_INDEX3QC Reflectivity (dBZ)
ZT_INDEX4Total Reflectivity (dBZ)
DR_INDEX5Differential reflectivity
LR_INDEX6Another differential refl.
ZD_INDEX7Reflectivity Depolarization Ratio  +

ZDR = 10log(ZH/ZV) (dB)

DM_INDEX8Received power (dBm)
RH_INDEX9Rho: Correlation coefficient
PH_INDEX10Phi (MCTEX parameter)
XZ_INDEX11X-band reflectivity
CR_INDEX12Corrected DR reflectivity (differential).
MZ_INDEX13DZ mask volume for HDF 1C-51 product.
MR_INDEX14DR mask volume for HDF 1C-51 product.
ZE_INDEX15Edited reflectivity.
VE_INDEX16Edited velocity.
KD_INDEX17KDP (unknown) for MCTEX data.
TI_INDEX18TIME (unknown) for MCTEX data.
+ +

+The Volume structure

+The Volume structure represents the RADAR data for one, and only one, field +type. Upon ingest, the data for each field type is separated and placed +into separate volumes. This makes it convenient to manipulate volumes based +on their field type. +

The organization of the Volume structure closely resembles the organization +of the Radar structure. It, too, is compose of two parts: +

    +
  • +Volume header.
  • + +
  • +Array of pointers to Sweeps.
  • +
+To access elements in the Volume header, you use the syntax: +
Volume *volume;
+volume->h.member;
+You can find a description of each volume header member later. The array +of pointers to Sweeps contains either +pointers to Sweeps of data or NULL. +The number of possible Sweeps in the +Volume is specified by volume->h.nsweeps. This number represents +the length of the array of pointers to Sweeps +and not the number of actual (non-NULL) sweeps in the volume. +

There are two methods to accessing sweeps: +

    +
  • +Use a loop index that ranges from 0 to volume->h.nsweeps-1.
  • + +
  • +Use RSL_get_sweep or other similiar RSL +sweep retieval functions.
  • +
+Here are two coding examples that demonstrate how to access the array of +pointers to sweeps. +

Example 1: +

Volume *volume;
+Sweep *sweep;
+int i;
+
+/* Assume a non-NULL volume at this point. */
+for (i=0; i<volume->h.nsweeps; i++) {
+   sweep = volume->sweep[i];
+   if (sweep == NULL) continue; /* Skip NULL sweeps. */
+   /* Do something with this sweep. */
+   printf("Sweep %d elevation is %f\n", i, sweep->h.elev);
+}
+Example 2: +
Volume *volume;
+Sweep *sweep;
+float elev;
+
+/* No assumption about volume, it *can* be NULL! */
+/* That's because RSL_get_sweep checks it. */
+elev = 2.0;
+sweep = RSL_get_sweep(volume, elev);
+if (sweep != NULL)
+   printf("Sweep %d elevation is %f\n", i, sweep->h.elev);
+Again, it is very important to check for NULL sweeps. By default volume->h.nsweeps +is the length of the array of pointers to Sweeps. +

+The Sweep structure

+The Sweep represents the data collected for one field type during one 360o +revolution of the RADAR. Like the Radar and Volume structures, the Sweep +organization is composed of two parts: +
    +
  • +Sweep header.
  • + +
  • +Array of pointers to Rays.
  • +
+To access elements in the Sweep header, you use the syntax: +
Sweep *sweep;
+sweep->h.member;
+A description of each member of the Sweep header is presented later. The +array of pointers to Rays contains either +pointers to Rays of data or NULL. The +number of possible Rays in the Sweep +is specified by sweep->h.nrays. This number represents the length +of the array of pointers to Rays and +not the number of actual (non-NULL) rays in the Sweep. +

There are two methods to accessing rays: +

    +
  • +Use a loop index that ranges from 0 to sweep->h.nrays-1.
  • + +
  • +Use RSL_get_ray or other similiar RSL ray +retieval functions.
  • +
+Here are two coding examples illustrating how to access the array of pointers +to Rays. +

Example 1: +

Sweep *sweep;
+Ray *ray;
+int i;
+
+/* Assume a non-NULL sweep at this point. */
+for (i=0; i<sweep->h.nrays; i++) {
+   ray = sweep->ray[i];
+   if (ray == NULL) continue; /* Skip NULL rays. */
+   /* Do something with this ray. */
+   printf("Ray %d azimuth is %f\n", i, ray->h.azimuth);
+}
+Example 2: +
Volume *volume;
+Ray *ray;
+float elev, azimuth;
+
+/* No assumption about volume, it *can* be NULL! */
+/* That's because RSL_get_ray checks it. */
+elev = 2.0;
+azimuth = 30.2;
+ray = RSL_get_ray(volume, elev, azimuth);
+if (ray != NULL)
+   printf("Ray %d elevation is %f, azimuth is %f\n", i, ray->h.elev, ray->h.azimuth);
+You never know when you'll encounter NULL rays, so, make sure you test +for it. By default, sweep->h.nrays is the length of the array of pointers +to Rays which may or may not be the number +of non-NULL Rays present. +

+The Ray structure

+A ray of RADAR measurements represents data collected from close to the +RADAR to some maximum physical range. The Ray, +too, is composed of two parts: +
    +
  • +Ray header.
  • + +
  • +Array of field type measurements. These are not pointers. It is an array +of values.
  • +
+We're getting close to the data, now. The ray header contains the largest +collection of members and describe all characteristics of the ray. To access +elements in the Ray header, you use the syntax: +
Ray *ray;
+ray->h.member;
+A description of each member of the Ray header is described later. The +array of field type measurements contains the data, finally. The data type +for the data is Range. The Range +data type must be converted to float by using the function that is in ray +header: ray->h.f(r), where r is of type Range. +These conversion functions are in the headers for the volume and sweep. +They are there only as a convenience to the application developer. The +number of data values in the Rays is specified by ray->h.nbins. +This number represents the length of the array of Range +values. There is no abiguity here, the number of data values (Range +values) exactly matches ray->h.nbins. +

There are two methods to accessing the data: +

    +
  • +Use a loop index that ranges from 0 to ray->h.nbins-1 calling +the ray->h.f function.
  • + +
  • +Use RSL_get_value or other similiar RSL +get value functions.
  • +
+Here are two coding examples illustrating how to access the array of Range +values.. +

Example 1: +

Ray *ray;
+int i;
+float x;
+
+/* Assume a non-NULL ray at this point. */
+for (i=0; i<ray->h.nbins; i++) {
+   x = ray->h.f(ray->range[i]);
+   /* Do something with this floating point value 'x'. */
+   printf("BIN %d value is %f\n", i, x);
+}
+Example 2: +
Volume *volume;
+float x;
+float elev, azimuth, range;
+
+/* No assumption about volume, it *can* be NULL! */
+/* That's because RSL_get_value checks it. */
+elev = 2.0;
+azimuth = 30.2;
+range = 87.3; /* KM */
+x = RSL_get_value(volume, elev, azimuth, range);
+ +

+No assumptions as to the validity of the data.

+The RSL does not modify the data in any way. It merely, loads the data +into the Radar structure. For instance, during the MCTEX experiment, the +azimuth values were incorrect for the first four tapes. They remain incorrect. +It is up to you to write a conversion procedure that corrects the problem. +

+Pitfalls when using RSL in an application.

+Here are some common mistakes made and things you should observe. +
    +
  1. +Not checking for NULL. It is very important to check for NULL pointers. +In the RSL context, NULL is a perfectly valid ray, sweep or volume. Blindly +assuming that a volume, sweep, or ray exists is asking for trouble. When +using an RSL interface routine, a routine that is prefixed with RSL_, +you don't have to worry too much about passing null pointers. RSL routines +check their arguments.
  2. + +
  3. +Not checking for NULL, when passing a volume, sweep, or ray pointer into +a routine. Check for NULL immediately.
  4. + +
  5. +Not using the value for radar->h.nvolumes, volume->h.nsweeps, +sweep->h.nray. +They represent the maximum index possible and not the actual number of +non-NULL structures. Remember a NULL sweep, in RSL, is a valid sweep; you +just can't do anything with it. If you want to know how many non-NULL volumes +you have, you'll have to count them yourself. Do that by looping from 0 +to radar->h.nvolumes - 1.
  6. + +
  7. +Not using the value for radar->h.nvolumes, volume->h.nsweeps, +sweep->h.nrays, +and ray->h.nbins for the current object. Never assume that the +values are constant throughout the radar structure. They constantly change. +For instance, the number of bins may decrease as the sweep elevation increases.
  8. + +
  9. +Not converting the data in the Radar, +Volume, +Sweep, +Ray, +(really the Ray) to floating point before comparing with anything, including +comparing it with BADVAL, RFVAL, APFLAG, NOECHO. Do this conversion with +the h.f(c), where c is ray->range[i] and is +of type Range. For example:
  10. + +
      +

      +

    x = ray->h.f(ray->range[ibin]); +

  11. +Not converting a floating point number to internal storage with h.invf(x), +where x is of type float, before filling the range array. For +example:
  12. + +
      +

      +

    ray->range[ibin] = ray->h.invf(x); +

  13. +Forgetting to load a color table before calling an image generation function. +If you don't load a color table, your images will be black.
  14. + +
  15. +Not rebinning the velocity data before making velocity images. The default +color table is setup to cover the range of -nyquist to +nyquist.
  16. +
+ + + diff --git a/doc/whats_new.gif b/doc/whats_new.gif new file mode 100644 index 0000000000000000000000000000000000000000..8c0957b4ce9c3ddf23d8fbdde6d04a3329e47d0d GIT binary patch literal 1030 zcmV+h1o`_%Nk%w1VFLjr0P_F<0002L0002L0KdNg006(g0KWjgzreu2fPjGi00030 z0RR60009600RI60|NsC0A^8LW000L7EC2ui00RLf07C@-@W@H4y*TU5yZ>M)j$~ zt7qb=ChoFn>CLnD&SG=;ru|MH$3JOUTXkq*Q!YtYZ$?IkhH`pNeI7zbewA%|mV1Ak zQ7=zmp@5hqVVPc^JXTPPgpN@hf|8MHwy>GEx{#^0XuCx-g{hRnqOV_`kIBlaz;%S;tO6Ow5h+RH#F!sV(45r_CPX?rHU6ALQ(eU`_>`R_nN%mMi5hz?g*nRTl&Qn?6$&Ylq0neI zbHSWI<{$4%}ekyKIAC01VC|Yvv$NA)!5y6efw#3laq16 zaEfABo9h*AQnel}H;${1ZMnL0?p?-=*zH>!q9q676WUqcfe{A}?fWF(7R>l{Wy?Q% zlFOu9^#|O07>|K|ed0dz>)+46f65j9iR4B9fMpP~UJD0qR-kOV1QlIZ1S04lcghqu zpd_{hmLP>AIQU>V0ba+3Q4f9tn1>~LLYIjgszH`tm{hYGi2d~jAT_g<2pMP}mZPI~ zV%^9|i^ZTfkBk;6$P{KLedO7Qc=5=ZR^i!VoRa_e6XlSaVTnzZj)520UeLr=kA_ZN zxK%eUCMo4&Yx#ytT*Bp|O(|<;gZN6TSjjm^7&AI4BwlNf#*kZR(rH~XNcq^O zSEocqBXpAvibQ9ar2^G5s-+kYcR&)hC!dc(nih38RnnBA!3kRAmA;HvXs8#x`l6n~ z$?7OjXD0VptG4pw>sgNyNtl*ueP$`MtGL2>ESG#KJL+V?f=cMHC+c?1w2XC|7^bu} z`;@7vb_wTjnPsLdw!>D!9x3A(a@B!UpfH6H~euM;LqhtjYubSsKE- zo;E0%0H-65Zb#N@GME~8Y~Or#;wfFs{4~lgFMGa>G=)H;^xn|~j+!-r5S$1AJH@T> A`2YX_ literal 0 HcmV?d00001 diff --git a/doc/whats_new.html b/doc/whats_new.html new file mode 100644 index 0000000..7f430e0 --- /dev/null +++ b/doc/whats_new.html @@ -0,0 +1,185 @@ + + + + + + + + +
+
  +
  +

+What's new?

+ +

+07/24/2008: Version 1.39 supports WSR-88D Level II Build 10 format.

+

+02/15/2006: Version 1.34 supports WSR-88D Level II Build 8 format.

+RSL can read both the old and new WSR-88D Level II data format. +

+Version 1.33 supports WSR-88D Level II Build 5 format.

+RSL can read both the old and new WSR-88D Level II data format. + +

+Version 1.25 release (what's new since v1.24).

+Merged changes from version 1.24.1.  Also, HDF routines are back +as not having them in the library caused more problems than it was worth.  +But, the most significant change is that the entire package is configured +by the configure script (provided).  Building the package is +done in two steps.  This is a dramatic improvment over previous releases. +

+Version 1.24.1 release (what's new since v1.24).

+Removed the HDF component.  Those routines are now part of gvs, where +they belong.  However, basic support in RSL_anyformat_to_radar +will exist for HDF -- it will still recognize an HDF file and call +RSL_hdf_to_radar.  +RSL_hdf_to_radar is located in gvs/gvslib.  To configure HDF into +RSL, specify -DHAVE_TSDIS_TOOLKIT in the Makefile. +

Added project[24] to the radar->h +structure. +

+Version 1.23 release (what's new since v1.18).

+RSL now accpets the EDGE format.  See RSL_edge_to_radar.  +KDP definition changed.  It now normalizes the value based on the +radar wavelength.  A bug in the RADTEC ingest routine was removed.  +Other than that, mostly bug fixes that were very minor.  Added RSL_set_color_table +and RSL_get_color_table.  These +routines permit better user control of the color table. +

+Version 1.18 release (what's new since v1.15).

+This version adds the RADTEC format ingest routine.  See RSL_radtec_to_radar.  +RADTEC requires the use of the PKWARE Data Compression Library, available +from PKWARE, Inc., http://www.pkware.com.  Also made several minor +bug fixes and the image generation was enhanced to allow generation of +images out to the range specified.  Previously,  image pixels +were 1km, now they are range/radius. +

+Version 1.15 release (what's new since v1.14).

+This version  adds  the RAPIC format ingest routine.  See +RSL_rapic_to_radar.  +A data truncation bug was fixed in the UF ingest.  This bug only affects +the velocity data.  The Lassen ingest no longer depends on (radar->h.name),  +for calibration of Gunn Point data.  It is now done based on time +periods of the data.  Please see the CHANGES +file for more information. +

+Version 1.14 release (what's new since v1.11).

+This version continues the minor bug fixes to the HDF component.  +Additionally, it includes calibration for the Gunn Point radar, in Lassen +format.   The distinction of Gunn Point data from other lassen +data is done by assumming the radar name (radar->h.name) is 'Gunn_Pt'.  +Please see the CHANGES file for more information. +

+Version 1.11 release (what's new since v1.8).

+Version 1.9 represented a bug fix to the HDF component.  Version 1.10 +represented a minor +
upgrade, mostly to the HDF component, but, other areas were modified +and that's why it is called an upgrade rather than a bug fix.  Version +1.11 represents a minor bug fix release from v1.10.  It only affects +the +
HDF components.   Please see the CHANGES +file for more detailed information regarding what changed. +

In version 1.10, ZDR color tables were modifed and a first draft of +the South Africa data format ingest routine was added. +
  +

+Version 1.8 release (what's new since v1.7).

+Added RSL_read_these_sweeps.  +Specify specific sweep numbers for ingest.  This drastically speeds +up ingest, if you're only interested in the first or first couple of sweeps.  +For example, making base scans images. +

Added RSL_load_zdr_color_table. +

More HDF mods; more warning messages. +

The TRMM Office has fixed several bugs in the TSDIS toolkit. For proper +HDF creation, that conforming to TSDIS HDF specifications, you will need +toolkit 4.5r1.1. Toolkit 4.5r1.1 is an unofficial release; the TRMM office +will pass this out upon request. +
  +

+Version 1.7 release (what's new since v1.6).

+This version fixes the lat/lon signs.  Also, lat/lon are added to +each ray for UF when extended headers are available in SIGMET files.  +Also, the HDF component has changed.  This affects RSL_radar_to_hdf +and RSL_hdf_to_radar. +

+Version 1.6 release (what's new since v1.5).

+This version of RSL will work with TSDIS toolkit 4.5r1.  UF now has +lat/lon stored for each ray, suitable for moving platforms.  Also, +the wsr88d code does not default to KMLB. +

+Version 1.5 release (what's new since v1.4).

+The HDF component has changed again. This version of RSL will work with +toolkit 4.0 or toolkit 4.0.1. Version 4.0.1 is an un-official release of +the TSDIS toolkit. This version removes the temporary files created during +level 1 processing. There was only one file that changed, the file may +be obtained from the TRMM Office, upon request. +

One minor consistancy check was added to the wsr88d ingest; it checks +that the number of bins in a ray is reasonable. This problem usually manifests +itself from bad input files. +

+Version 1.4 release (what's new since v1.0).

+The HDF component is in a state of flux. The TSDIS +toolkit keeps changing -- the interface keeps changing. The TSDIS toolkit +is, in the TRMM Office opinion, not stable. Their latest release is 4.0 +and it has fixed many problems. One minor problem remains for level 1 processing: +temporary config files are not removed when the toolkit is closed. +

RSL is incorporated into a larger package called GVBOX. The latest version +of GVBOX is 1.1. GVBOX is a complete ground validation system to generate +TRMM GV products on pentium PCs running Linux. GVBOX is available on CDROM. +

RSL is now LGPL-ed. +

Added the routine RSL_select_fields +to reduce memory requirements upon reading data. This works very nicely +for LASSEN data where the number of fields is large, however, only 2 or +3 are needed. +

+Version 1.0 release (what's new since v0.45).

+Version 1.0 marks the jump from the previous stable version, version 0.45. +A few very minor bugs were encountered and repaired. But, the bulk of this +transisition is improved documentation with the addition of a Users Guide. +Additionally, the SIGMET ingest was repaired and can now read version 2 +files, HDF I/O was added and the LASSEN ingest modified to read version +1.4 files. Version 1.4 LASSEN files were used during the MCTEX experiment. +Other than that, no major modifications were made. Technically, version +1.0 is a minor upgrade to RSL 0.45. But, due to the witnessed stability +of RSL, it was decided to call it version 1.0. +
  +

+Can read compressed files automatically (new since v0.41)

+Transparent, to all ingest routines the capability of filtering the input +data file through the GNU gzip program for decompressing the file has been +added. This feature does not appear to slow the I/O time and, in some cases, +especially on 486 pc's, improves overall throughput time. Two generic, +internal routines, have been added: compress_pipe and uncompress_pipe. +Each routine takes a FILE * and redirects it through gzip. +Each routine returns a new FILE *. Wsr88d files occupy 1/10 the +disk space when compressed and the TRMM Office plans to compress wsr88d +files to CDROM and 8mm tape for overall throughput savings for the production +system. It will no longer be necessary to decompress the data before processing +level 1. +

Similiarly, UF output can be saved using the gzip filter. The new routine +added is RSL_radar_to_uf_gzip which +utilizes the gzip compression filter. +

+Can read stdin (new since v0.39)

+A new routine is provided called RSL_uf_to_radar_fp +which takes an open file descriptor and returns a radar pointer. That file +pointer can be stdin. This special interface syntax, for the UF +ingest, is an exception to the interfaces that the other ingest routines +have. All other ingest routines, including RSL_uf_to_radar, +have been modified to read stdin when the input filename is NULL. The complete +list of routines is: RSL_wsr88d_to_radar, +RSL_nsig_to_radar, +RSL_lassen_to_radar, +RSL_uf_to_radar, +RSL_mcgill_to_radar +and RSL_toga_to_radar. The only routine +that will not accept stdin will be RSL_anyformat_to_radar. +That routine will not be able to handle reading stdin because it needs +to read the first few bytes of the file to determine which ingest routine +to call. If you plan to make a filter program, you'll just have to know +what file format you expect: UF, nsig, wsr88d, etc. +
  +
  + + diff --git a/doc/x_to_radar.fig b/doc/x_to_radar.fig new file mode 100644 index 0000000..eaf4ba9 --- /dev/null +++ b/doc/x_to_radar.fig @@ -0,0 +1,48 @@ +#FIG 2.1 +80 2 +6 114 409 229 524 +4 0 0 15 0 -1 0 0.00000 4 19 91 114 429 toga_to_radar +4 0 0 15 0 -1 0 0.00000 4 19 111 114 452 wsr88d_to_radar +4 0 0 15 0 -1 0 0.00000 4 19 102 114 475 lassen_to_radar +4 0 0 15 0 -1 0 0.00000 4 19 77 114 498 uf_to_radar +4 0 0 15 0 -1 0 0.00000 4 19 90 114 521 nsig_to_radar +-6 +6 454 409 564 454 +6 454 409 564 454 +4 0 0 15 0 -1 0 0.00000 4 19 77 454 429 radar_to_uf +4 0 0 15 0 -1 0 0.00000 4 19 107 454 452 radar_to_dorade +-6 +-6 +1 1 0 1 -1 0 0 0 0.00000 1 0.000 324 229 90 35 324 229 414 264 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 154 144 234 224 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 144 209 234 229 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 144 259 234 234 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 159 319 239 239 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 189 89 239 219 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 414 229 529 184 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 414 229 524 224 9999 9999 +4 1 0 20 0 -1 0 0.00000 4 22 47 324 239 Radar +4 1 0 20 0 -1 0 0.00000 4 22 53 109 214 Lassen +4 1 0 20 0 -1 0 0.00000 4 22 25 124 264 UF +4 1 0 20 0 -1 0 0.00000 4 22 55 124 144 wsr88d +4 1 0 20 0 -1 0 0.00000 4 22 39 164 89 Toga +4 1 0 20 0 -1 0 0.00000 4 22 113 139 339 New SIGMET +4 1 0 20 0 -1 0 0.00000 4 22 25 549 189 UF +4 0 0 20 0 4 0 0.00000 4 22 56 534 229 Dorade +4 1 0 30 0 -1 0 0.00000 4 37 255 399 104 Format conversion. +4 1 0 18 0 -1 0 0.00000 4 22 122 174 404 Ingest functions +4 1 0 18 0 -1 0 0.00000 4 22 131 514 399 Output functions diff --git a/dorade.c b/dorade.c new file mode 100644 index 0000000..6c692bf --- /dev/null +++ b/dorade.c @@ -0,0 +1,616 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1999 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include "dorade.h" + +int dorade_verbose = 0; + +void dorade_verbose_on() +{ + dorade_verbose = 1; +} +void dorade_verbose_off() +{ + dorade_verbose = 0; +} + +/**********************************************************************/ +/* */ +/* dorade_read_comment_block */ +/* */ +/**********************************************************************/ +Comment_block *dorade_read_comment_block(FILE *in) +{ + Comment_block *cb; + cb = (Comment_block *) calloc(1, sizeof(Comment_block)); + if (cb == NULL) { + perror("dorade_read_comment_block"); + return NULL; + } + fread(cb->code, sizeof(cb->code), 1, in); + fread(&cb->len, sizeof(cb->len), 1, in); cb->len = ntohl(cb->len); + cb->comment = (char *) calloc(cb->len, sizeof(char)); + if (cb->comment == NULL) { + perror("dorade_read_comment_block: cb->comment"); + return cb; + } + fread(cb->comment, sizeof(char), cb->len, in); + return cb; +} + +/**********************************************************************/ +/* */ +/* dorade_read_volume_desc */ +/* */ +/**********************************************************************/ +Volume_desc *dorade_read_volume_desc (FILE *in) +{ + Volume_desc *vd; + + vd = (Volume_desc *) calloc(1, sizeof(Volume_desc)); + if(!vd) { + perror("dorade_read_volume_desc"); + return NULL; + } + + fread(vd, sizeof(Volume_desc), 1, in); + /* Now, convert from Big Endian. */ + vd->len = ntohl(vd->len); + vd->version = ntohs(vd->version); + vd->volume_number = ntohs(vd->volume_number); + vd->max_bytes = ntohl(vd->max_bytes); + vd->year = ntohs(vd->year); + vd->month = ntohs(vd->month); + vd->day = ntohs(vd->day); + vd->hour = ntohs(vd->hour); + vd->minute = ntohs(vd->minute); + vd->second = ntohs(vd->second); + vd->gen_year = ntohs(vd->gen_year); + vd->gen_month = ntohs(vd->gen_month); + vd->gen_day = ntohs(vd->gen_day); + vd->nsensors = ntohs(vd->nsensors); + return vd; +} + +extern int little_endian(void); +extern void swap_4_bytes(void *word); +extern void swap_2_bytes(void *word); + + +/* Sensor descriptor routines. */ +/**********************************************************************/ +/* */ +/* dorade_read_radar_desc */ +/* */ +/**********************************************************************/ +Radar_desc *dorade_read_radar_desc (FILE *in) +{ + Radar_desc *rd; + int i; + + rd = (Radar_desc *) calloc(1, sizeof(Radar_desc)); + if(!rd) { + perror("dorade_read_radar_desc"); + return NULL; + } + + fread(rd, sizeof(Radar_desc), 1, in); + /* Now, convert from Big Endian. */ + if (little_endian()) { + swap_4_bytes(&rd->len); + swap_4_bytes(&rd->radar_constant); /* Yes, even the ieee floating values. */ + swap_4_bytes(&rd->peak_power); + swap_4_bytes(&rd->noise_power); + swap_4_bytes(&rd->rcvr_gain); + swap_4_bytes(&rd->ant_gain); + swap_4_bytes(&rd->radar_system_gain); + swap_4_bytes(&rd->horizontal_beam_width); + swap_4_bytes(&rd->vertical_beam_width); + swap_2_bytes(&rd->radar_type); + swap_2_bytes(&rd->scan_mode); + swap_4_bytes(&rd->scan_rate); + swap_4_bytes(&rd->start_angle); + swap_4_bytes(&rd->stop_angle); + swap_2_bytes(&rd->nparam_desc); + swap_2_bytes(&rd->ndesc); + swap_2_bytes(&rd->compress_code); + swap_2_bytes(&rd->compress_algo); + swap_4_bytes(&rd->data_reduction_param1); + swap_4_bytes(&rd->data_reduction_param2); + swap_4_bytes(&rd->longitude); + swap_4_bytes(&rd->latitude); + swap_4_bytes(&rd->altitude); + swap_4_bytes(&rd->unambiguous_velocity); + swap_4_bytes(&rd->unambiguous_range); + swap_2_bytes(&rd->nfreq); + swap_2_bytes(&rd->npulse_periods); + for (i=0; i<5; i++) { + swap_4_bytes(&rd->freq[i]); + swap_4_bytes(&rd->period[i]); + } + } + return rd; +} +/**********************************************************************/ +/* */ +/* dorade_read_parameter_desc */ +/* */ +/**********************************************************************/ +Parameter_desc *dorade_read_parameter_desc (FILE *in) +{ + Parameter_desc *pd; + + pd = (Parameter_desc *) calloc(1, sizeof(Parameter_desc)); + if(!pd) { + perror("dorade_read_parameter_desc"); + return NULL; + } + + fread(pd, sizeof(Parameter_desc), 1, in); + /* Now, convert from Big Endian. */ + if (little_endian()) { + swap_4_bytes(&pd->len); + swap_2_bytes(&pd->ipp); + swap_2_bytes(&pd->xmit_freq); + swap_4_bytes(&pd->rcvr_bandwidth); + swap_2_bytes(&pd->pulse_width); + swap_2_bytes(&pd->polarization); + swap_2_bytes(&pd->nsamp_in_dwell_time); + swap_2_bytes(&pd->parameter_type); + swap_4_bytes(&pd->threshold_value); + swap_4_bytes(&pd->scale_factor); + swap_4_bytes(&pd->offset_factor); + swap_4_bytes(&pd->missing_data_flag); + } + return pd; +} + +/**********************************************************************/ +/* */ +/* dorade_read_cell_range_vector */ +/* */ +/**********************************************************************/ +Cell_range_vector *dorade_read_cell_range_vector (FILE *in) +{ + Cell_range_vector *cv; + char *buff; + int i; + + cv = (Cell_range_vector *) calloc(1, sizeof(Cell_range_vector)); + if(!cv) { + perror("dorade_read_cell_range_vector"); + return NULL; + } + + fread(&cv->code, sizeof(cv->code), 1, in); + fread(&cv->len, sizeof(cv->len), 1, in); + fread(&cv->ncells, sizeof(cv->ncells), 1, in); + if (little_endian()) { + swap_4_bytes(&cv->len); + swap_4_bytes(&cv->ncells); + } + cv->range_cell = (float *)calloc(cv->ncells, sizeof(float)); + if (!cv->range_cell) { + perror("dorade_read_cell_range_vector: cv->range_cell"); + return cv; + } + fread(cv->range_cell, sizeof(float), cv->ncells, in); + + if (little_endian()) { + for (i=0; incells; i++) + swap_4_bytes(&cv->range_cell[i]); + } + + /* Usually reading the range cells does not read to the end + * of the Cell_range_vector structure. We may be reading + * a non seekable device! + */ + i = cv->len /* Remove a few bytes that precede. */ + - sizeof(cv->code) + - sizeof(cv->len) + - sizeof(cv->ncells) + - cv->ncells*4; + buff = (char *)malloc(i); + if (!buff) return cv; + fread(buff, sizeof(char), i, in); + free(buff); + return cv; +} + +/**********************************************************************/ +/* */ +/* dorade_read_correction_factor_desc */ +/* */ +/**********************************************************************/ +Correction_factor_desc *dorade_read_correction_factor_desc(FILE *in) +{ + Correction_factor_desc *cf; + + cf = (Correction_factor_desc *) calloc(1, sizeof(Correction_factor_desc)); + if(!cf) { + perror("dorade_read_correction_factor_desc"); + return NULL; + } + + fread(cf, sizeof(Correction_factor_desc), 1, in); + /* Now, convert from Big Endian. */ + if (little_endian()) { + swap_4_bytes(&cf->len); + swap_4_bytes(&cf->azimuth); + swap_4_bytes(&cf->elevation); + swap_4_bytes(&cf->range); + swap_4_bytes(&cf->longitude); + swap_4_bytes(&cf->latitude); + swap_4_bytes(&cf->altitude); + swap_4_bytes(&cf->height); + swap_4_bytes(&cf->speed_east_west); + swap_4_bytes(&cf->speed_north_south); + swap_4_bytes(&cf->vertical_velocity); + swap_4_bytes(&cf->heading); + swap_4_bytes(&cf->roll); + swap_4_bytes(&cf->pitch); + swap_4_bytes(&cf->drift); + swap_4_bytes(&cf->rotation_angle); + swap_4_bytes(&cf->tilt_angle); + } + return cf; +} + +/**********************************************************************/ +/* */ +/* dorade_read_sensor */ +/* */ +/**********************************************************************/ +Sensor_desc *dorade_read_sensor (FILE *in) + + /* Read one 'Sensor #n' descriptor from FILE. */ +{ + Sensor_desc *sd; + int i; + + sd = (Sensor_desc *) calloc (1, sizeof(Sensor_desc)); + if (!sd) { + perror("dorade_read_sensor"); + return NULL; + } + + sd->radar_desc = dorade_read_radar_desc(in); + sd->nparam = sd->radar_desc->nparam_desc; + + sd->p_desc = (Parameter_desc **) calloc(sd->nparam, sizeof(Parameter_desc *)); + if (!sd->p_desc) { + perror("dorade_read_sensor: sd->p_desc"); + return sd; + } + for (i=0; inparam; i++) { + sd->p_desc[i] = dorade_read_parameter_desc(in); + } + + sd->cell_range_vector = dorade_read_cell_range_vector(in); + sd->correction_factor_desc = dorade_read_correction_factor_desc(in); + return sd; +} + + +/**********************************************************************/ +/* */ +/* dorade_read_sweep_info */ +/* */ +/**********************************************************************/ +Sweep_info *dorade_read_sweep_info(FILE *in) +{ + Sweep_info *si; + + si = (Sweep_info *) calloc(1, sizeof(Sweep_info)); + if(!si) { + perror("dorade_read_sweep_info"); + return NULL; + } + + fread(si, sizeof(Sweep_info), 1, in); + /* FIXME: ?? For now, VOLD is what we expect when there + * are no more SWIB. This is a data driven EOF. + * Returning NULL should suffice. + */ + if(strncmp(si->code, "SWIB", 4) != 0) { + /* Ignore the rest of the file. */ + free(si); + return NULL; + } + + /* Now, convert from Big Endian. */ + if (little_endian()) { + swap_4_bytes(&si->len); + swap_4_bytes(&si->sweep_num); + swap_4_bytes(&si->nrays); + swap_4_bytes(&si->start_angle); + swap_4_bytes(&si->stop_angle); + swap_4_bytes(&si->fixed_angle); + swap_4_bytes(&si->filter_flag); + } + + return si; +} + +/* Data Ray routines. */ + +/**********************************************************************/ +/* */ +/* dorade_read_ray_info */ +/* */ +/**********************************************************************/ +Ray_info *dorade_read_ray_info (FILE *in) +{ + Ray_info *ri; + + ri = (Ray_info *) calloc(1, sizeof(Ray_info)); + if(!ri) { + perror("dorade_read_ray_info"); + return NULL; + } + + fread(ri, sizeof(Ray_info), 1, in); + /* Now, convert from Big Endian. */ + if (little_endian()) { + swap_4_bytes(&ri->len); + swap_4_bytes(&ri->sweep_num); + swap_4_bytes(&ri->jday); + swap_2_bytes(&ri->hour); + swap_2_bytes(&ri->minute); + swap_2_bytes(&ri->second); + swap_2_bytes(&ri->msec); + swap_4_bytes(&ri->azimuth); + swap_4_bytes(&ri->elevation); + swap_4_bytes(&ri->peak_power); + swap_4_bytes(&ri->scan_rate); + swap_4_bytes(&ri->status); + } + + return ri; +} + +/**********************************************************************/ +/* */ +/* dorade_read_platform_info */ +/* */ +/**********************************************************************/ +Platform_info *dorade_read_platform_info (FILE *in) +{ + Platform_info *pi; + + pi = (Platform_info *) calloc(1, sizeof(Platform_info)); + if(!pi) { + perror("dorade_read_platform_info"); + return NULL; + } + + fread(pi, sizeof(Platform_info), 1, in); + /* Now, convert from Big Endian. */ + if (little_endian()) { + swap_4_bytes(&pi->len); + swap_4_bytes(&pi->longitude); + swap_4_bytes(&pi->latitude); + swap_4_bytes(&pi->altitude); + swap_4_bytes(&pi->height); + swap_4_bytes(&pi->ew_speed); + swap_4_bytes(&pi->ns_speed); + swap_4_bytes(&pi->v_speed); + swap_4_bytes(&pi->heading); + swap_4_bytes(&pi->roll); + swap_4_bytes(&pi->pitch); + swap_4_bytes(&pi->drift); + swap_4_bytes(&pi->rotation); + swap_4_bytes(&pi->tilt); + swap_4_bytes(&pi->ew_wind_speed); + swap_4_bytes(&pi->ns_wind_speed); + swap_4_bytes(&pi->v_wind_speed); + swap_4_bytes(&pi->heading_rate); + swap_4_bytes(&pi->pitch_rate); + } + + return pi; +} +/**********************************************************************/ +/* */ +/* dorade_read_parameter_info */ +/* */ +/**********************************************************************/ + +Parameter_data *dorade_read_parameter_data(FILE *in) +{ + Parameter_data *pd; + int len; + + pd = (Parameter_data *) calloc(1, sizeof(Parameter_data)); + if(!pd) { + perror("dorade_read_parameter_data: pd"); + return NULL; + } + + fread(&pd->code, sizeof(pd->code), 1, in); + fread(&pd->len, sizeof(pd->len), 1, in); + fread(&pd->name, sizeof(pd->name), 1, in); + if (little_endian()) swap_4_bytes(&pd->len); + /* Length is in parameter data block? or calculate if from pd->len. */ + + len = pd->len /* Use pd->len for now. */ + - sizeof(pd->code) /* Remove a few bytes from */ + - sizeof(pd->len) /* the count. */ + - sizeof(pd->name); + pd->data = (char *)calloc(len, sizeof(char)); + if (!pd->data) { + perror("dorade_read_parameter_data: pd->data"); + return pd; + } + fread(pd->data, sizeof(char), len, in); + + /* FIXME: Big endian conversion in caller? Is that the right place? */ + + return pd; +} +/**********************************************************************/ +/* */ +/* dorade_read_sweep */ +/* */ +/**********************************************************************/ +Sweep_record *dorade_read_sweep(FILE *fp, Sensor_desc **sd) +{ + Sweep_record *sr; + + Sweep_info *si; + Ray_info *ri; + Platform_info *pi; + Parameter_data *pd; + Parameter_desc **parameter_desc; + + int i, j, k,len; + int nparam; + + sr = (Sweep_record *) calloc (1, sizeof(Sweep_record)); + if (!sr) { + perror("dorade_read_sweep"); + return NULL; + } + + nparam = sd[0]->nparam; + parameter_desc = sd[0]->p_desc; + + /* Expect SWIB */ + sr->s_info = si = dorade_read_sweep_info(fp); + if (!si) { + free(sr); + return NULL; /* EOF or error. */ + } + sr->nrays = si->nrays; + if (dorade_verbose) { + printf("=====< NEW SWIB >=====\n"); + dorade_print_sweep_info(si); + } + sr->data_ray = (Data_ray **) calloc(si->nrays, sizeof(Data_ray *)); + if (!sr->data_ray) { + free(sr); + return NULL; /* EOF or error. */ + } + + for (i=0; inrays; i++) { + if (dorade_verbose) printf("---------- Ray %d ----------\n", i); + sr->data_ray[i] = (Data_ray *) calloc(1, sizeof(Data_ray)); + if (!sr->data_ray[0]) { + free(sr); + return NULL; /* EOF or error. */ + } + ri = dorade_read_ray_info(fp); + if (dorade_verbose) { + dorade_print_ray_info(ri); + } + pi = dorade_read_platform_info(fp); + if (dorade_verbose) { + dorade_print_platform_info(pi); + } + sr->data_ray[i]->ray_info = ri; + sr->data_ray[i]->platform_info = pi; + sr->data_ray[i]->parameter_data = (Parameter_data **) calloc(nparam, sizeof(Parameter_data *)); + sr->data_ray[i]->data_len = (int *) calloc(nparam, sizeof(int)); + sr->data_ray[i]->word_size = (int *) calloc(nparam, sizeof(int)); + sr->data_ray[i]->nparam = nparam; + + for (j=0; jlen /* Use pd->len for now. */ + - sizeof(pd->code) /* Remove a few bytes from */ + - sizeof(pd->len) /* the count. */ + - sizeof(pd->name); + sr->data_ray[i]->parameter_data[j] = pd; + sr->data_ray[i]->data_len[j] = len; + if (parameter_desc[j]->parameter_type == 2) + sr->data_ray[i]->word_size[j] = 2; /* 2 bytes per word */ + else if (parameter_desc[j]->parameter_type == 3 || + parameter_desc[j]->parameter_type == 4) + sr->data_ray[i]->word_size[j] = 4; /* 4 bytes per word */ + + if (little_endian()) { /* Numbers were read big-endian. */ + if (sr->data_ray[i]->word_size[j] == 2) + for (k=0; kdata[k]); + else if (sr->data_ray[i]->word_size[j] == 4) + for (k=0; kdata[k]); + } + } + } + return sr; +} + +/**********************************************************************/ +/* */ +/* dorade_read_ray */ +/* */ +/**********************************************************************/ +Data_ray *dorade_read_ray (FILE *in); + + +/* MEMORY MANAGEMENT ROUTINES */ + +/**********************************************************************/ +/* */ +/* dorade_free_data_ray */ +/* */ +/**********************************************************************/ +void dorade_free_data_ray(Data_ray *r) +{ + int i; + if (r == NULL) return; + + free(r->ray_info); + free(r->platform_info); + if (r->parameter_data) { + for (i=0; inparam; i++) + free(r->parameter_data[i]); + free(r->parameter_data); + } + free(r); +} + +/**********************************************************************/ +/* */ +/* dorade_free_sweep */ +/* */ +/**********************************************************************/ +void dorade_free_sweep(Sweep_record *s) +{ + int i; + if (s == NULL) return; + + if (s->data_ray) { + for (i=0; inrays; i++) + dorade_free_data_ray(s->data_ray[i]); + free(s->data_ray); + } + if (s->s_info) free(s->s_info); + free(s); +} diff --git a/dorade.h b/dorade.h new file mode 100644 index 0000000..941a25f --- /dev/null +++ b/dorade.h @@ -0,0 +1,324 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996-1999 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifndef _dorade_ +#define _dorade_ +#include + +typedef struct { + char code[4]; + int len; + char *comment; /* 0..len-1 of comments (N bytes ASCII, N%4==0 */ +} Comment_block; + +typedef struct { + char code[4]; /* Code identifier for the volume descriptor. (4 ASCII "VOLD") */ + int len; /* Length of the volume descriptor. (4 byte int) */ + short version; /* Version number of the format. (2 byte int) */ + short volume_number; /* Volume number from the begining of the data set. (2 byte int) */ + int max_bytes; /* Maximum number of bytes in a data record. (4 byte int) */ + char project_name[20]; /* Project name. (20 ASCII) */ + short year; /* Year YYYY e.g. 1999 (2 byte int) */ + short month; /* Month 1-12 (2 byte int) */ + short day; /* Day 1-31 (2 byte int) */ + short hour; /* Hour 1-23 (2 byte int) */ + short minute; /* Minute 0-59 (2 byte int) */ + short second; /* Second 0-59 (2 byte int) */ + char flight_num[8]; /* Flight number (8 ASCII) for airborne raar or IOP number + for ground based radars. */ + char facility_name[8]; /* Generation facility. (8 ASCII) */ + short gen_year; /* Generation year YYYY. (2 byte int) */ + short gen_month; /* Generation month 1-12. (2 byte int) */ + short gen_day; /* Generation day 1-31. (2 byte int) */ + short nsensors; /* Number of sennsor descriptors to follow. (2 byte int) */ +} Volume_desc; + +typedef struct { + char code[4]; /* Code identifier for the radar descriptor. (4 ASCII "RADD") */ + int len; /* Length of the radar descriptor. (4 byte int) */ + char radar_name[8]; /* Radar name. (8 ASCII) */ + float radar_constant;/* Radar constant. */ + float peak_power; /* Nominal Peak power. [kw] */ + float noise_power; /* Nominal Noise power. [dBm] */ + float rcvr_gain; /* Receiver gain. [dB] */ + float ant_gain; /* Antenna gain. [dB] */ + float radar_system_gain; /* [dB] */ + float horizontal_beam_width; /* [deg] */ + float vertical_beam_width; /* [deg] */ + short radar_type; /* 0--Ground + 1--Airborne fore + 2--Airborne aft + 3--Airborne tail + 4--Airborne lower fuselage + 5--Shipborne + */ + short scan_mode; /* 0--Calibration + 1--PPI (Constant elevation) + 2--Coplane + 3--RHI (Constant azimuth) + 4--Vertical pointing + 5--Target (Stationary, not vertical pointing) + 6--Manual + 7--Idle (out of control) + 8--Surveillance + 9--Vertical sweep (rotation axis parallels the fuselage) + */ + float scan_rate; /* Nominal scan rate. [deg/sec] */ + float start_angle; /* Nominal start angle. [deg] */ + float stop_angle; /* Nominal stop angle. [deg] */ + short nparam_desc; /* Total number of parameter descriptors for this radar. (2 byte int) */ + short ndesc; /* Total number of descriptors for this radar. (2 byte int) */ + short compress_code; /* Data compression format code. (2 byte int): + 0--no compression + 1--data compression (compression algorithm described + in the ASCII file athe the begining of the file. + */ + short compress_algo; /* Data reduction algorithm: + 0--No data reduction. + 1--Data recorded between two rotation angles. + 2--Data recorded between two concentic angles. + 3--Data recorded between two altitudes. + 4-N--Other types of data reduction. + */ + float data_reduction_param1; /* Data reduction specific parameter #1 + 1--Smallest positive angle [deg]. + 2--Inner circle diameter [km]. + 3--Minimum altitude [km]. + 4-N--Will be defined if other types created. + */ + float data_reduction_param2; /* Data reduction specific parameter #2 + 1--Largest positive angle [deg]. + 2--Outer circle diameter [km]. + 3--Maximum altitude [km]. + 4-N--Will be defined if other types created. + */ + float longitude; /* Radar longitude [deg]. If airborne, airport longitude. */ + float latitude; /* Radar latitude [deg]. If airborne, airport latitude. */ + float altitude; /* Radar altitude of mean sea level (msl) [km]. + If airborne, airport altitude. */ + float unambiguous_velocity; /* Effective unambiguous velocity [m/s]. */ + float unambiguous_range; /* Effective unambiguous range [km]. */ + short nfreq; /* Number of freqencies transmitted (2 byte int). */ + short npulse_periods; /* Number of different inter-pulse periods (IPP's) transmitted. + (2 byte int). */ + float freq[5]; /* Frequency 1..5 [GHz] (float) */ + float period[5]; /* Interpulse Period (IPP) 1..5 [ms] (float) */ +} Radar_desc; + +typedef struct { + char code[4]; /* Code identifier. (4 ASCII "PARM") */ + int len; /* Length of this descriptor. */ + char name[8]; /* Name of the parameter. */ + char description[40]; /* Description of the parameter. */ + char units[8]; /* Units (8 ASCII) */ + short ipp; /* Inter-pulse periods. + Bit 0 set to 1 indicates IPP#1 is used in this parameter. + Similiarly for bits 1,2,3 and 4 and IPP's 2,3,4 and 5. + */ + short xmit_freq; /* Transmittd frequencies. + Bit 0 set to 1 indicates Frequency#1 is used in this parameter. + Similiarly for bits 1,2,3 and 4 and Frequencies 2,3,4 and 5. + */ + float rcvr_bandwidth;/* [MHz] */ + short pulse_width; /* [m] */ + short polarization; /* 0--Horizontal + 1--Vertical + 2--Circular, Right handed + 3--Elliptical + 4--Circular, Left handed + 5--Dual polarization + */ + short nsamp_in_dwell_time; /* Number of samples in dwell time. */ + short parameter_type; /* 1--8 bit integer + 2--16 bit integer + 3--32 bit integer + 4--floating point (32 bit IEEE) + */ + char threshold_field[8]; + float threshold_value; /* Units depend on the threshold field. */ + float scale_factor; /* Scale factor. */ + float offset_factor; /* meteorological val = (recorded val - offset factor / scale factor */ + int missing_data_flag; /* Deleted or missing data flag. 256for bytes, -999 for all others. */ +} Parameter_desc; + +typedef struct { + char code[4]; /* Code identifier. (4 ASCII "CELV") */ + int len; /* Length of this descriptor. */ + int ncells; /* Number of cells definced in this vector. */ + float *range_cell; /* Range to cell n [m] (0..ncells-1) */ +} Cell_range_vector; + +typedef struct { + char code[4]; /* Code identifier. (4 ASCII "CFAC") */ + int len; /* Length of this descriptor. */ + float azimuth; /* Correction for azimuth [deg]. */ + float elevation; /* Correction for elevation [deg]. */ + float range; /* Correction for range delay [m]. */ + float longitude; /* Correction for radar longitude [deg]. */ + float latitude; /* Correction for radar latitude [deg]. */ + float altitude; /* Correction for radar pressure altitude (msl) [km]. */ + float height; /* Correction for radar altitude above ground (agl) [km]. */ + float speed_east_west; /* Correction for radar platform ground speed E->W [m/s]. */ + float speed_north_south; /* Correction for radar platform ground spedd N->S [m/s]. */ + float vertical_velocity; /* Correction for radar platform vertical velocity [m/s]. */ + float heading; /* Correction for radar platform heading [deg]. */ + float roll; /* Correction for radar platform roll [deg]. */ + float pitch; /* Correction for radar platform pitch [deg]. */ + float drift; /* Correction for radar platform drift [deg]. */ + float rotation_angle; /* Correction for radar rotation angle [deg]. */ + float tilt_angle; /* Correction for radar tilt angle [deg]. */ +} Correction_factor_desc; + +typedef struct { + char code[4]; /* Code identifier. (4 ASCII "SWIB") */ + int len; /* Length of this descriptor. */ + char radar_name[8]; /* Radar name. */ + int sweep_num; /* Sweep number from beginning of volume. */ + int nrays; /* Number of rays recorded in this sweep. */ + float start_angle; /* True start angle [deg]. */ + float stop_angle; /* True stop angle [deg]. */ + float fixed_angle; /* Fixed angle [deg]. */ + int filter_flag; /* Filter flag: + 0--No filtering in use. + 1--ON (Algorithm described in ASCII file at beginning of the file.) + */ +} Sweep_info; + +typedef struct { + char code[4]; /* Code identifier. (4 ASCII "RYIB") */ + int len; /* Length of this descriptor. */ + int sweep_num; + int jday; /* Julian day. (from beginning of year :-) */ + short hour; /* Hour 0-23. */ + short minute; /* Minute 0-59. */ + short second; /* Second 0-59. */ + short msec; /* Millisecond. */ + float azimuth; /* [deg] */ + float elevation; /* [deg] */ + float peak_power;/* [kw] */ + float scan_rate; /* Peak transmitted power [deg/sec]. */ + int status; /* Ray status: + 0--Normal + 1--Transition (antenna repositioning) + 2--Bad + 3--Questionable + */ +} Ray_info; + +typedef struct { /* Especially for moving radars. */ + char code[4]; /* Code identifier. (4 ASCII "ASIB") */ + int len; /* Length of this descriptor. */ + float longitude; /* Radar longitude [deg]. */ + float latitude; /* Radar latitude [deg]. */ + float altitude; /* Radar pressure altitude (msl) [km]. */ + float height; /* Radar above ground altitude (agl) [km]. */ + float ew_speed; /* Platform ground speed (E->W) [m/s]. */ + float ns_speed; /* Platform ground speed (N->S) [m/s]. */ + float v_speed; /* Platform vertical velocity [m/s]. */ + float heading; /* Platform heading [deg]. */ + float roll; /* Platform roll [deg]. */ + float pitch; /* Platform pitch [deg]. */ + float drift; /* Platform drift [deg]. */ + float rotation; /* Platform rotation angle [deg]. */ + float tilt; /* Platform tilt [deg]. */ + float ew_wind_speed; /* Horizontal wind speed at radar (East->West) [m/s]. */ + float ns_wind_speed; /* Horizontal wind speed at radar (North->South) [m/s]. */ + float v_wind_speed; /* Vertical wind speed at radar (East->West) [m/s]. */ + float heading_rate; /* Heading change rate [deg/sec]. */ + float pitch_rate; /* Pitch change rate [deg/sec]. */ +} Platform_info; + +typedef struct { + char code[4]; /* Code identifier. (4 ASCII "RDAT") */ + int len; /* Length of this descriptor. */ + char name[8]; /* Name of parameter. (See name in 'parameter descriptor'). */ + char *data; /* Length as described in Parameter_desc. */ +} Parameter_data; + +/* Higher level objects */ +typedef struct { + Radar_desc *radar_desc; + int nparam; + Parameter_desc **p_desc; /* 0..nparam-1 */ + Cell_range_vector *cell_range_vector; + Correction_factor_desc *correction_factor_desc; +} Sensor_desc; + +typedef struct { + Ray_info *ray_info; + Platform_info *platform_info; + int nparam; + int *data_len; /* 0..nparam-1 + * Length of *parameter_data[i] in words. + * Words can be 2 or 4 bytes. + */ + int *word_size; /* 0..nparam-1 + * Size of each word in *parameter_data[i]. + */ + Parameter_data **parameter_data; /* 0..nparam-1 */ +} Data_ray; + +typedef struct { + Sweep_info *s_info; + int nrays; + Data_ray **data_ray; /* 0..nrays-1 */ +} Sweep_record; + +/* PROTOTYPES */ +Comment_block *dorade_read_comment_block(FILE *in); + +Volume_desc *dorade_read_volume_desc (FILE *in); + +/* Sensor descriptor routines. */ +Radar_desc *dorade_read_radar_desc (FILE *in); +Parameter_desc *dorade_read_parameter_desc (FILE *in); +Cell_range_vector *dorade_read_cell_range_vector (FILE *in); +Correction_factor_desc *dorade_read_correction_factor_desc(FILE *in); +Sensor_desc *dorade_read_sensor (FILE *in); + +Sweep_info *dorade_read_sweep_info(FILE *in); +Sweep_record *dorade_read_sweep(FILE *fp, Sensor_desc **sd); + +/* Data Ray routines. */ + +Ray_info *dorade_read_ray_info (FILE *in); +Platform_info *dorade_read_platform_info (FILE *in); +Parameter_data *dorade_read_parameter_data(FILE *in); +Data_ray *dorade_read_ray (FILE *in); + +/* Memory management routines. */ +void dorade_free_sweep(Sweep_record *s); +void dorade_free_data_ray(Data_ray *r); + +/* Print routines. */ +void dorade_print_sweep_info(Sweep_info *d); +void dorade_print_ray_info(Ray_info *d); +void dorade_print_platform_info(Platform_info *d); +void dorade_print_correction_factor_desc(Correction_factor_desc *d); +void dorade_print_cell_range_vector(Cell_range_vector *d); +void dorade_print_parameter_desc(Parameter_desc *d); +void dorade_print_radar_desc(Radar_desc *d); +void dorade_print_volume_desc(Volume_desc *d); +void dorade_print_comment_block(Comment_block *cb); +void dorade_print_sensor(Sensor_desc *s); + +#endif diff --git a/dorade_print.c b/dorade_print.c new file mode 100644 index 0000000..85e28cf --- /dev/null +++ b/dorade_print.c @@ -0,0 +1,245 @@ +#include +#include "dorade.h" +void dorade_print_sweep_info(Sweep_info *d) +{ + int i; + + printf("Sweep info block\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("len = %d\n", d->len); + printf("d->radar_name = <"); + for(i=0; iradar_name); i++) printf("%c", d->radar_name[i]); + printf(">\n"); + printf("d->sweep_num = %d\n", d->sweep_num); + printf("d->nrays = %d\n", d->nrays); + printf("d->start_angle = %f\n", d->start_angle); + printf("d->stop_angle = %f\n", d->stop_angle); + printf("d->fixed_angle = %f\n", d->fixed_angle); + printf("d->filter_flag = %d\n", d->filter_flag); +} + +void dorade_print_ray_info(Ray_info *d) +{ + int i; + + printf("Ray info block\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("len = %d\n", d->len); + printf("d->sweep_num = %d\n", d->sweep_num); + printf("d->jday = %d\n", d->jday); + printf("d->hour = %d\n", d->hour); + printf("d->minute = %d\n", d->minute); + printf("d->second = %d\n", d->second); + printf("d->msec = %d\n", d->msec); + printf("d->azimuth = %f\n", d->azimuth); + printf("d->elevation = %f\n", d->elevation); + printf("d->peak_power = %f\n", d->peak_power); + printf("d->scan_rate = %f\n", d->scan_rate); + printf("d->status = %d\n", d->status); +} + + +void dorade_print_platform_info(Platform_info *d) +{ + int i; + + printf("Platform info block\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("len = %d\n", d->len); + printf("d->longitude = %f\n", d->longitude); + printf("d->latitude = %f\n", d->latitude); + printf("d->altitude = %f\n", d->altitude); + printf("d->height = %f\n", d->height); + printf("d->ew_speed = %f\n", d->ew_speed); + printf("d->ns_speed = %f\n", d->ns_speed); + printf("d->v_speed = %f\n", d->v_speed); + printf("d->heading = %f\n", d->heading); + printf("d->roll = %f\n", d->roll); + printf("d->pitch = %f\n", d->pitch); + printf("d->drift = %f\n", d->drift); + printf("d->rotation = %f\n", d->rotation); + printf("d->tilt = %f\n", d->tilt); + printf("d->ew_wind_speed = %f\n", d->ew_wind_speed); + printf("d->ns_wind_speed = %f\n", d->ns_wind_speed); + printf("d->v_wind_speed = %f\n", d->v_wind_speed); + printf("d->heading_rate = %f\n", d->heading_rate); + printf("d->pitch_rate = %f\n", d->pitch_rate); +} + +void dorade_print_correction_factor_desc(Correction_factor_desc *d) +{ + int i; + + printf("Correction factor descriptor\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("len = %d\n", d->len); + printf("d->azimuth = %f\n", d->azimuth); + printf("d->elevation = %f\n", d->elevation); + printf("d->range = %f\n", d->range); + printf("d->longitude = %f\n", d->longitude); + printf("d->latitude = %f\n", d->latitude); + printf("d->altitude = %f\n", d->altitude); + printf("d->height = %f\n", d->height); + printf("d->speed_east_west = %f\n", d->speed_east_west); + printf("d->speed_north_south = %f\n", d->speed_north_south); + printf("d->vertical_velocity = %f\n", d->vertical_velocity); + printf("d->heading = %f\n", d->heading); + printf("d->roll = %f\n", d->roll); + printf("d->pitch = %f\n", d->pitch); + printf("d->drift = %f\n", d->drift); + printf("d->rotation_angle = %f\n", d->rotation_angle); + printf("d->tilt_angle = %f\n", d->tilt_angle); +} + +void dorade_print_cell_range_vector(Cell_range_vector *d) +{ + int i; + + printf("Cell range vector\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("len = %d\n", d->len); + printf("d->ncells = %d\n", d->ncells); + for (i=0; incells; i++) + printf("d->range_cell[%d] = %f\n", i, d->range_cell[i]); +} + +void dorade_print_parameter_desc(Parameter_desc *d) +{ + int i; + + printf("Parameter Descriptor\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("len = %d\n", d->len); + printf("d->name = <"); + for(i=0; iname); i++) printf("%c", d->name[i]); + printf(">\n"); + printf("d->description = <"); + for(i=0; idescription); i++) printf("%c", d->description[i]); + printf(">\n"); + printf("d->units = <"); + for(i=0; iunits); i++) printf("%c", d->units[i]); + printf(">\n"); + printf("d->ipp = %d\n", d->ipp); + printf("d->xmit_freq = %d\n", d->xmit_freq); + printf("d->rcvr_bandwidth = %f\n", d->rcvr_bandwidth); + printf("d->pulse_width = %d\n", d->pulse_width); + printf("d->polarization = %d\n", d->polarization); + printf("d->nsamp_in_dwell_time = %d\n", d->nsamp_in_dwell_time); + printf("d->parameter_type = %d\n", d->parameter_type); + printf("d->threshold_field = <"); + for(i=0; ithreshold_field); i++) printf("%c", d->threshold_field[i]); + printf(">\n"); + printf("d->threshold_value = %f\n", d->threshold_value); + printf("d-> scale_factor = %f\n", d-> scale_factor); + printf("d-> offset_factor = %f\n", d-> offset_factor); + printf("d-> missing_data_flag = %d\n", d-> missing_data_flag); +} + +void dorade_print_radar_desc(Radar_desc *d) +{ + int i; + + printf("Radar Descriptor\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("len = %d\n", d->len); + printf("d->radar_name = <"); + for(i=0; iradar_name); i++) printf("%c", d->radar_name[i]); + printf(">\n"); + printf("radar_constant = %f\n", d->radar_constant); + printf("peak_power = %f\n", d-> peak_power); + printf("noise_power = %f\n", d-> noise_power); + printf("rcvr_gain = %f\n", d-> rcvr_gain); + printf("ant_gain = %f\n", d-> ant_gain); + printf("radar_system_gain = %f\n", d-> radar_system_gain); + printf("horizontal_beam_width = %f\n", d-> horizontal_beam_width); + printf("vertical_beam_width = %f\n", d-> vertical_beam_width); + printf("radar_type = %d\n", d->radar_type); + printf("scan_mode = %d\n", d-> scan_mode); + printf("scan_rate = %f\n", d-> scan_rate); + printf("start_angle = %f\n", d-> start_angle); + printf("stop_angle = %f\n", d-> stop_angle); + printf("nparam_desc = %d\n", d->nparam_desc); + printf("ndesc = %d\n", d-> ndesc); + printf("compress_code = %d\n", d-> compress_code); + printf("compress_algo = %d\n", d-> compress_algo); + printf("data_reduction_param1 = %f\n", d-> data_reduction_param1); + printf("data_reduction_param2 = %f\n", d-> data_reduction_param2); + printf("latitude = %f\n", d-> latitude); + printf("longitude = %f\n", d-> longitude); + printf("altitude = %f\n", d-> altitude); + printf("unambiguous_velocity = %f\n", d-> unambiguous_velocity); + printf("unambiguous_range = %f\n", d-> unambiguous_range); + printf("nfreq = %d\n", d-> nfreq); + printf("npulse_periods = %d\n", d->npulse_periods); + for (i=0; i<5; i++) printf("freq[%d] = %f\n", i, d->freq[i]); + for (i=0; i<5; i++) printf("period[%d] = %f\n", i, d->period[i]); +} + +void dorade_print_volume_desc(Volume_desc *d) +{ + int i; + printf("Volume Descriptor\n"); + printf("d->code = <"); + for(i=0; icode); i++) printf("%c", d->code[i]); + printf(">\n"); + printf("version = %d\n", d->version); + printf("volume_number = %d\n", d->volume_number); + printf("max_bytes = %d\n", d->max_bytes); + printf("project_name = <"); + for(i=0; iproject_name); i++) printf("%c", d->project_name[i]); + printf(">\n"); + printf("year = %d\n", d->year); + printf("month = %d\n", d->month); + printf("day = %d\n", d->day); + printf("hour = %d\n", d->hour); + printf("minute = %d\n", d->minute); + printf("second = %d\n", d->second); + printf("flight_num = <"); + for(i=0; iflight_num); i++) printf("%c", d->flight_num[i]); + printf(">\n"); + printf("facility_name = <"); + for(i=0; ifacility_name); i++) printf("%c", d->facility_name[i]); + printf(">\n"); + printf("gen_year = %d\n", d->gen_year); + printf("gen_month = %d\n", d->gen_month); + printf("gen_day = %d\n", d->gen_day); + printf("nsensors = %d\n", d->nsensors); +} + +void dorade_print_comment_block(Comment_block *cb) +{ + int i; + printf("COMMENT BLOCK:\n"); + printf("cb->code = <"); + for(i=0; icode); i++) printf("%c", cb->code[i]); + printf(">\n"); + printf("cb->len = %d\n", cb->len); + printf("cb->comment = <%s>\n", cb->comment); +} + +void dorade_print_sensor(Sensor_desc *s) +{ + int i; + dorade_print_radar_desc(s->radar_desc); + + for (i=0; inparam; i++) { + dorade_print_parameter_desc(s->p_desc[i]); + printf("=====================================================\n"); + } + /* dorade_print_cell_range_vector(s->cell_range_vector); */ + dorade_print_correction_factor_desc(s->correction_factor_desc); +} diff --git a/dorade_to_radar.c b/dorade_to_radar.c new file mode 100644 index 0000000..ff963a8 --- /dev/null +++ b/dorade_to_radar.c @@ -0,0 +1,255 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996-1999 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#define USE_RSL_VARS +#include "rsl.h" +#include "dorade.h" + +extern int radar_verbose_flag; + +/********************************************************************/ +/* */ +/* find_rsl_field_index */ +/* */ +/********************************************************************/ +int find_rsl_field_index(char *dorade_field_name) +{ + /* + * Dorade: VE, DM, SW, DZ, ZDR, PHI, RHO, LDR, DX, CH, AH, CV, AV + * RSL: VR, DM, SW, DZ, ZD, PH, RH, LR, *DX, *CH, *AH, *CV, *AV. + */ + if (strncasecmp(dorade_field_name, "ve", 2) == 0) return VR_INDEX; + if (strncasecmp(dorade_field_name, "dm", 2) == 0) return DM_INDEX; + if (strncasecmp(dorade_field_name, "sw", 2) == 0) return SW_INDEX; + if (strncasecmp(dorade_field_name, "dz", 2) == 0) return DZ_INDEX; + if (strncasecmp(dorade_field_name, "zdr", 3) == 0) return ZD_INDEX; + if (strncasecmp(dorade_field_name, "phi", 3) == 0) return PH_INDEX; + if (strncasecmp(dorade_field_name, "rho", 3) == 0) return RH_INDEX; + if (strncasecmp(dorade_field_name, "ldr", 3) == 0) return LR_INDEX; + if (strncasecmp(dorade_field_name, "dx", 2) == 0) return DX_INDEX; + if (strncasecmp(dorade_field_name, "ch", 2) == 0) return CH_INDEX; + if (strncasecmp(dorade_field_name, "ah", 2) == 0) return AH_INDEX; + if (strncasecmp(dorade_field_name, "cv", 2) == 0) return CV_INDEX; + if (strncasecmp(dorade_field_name, "av", 2) == 0) return AV_INDEX; + + fprintf(stderr, "Unknown DORADE type <%s>\n", dorade_field_name); + return -1; +} + +/* Secretly defined in uf_to_radar.c */ +Volume *copy_sweeps_into_volume(Volume *new_volume, Volume *old_volume); + +Radar *RSL_dorade_to_radar(char *infile) +{ + Radar *radar; + Volume *new_volume; + Sweep *sweep; + Ray *ray; + int iv, iray, iparam; + + FILE *fp; + Volume_desc *vd; + Sensor_desc **sd; + Sweep_record *sr; + Radar_desc *rd; + Data_ray *dray; + Parameter_data *pd; + + int nsweep; + int i; + char buf[1024]; + + int degree, minute; + float second; + + radar = NULL; + if (infile == NULL) { + int save_fd; + save_fd = dup(0); + fp = fdopen(save_fd, "r"); + } else + if((fp=fopen(infile, "r"))==(FILE *)NULL) { + perror(infile); + return radar; + } + + fp = uncompress_pipe(fp); /* Transparently, use gunzip. */ + + /**********************************************************************/ + + vd = dorade_read_volume_desc(fp); /* R E A D */ + if (radar_verbose_flag) dorade_print_volume_desc(vd); /* P R I N T */ + + /* R E A D */ + sd = (Sensor_desc **) calloc(vd->nsensors, sizeof(Sensor_desc *)); + for (i=0; insensors; i++) { + sd[i] = dorade_read_sensor(fp); + } + + /* P R I N T */ + if (radar_verbose_flag) { + for (i=0; insensors; i++) { + fprintf(stderr, "============ S E N S O R # %d =====================\n", i); + dorade_print_sensor(sd[i]); + } + } + /* R E A D sweeps. */ + if (vd->nsensors > 1) { + fprintf(stderr, "RSL_dorade_to_radar: Unable to process for more than 1 sensor.\n"); + fprintf(stderr, "RSL_dorade_to_radar: Number of sensors is %d\n", vd->nsensors); + return NULL; + } + + /* Use sensor 0 for vitals. */ + rd = sd[0]->radar_desc; + + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + radar->h.month = vd->month; + radar->h.day = vd->day; + radar->h.year = vd->year; + radar->h.hour = vd->hour; + radar->h.minute = vd->minute; + radar->h.sec = vd->second; + sprintf(radar->h.radar_type, "dorade"); + radar->h.number = 0; + strncpy(radar->h.name, vd->flight_num, sizeof(radar->h.name)); + strncpy(radar->h.radar_name, rd->radar_name, sizeof(radar->h.radar_name)); + strncpy(radar->h.project, vd->project_name, sizeof(radar->h.project)); + sprintf(radar->h.city, "Unknown"); + strncpy(radar->h.state, "UKN", 3); + sprintf(radar->h.country, "Unknown"); + /* Convert lat to d:m:s */ + degree = (int)rd->latitude; + minute = (int)((rd->latitude - degree) * 60); + second = (rd->latitude - degree - minute/60.0) * 3600.0; + radar->h.latd = degree; + radar->h.latm = minute; + radar->h.lats = second; + /* Convert lat to d:m:s */ + degree = (int)rd->longitude; + minute = (int)((rd->longitude - degree) * 60); + second = (rd->longitude - degree - minute/60.0) * 3600.0; + radar->h.lond = degree; + radar->h.lonm = minute; + radar->h.lons = second; + radar->h.height = rd->altitude * 1000.0; + radar->h.spulse = 0; /* FIXME */ + radar->h.lpulse = 0; /* FIXME */ + + /* Begin volume code. */ + /* We don't know how many sweeps per volume exist, until we read + * the file. So allocate a large number of pointers, hope we don't + * exceed it, and adjust the pointer array at the end. This is + * efficient because we'll be manipulating pointers to the sweeps and + * not the sweeps themselves. + */ + + if (radar_verbose_flag) + fprintf(stderr, "Number of parameters: %d\n", rd->nparam_desc); + + /* All the parameters are together, however, their order within + * the ray is not guarenteed. For instance, VE could appear after + * DM. For this we'll keep a list of parameter names and perform + * a (linear) search. The result will be an index into the RSL + * volume array (radar->v[i]). It is likely that the order will + * consistant within a file, therefore, we'll keep track of the index of + * our previous parameter type and begin the search from there; the next + * index should be a match. + * + * The dorade parameter names and the rsl mapping is: + * + * Dorade: VE, DM, SW, DZ, ZDR, PHI, RHO, LDR, DX, CH, AH, CV, AV + * RSL: VR, DM, SW, DZ, ZD, PH, RH, LR, *DX, *CH, *AH, *CV, *AV. + * + * * means this is a new RSL name. + */ + +#define DORADE_MAX_SWEEP 20 + nsweep = 0; + while((sr = dorade_read_sweep(fp, sd))) { + for(iray = 0; iray < sr->nrays; iray++) { + dray = sr->data_ray[iray]; + + /* Now, loop through the parameters and fill the rsl structures. */ + for (iparam = 0; iparam < dray->nparam; iparam++) { + pd = dray->parameter_data[iparam]; + iv = find_rsl_field_index(pd->name); + if (radar->v[iv] == NULL) { + radar->v[iv] = RSL_new_volume(DORADE_MAX_SWEEP); /* Expandable */ + } else if (nsweep >= radar->v[iv]->h.nsweeps) { + /* Must expand the number of sweeps. */ + /* Expand by another DORADE_MAX_SWEEP. */ + if (radar_verbose_flag) { + fprintf(stderr, "nsweeps (%d) exceeds radar->v[%d]->h.nsweeps (%d).\n", nsweep, iv, radar->v[iv]->h.nsweeps); + fprintf(stderr, "Increading it to %d sweeps\n", radar->v[iv]->h.nsweeps+DORADE_MAX_SWEEP); + } + new_volume = RSL_new_volume(radar->v[iv]->h.nsweeps+DORADE_MAX_SWEEP); + /* Look in uf_to_radar.c for 'copy_sweeps_into_volume' */ + new_volume = copy_sweeps_into_volume(new_volume, radar->v[iv]); + radar->v[iv] = new_volume; + } + + /* Allocate the ray and load the parameter data. */ + if ((sweep = radar->v[iv]->sweep[nsweep]) == NULL) { + sweep = radar->v[iv]->sweep[nsweep] = RSL_new_sweep(sr->s_info->nrays); + sweep->h.sweep_num = sr->s_info->sweep_num; + sweep->h.elev = sr->s_info->fixed_angle; + sweep->h.beam_width = rd->horizontal_beam_width; + sweep->h.vert_half_bw = radar->v[iv]->sweep[nsweep]->h.beam_width / 2.0; + sweep->h.horz_half_bw = rd->horizontal_beam_width / 2.0; + sweep->h.f = RSL_f_list[iv]; + sweep->h.invf = RSL_invf_list[iv]; + } + + + if ((ray = sweep->ray[iray]) == NULL) { + if (radar_verbose_flag) + fprintf(stderr, "Allocating %d bins for ray %d\n", dray->data_len[iparam], iray); + ray = sweep->ray[iray] = RSL_new_ray(dray->data_len[iparam]); + } + + /* Copy the ray data into the RSL ray. */ + + /* .... fill here .... */ + } + } + nsweep++; + if (radar_verbose_flag) fprintf(stderr, "______NEW SWEEP__<%d>____\n", nsweep); + /* Save for loading into volume structure. */ + dorade_free_sweep(sr); + } + + /* The following avoids a broken pipe message, since a VOLD at the end + * is not read yet. + */ + while(fread(buf, sizeof(buf), 1, fp)) continue; /* Read til EOF */ + + rsl_pclose(fp); + + return radar; +} + diff --git a/edge_to_radar.c b/edge_to_radar.c new file mode 100644 index 0000000..bd75b9b --- /dev/null +++ b/edge_to_radar.c @@ -0,0 +1,496 @@ +#include "rsl.h" + +#ifdef HAVE_LIBETOR + +/*----------------------------------------------------------------------** +** +** EDGE_to_Radar.c +** +**----------------------------------------------------------------------** +** +** DESCRIPTION +** +** Converts an EDGE Volume structure to an RSL Radar structure +** +** USAGE: +** +** Radar *RSL_EDGE_to_radar(EDGE_filename); -* Usage Section with comments *- +** char *EDGE_filename; -* name of EDGE volume file *- +** +** PROCESSING: +** +** This program creates an RSL radar data structure copies an Edge +** volume data structure into it and returns the pointer to the Radar +** structure. +** +** COPYRIGHT NOTICE +** +** Copyright (c) 1997 by Enterprise Electronics Corporation +** All Rights Reserved +** +** This program is copyright by Enterprise Electronics Corpora- +** tion, Enterprise, Alabama, USA 36330 (334) 347-3478. It is +** licensed for use on a specific CPU and is not to be +** transferred or otherwise divulged. Copies or modifications of +** this program must carry this copyright notice. +** +** +** +** HEADER INFOMATION +** +** Software Suite - EDGE +** Package - +** Reference number - SP1/PGM/ +** Revision number - $Revision: 1.3 $ +** Release State - $State: Exp $ +** Author, designer - Don Burrows +** Modification Date - $Date: 1999/11/23 00:36:00 $ +** Modified by - $Author: merritt $ +** $Source: /nfs/trmm/src/CVS/rsl/edge_to_radar.c,v $ +** +** MODIFICATION RECORD +** +** $Log: edge_to_radar.c,v $ +** Revision 1.3 1999/11/23 00:36:00 merritt +** auto configure scripts added +** +** Revision 1.2 1999/04/02 16:14:45 merritt +** ready for v1.23 +** +** Revision 1.1 1999/03/31 22:35:16 merritt +** round 1 for edge incorporation. Still seg faults for any_to_gif +** +** +**----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Feature Test Switches */ +/*----------------------------------------------------------------------*/ +#define _POSIX_SOURCE 1 + +/*----------------------------------------------------------------------*/ +/* System Headers { full list in stdinc.h } */ +/*----------------------------------------------------------------------*/ +#include /* stdio library */ +#include /* Some popular symbols */ +#include /* Some standard funct. */ +#include /* POSIX symbols definitions */ +#include +#include +#include + +/*----------------------------------------------------------------------*/ +/* Application Headers */ +/*----------------------------------------------------------------------*/ +#include "vol.h" +#include "antenna.h" + +/*----------------------------------------------------------------------*/ +/* Macros */ +/*----------------------------------------------------------------------*/ +#define NEEDED_VOLS 8 + +/*----------------------------------------------------------------------*/ +/* External (Import) Variables */ +/*----------------------------------------------------------------------*/ +extern int radar_verbose_flag; + +/*----------------------------------------------------------------------*/ +/* External Functions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Structures and Unions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Global (Export) Variables */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local (Static) Variables */ +/*----------------------------------------------------------------------*/ +static struct vol_struct *EDGE_vol=NULL; +static int num_sweeps,num_rays,num_bins,gate_width; +static float azimuth,elevation; +static float prf,wavelength,nyq_vel,meansr; +static struct tm *sweeptime; +static float lat,lon; +static int bytes_bin; +static float beam_width; +static float (*f)(Range x); +static Range (*invf)(float x); + +/*----------------------------------------------------------------------*/ +/* Signal Catching Functions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Function */ +/*----------------------------------------------------------------------*/ + +Ray *Fill_Ray_Header(int num_bins,int isweep,int iray) +{ + Ray *RSL_ray; + + RSL_ray = RSL_new_ray(num_bins); + RSL_ray->h.sec = sweeptime->tm_sec; + RSL_ray->h.minute = sweeptime->tm_min; + RSL_ray->h.hour = sweeptime->tm_hour; + RSL_ray->h.day = sweeptime->tm_mday; + RSL_ray->h.month = sweeptime->tm_mon+1; + RSL_ray->h.year = sweeptime->tm_year + 1900; + RSL_ray->h.unam_rng = 149851.274/prf; + RSL_ray->h.azimuth = azimuth; + RSL_ray->h.ray_num = iray; + RSL_ray->h.elev = elevation; + RSL_ray->h.elev_num = isweep; + RSL_ray->h.range_bin1 = gate_width; + RSL_ray->h.gate_size = gate_width; + RSL_ray->h.vel_res = nyq_vel/128.0; + RSL_ray->h.sweep_rate = meansr; + RSL_ray->h.prf = prf; + RSL_ray->h.azim_rate = + (float)EDGE_vol->sweep[isweep].rad.antenna_speed*0.55; + RSL_ray->h.lat = lat; + RSL_ray->h.lon = lon; + RSL_ray->h.alt = EDGE_vol->sweep[isweep].rad.antenna_height; + RSL_ray->h.rvc = 0; + RSL_ray->h.pulse_count = EDGE_vol->sweep[isweep].rad.pulses; + RSL_ray->h.pulse_count = EDGE_vol->sweep[isweep].rad.pulse_width*1.2+0.8; + RSL_ray->h.beam_width = beam_width; + RSL_ray->h.frequency = 299.702547/wavelength; + RSL_ray->h.wavelength = wavelength; + RSL_ray->h.nyq_vel = nyq_vel; + RSL_ray->h.f = f; + RSL_ray->h.invf = invf; + RSL_ray->h.nbins = num_bins; + return RSL_ray; +} + +/*----------------------------------------------------------------------*/ +/* Main Function */ +/*----------------------------------------------------------------------*/ + +Radar *RSL_EDGE_to_radar(char *EDGE_filename) +{ + Radar *RSL_rad; + int i,j,k; + Sweep *sweep_u,*sweep_z,*sweep_v,*sweep_w,*sweep_d=NULL; + unsigned char *EDGE_ray; + unsigned short *sray; + struct tm *voltime; + float start_azimuth,end_azimuth; + char state[2]; + + float uz,cz,rv,sw,zdr=0; + + if (radar_verbose_flag) printf("EDGE_to_radar(%s)\n",EDGE_filename); + +/** Load the EDGE volume structure **/ + if (load_data((char **)&EDGE_vol,EDGE_filename,VOL_FILE) == -1) + { + EDGE_vol = NULL; + fprintf(stderr,"EDGE_to_radar: Could not load EDGE Volume File: %s\n",EDGE_filename); + return NULL; + } +/** Allocating memory for radar structure **/ + RSL_rad = RSL_new_radar(MAX_RADAR_VOLUMES); + if (RSL_rad == NULL) + { + fprintf(stderr, "EDGE_to_radar: radar is NULL\n"); + free(EDGE_vol); + return NULL; + } + bytes_bin = BYTES_BIN(EDGE_vol); + prf = (float)EDGE_vol->sweep[0].rad.prf1; + wavelength = EDGE_vol->sweep[0].rad.wavelength; + if (radar_verbose_flag) printf("bytes_bin: %d prf %5.0f wavelength %4.1f\n", + bytes_bin,prf,wavelength*100.0); + nyq_vel = prf*wavelength/4.0; + num_sweeps = EDGE_vol->num_sweeps; + if (radar_verbose_flag) printf("nyq_vel %5.1f num_sweeps %d\n",nyq_vel,num_sweeps); + + meansr = 0.0; + for(i=0;isweep[i+1].date-EDGE_vol->sweep[i].date); + meansr /= (float)num_sweeps-1.0; + meansr = 60.0/meansr; + + voltime = gmtime(&EDGE_vol->date); + if (num_sweeps > MAX_SWEEPS) num_sweeps = MAX_SWEEPS; + sprintf(state,"NA"); + +/* Now fill the Radar header */ + RSL_rad->h.sec = voltime->tm_sec; + RSL_rad->h.minute = voltime->tm_min; + RSL_rad->h.hour = voltime->tm_hour; + RSL_rad->h.day = voltime->tm_mday; + RSL_rad->h.month = voltime->tm_mon + 1; + RSL_rad->h.year = voltime->tm_year + 1900; + strcpy(RSL_rad->h.radar_type,"EDGE"); + RSL_rad->h.nvolumes = NEEDED_VOLS; + RSL_rad->h.number = 553;/* What is this number supposed to be??? */ + memmove(RSL_rad->h.name,EDGE_vol->sweep[0].rad.site_name, + sizeof(RSL_rad->h.name)); + memmove(RSL_rad->h.radar_name,EDGE_vol->sweep[0].rad.radar_type, + sizeof(RSL_rad->h.radar_name)); + memmove(RSL_rad->h.city,EDGE_vol->sweep[0].rad.site_name, + sizeof(RSL_rad->h.city)); + memmove(RSL_rad->h.state,state,sizeof(RSL_rad->h.state)); + RSL_rad->h.latd = EDGE_vol->sweep[0].rad.lat_deg; + RSL_rad->h.latm = EDGE_vol->sweep[0].rad.lat_min; + RSL_rad->h.lats = EDGE_vol->sweep[0].rad.lat_sec; + RSL_rad->h.lond = EDGE_vol->sweep[0].rad.long_deg; + RSL_rad->h.lonm = EDGE_vol->sweep[0].rad.long_min; + RSL_rad->h.lons = EDGE_vol->sweep[0].rad.long_sec; + if (RSL_rad->h.latd < 0) + { + if(RSL_rad->h.latm > 0) RSL_rad->h.latm *= -1; + if(RSL_rad->h.lats > 0) RSL_rad->h.lats *= -1; + } + if (RSL_rad->h.lond < 0) + { + if(RSL_rad->h.lonm > 0) RSL_rad->h.lonm *= -1; + if(RSL_rad->h.lons > 0) RSL_rad->h.lons *= -1; + } + lat = (float)RSL_rad->h.latd+(float)RSL_rad->h.latm/60.0+ + (float)RSL_rad->h.lats/3600.0; + lon = (float)RSL_rad->h.lond+(float)RSL_rad->h.lonm/60.0+ + (float)RSL_rad->h.lons/3600.0; + RSL_rad->h.height = EDGE_vol->sweep[0].rad.antenna_height; + RSL_rad->h.spulse = EDGE_vol->sweep[0].rad.pulse_width*1200 + 800; + RSL_rad->h.lpulse = EDGE_vol->sweep[0].rad.pulse_width*1200 + 800; + if (radar_verbose_flag) printf("Radar Header Filled\n"); +/* + Done with Radar header + Now create the necessary volumes and fill the + volume headers +*/ + + RSL_rad->v[DZ_INDEX] = RSL_new_volume(num_sweeps); + if (radar_verbose_flag) printf("DZ volume created index is %d\n",DZ_INDEX); + if ((RSL_rad->v[DZ_INDEX]->h.type_str = malloc(25)) != NULL) + { + RSL_rad->v[DZ_INDEX]->h.type_str[24] = '\0'; + strcpy(RSL_rad->v[DZ_INDEX]->h.type_str,"Uncorrected Reflectivity"); + } + if (radar_verbose_flag) printf("Uncorrected Reflectivity\n"); + RSL_rad->v[DZ_INDEX]->h.nsweeps = num_sweeps; + if (radar_verbose_flag) printf("num_sweeps %d assigned\n",num_sweeps); + RSL_rad->v[DZ_INDEX]->h.f = DZ_F; + if (radar_verbose_flag) printf("DZ_F assigned\n"); + RSL_rad->v[DZ_INDEX]->h.invf = DZ_INVF; + if (radar_verbose_flag) printf("DZ volume created and header Filled\n"); + + RSL_rad->v[CZ_INDEX] = RSL_new_volume(num_sweeps); + if ((RSL_rad->v[CZ_INDEX]->h.type_str = malloc(23)) != NULL) + { + RSL_rad->v[CZ_INDEX]->h.type_str[22] = '\0'; + strcpy(RSL_rad->v[CZ_INDEX]->h.type_str,"Corrected Reflectivity"); + } + RSL_rad->v[CZ_INDEX]->h.nsweeps = num_sweeps; + RSL_rad->v[CZ_INDEX]->h.f = CZ_F; + RSL_rad->v[CZ_INDEX]->h.invf = CZ_INVF; + if (radar_verbose_flag) printf("CZ volume created and header Filled\n"); + + RSL_rad->v[VR_INDEX] = RSL_new_volume(num_sweeps); + if ((RSL_rad->v[VR_INDEX]->h.type_str = malloc(16)) != NULL) + { + RSL_rad->v[VR_INDEX]->h.type_str[15] = '\0'; + strcpy(RSL_rad->v[VR_INDEX]->h.type_str,"Radial Velocity"); + } + RSL_rad->v[VR_INDEX]->h.nsweeps = num_sweeps; + RSL_rad->v[VR_INDEX]->h.f = VR_F; + RSL_rad->v[VR_INDEX]->h.invf = VR_INVF; + if (radar_verbose_flag) printf("VR volume created and header Filled\n"); + + RSL_rad->v[SW_INDEX] = RSL_new_volume(num_sweeps); + if ((RSL_rad->v[SW_INDEX]->h.type_str = malloc(15)) != NULL) + { + RSL_rad->v[SW_INDEX]->h.type_str[14] = '\0'; + strcpy(RSL_rad->v[SW_INDEX]->h.type_str,"Spectrum Width"); + } + RSL_rad->v[SW_INDEX]->h.nsweeps = num_sweeps; + RSL_rad->v[SW_INDEX]->h.f = SW_F; + RSL_rad->v[SW_INDEX]->h.invf = SW_INVF; + if (radar_verbose_flag) printf("SW volume created and header Filled\n"); + + if (bytes_bin == 5) + { + RSL_rad->v[ZD_INDEX] = RSL_new_volume(num_sweeps); + strcpy(RSL_rad->v[ZD_INDEX]->h.type_str,"Differential Reflectivity"); + if ((RSL_rad->v[ZD_INDEX]->h.type_str = malloc(26)) != NULL) + { + RSL_rad->v[ZD_INDEX]->h.type_str[25] = '\0'; + strcpy(RSL_rad->v[ZD_INDEX]->h.type_str,"Differential Reflectivity"); + } + RSL_rad->v[ZD_INDEX]->h.nsweeps = num_sweeps; + RSL_rad->v[ZD_INDEX]->h.f = ZD_F; + RSL_rad->v[ZD_INDEX]->h.invf = ZD_INVF; + if (radar_verbose_flag) printf("ZD volume created and header Filled\n"); + } +/* + Volume Headers complete now fill the sweeps +*/ + + for (i=0;isweep[i].num_rays; + sray = (unsigned short *)RAY_PTR(EDGE_vol,i,10); + elevation = ((float)(BINEL2IANG100(sray[1])) + + (float)(BINEL2IANG100(sray[3])))/200.0; + sweeptime = gmtime(&EDGE_vol->sweep[i].date); +/* + In newer versions of edge the beam width will be EDGE_vol->sweep[i].rad.beam_width +*/ + beam_width = 1.0; + + RSL_rad->v[DZ_INDEX]->sweep[i] = RSL_new_sweep(num_rays); + sweep_u = RSL_rad->v[DZ_INDEX]->sweep[i]; + sweep_u->h.sweep_num = i; + sweep_u->h.elev = elevation; + sweep_u->h.beam_width = beam_width; + sweep_u->h.vert_half_bw = beam_width/2.0; + sweep_u->h.horz_half_bw = beam_width/2.0; + sweep_u->h.nrays = num_rays; + sweep_u->h.f = DZ_F; + sweep_u->h.invf = DZ_INVF; + + RSL_rad->v[CZ_INDEX]->sweep[i] = RSL_new_sweep(num_rays); + sweep_z = RSL_rad->v[CZ_INDEX]->sweep[i]; + sweep_z->h.sweep_num = i; + sweep_z->h.elev = elevation; + sweep_z->h.beam_width = beam_width; + sweep_z->h.vert_half_bw = beam_width/2.0; + sweep_z->h.horz_half_bw = beam_width/2.0; + sweep_z->h.nrays = num_rays; + sweep_z->h.f = CZ_F; + sweep_z->h.invf = CZ_INVF; + + RSL_rad->v[VR_INDEX]->sweep[i] = RSL_new_sweep(num_rays); + sweep_v = RSL_rad->v[VR_INDEX]->sweep[i]; + sweep_v->h.sweep_num = i; + sweep_v->h.elev = elevation; + sweep_v->h.beam_width = beam_width; + sweep_v->h.vert_half_bw = beam_width/2.0; + sweep_v->h.horz_half_bw = beam_width/2.0; + sweep_v->h.nrays = num_rays; + sweep_v->h.f = VR_F; + sweep_v->h.invf = VR_INVF; + + RSL_rad->v[SW_INDEX]->sweep[i] = RSL_new_sweep(num_rays); + sweep_w = RSL_rad->v[SW_INDEX]->sweep[i]; + sweep_w->h.sweep_num = i; + sweep_w->h.elev = elevation; + sweep_w->h.beam_width = beam_width; + sweep_w->h.vert_half_bw = beam_width/2.0; + sweep_w->h.horz_half_bw = beam_width/2.0; + sweep_w->h.nrays = num_rays; + sweep_w->h.f = SW_F; + sweep_w->h.invf = SW_INVF; + + if (bytes_bin == 5) + { + RSL_rad->v[ZD_INDEX]->sweep[i] = RSL_new_sweep(num_rays); + sweep_d = RSL_rad->v[ZD_INDEX]->sweep[i]; + sweep_d->h.sweep_num = i; + sweep_d->h.elev = elevation; + sweep_d->h.beam_width = beam_width; + sweep_d->h.vert_half_bw = beam_width/2.0; + sweep_d->h.horz_half_bw = beam_width/2.0; + sweep_d->h.nrays = num_rays; + sweep_d->h.f = ZD_F; + sweep_d->h.invf = ZD_INVF; + } +/* + Sweeps are complete now to do the rays +*/ + num_bins = (int)EDGE_vol->sweep[i].rad.gates; + for (j=0;jsweep[i].rad.gw1; + start_azimuth =BIN2IANG(sray[0]); + end_azimuth =BIN2IANG(sray[2]); + azimuth = (start_azimuth + end_azimuth)/2.0; + if (fabs(end_azimuth - start_azimuth) > 180.0) azimuth = azimuth - 180.0; + if (azimuth < 0.0) azimuth = azimuth + 360.0; + + f = DZ_F; + invf = DZ_INVF; + sweep_u->ray[j] = Fill_Ray_Header(num_bins,i,j); + f = CZ_F; + invf = CZ_INVF; + sweep_z->ray[j] = Fill_Ray_Header(num_bins,i,j); + f = VR_F; + invf = VR_INVF; + sweep_v->ray[j] = Fill_Ray_Header(num_bins,i,j); + f = SW_F; + invf = SW_INVF; + sweep_w->ray[j] = Fill_Ray_Header(num_bins,i,j); + if (bytes_bin == 5) + { + f = ZD_F; + invf = ZD_INVF; + sweep_d->ray[j] = Fill_Ray_Header(num_bins,i,j); + } + EDGE_ray = RAY_PTR(EDGE_vol,i,j); + +/* + Now fill the rest of the ray +*/ + for (k=0;k 255.0) uz = BADVAL; + else uz = uz/2.0-32.0; + cz = (float)EDGE_ray[k*bytes_bin]; + if (cz == 0.0) cz = NOECHO; + else if (cz > 255.0) cz = BADVAL; + else cz = cz/2.0-32.0; + rv = (float)EDGE_ray[k*bytes_bin+1]; + if (rv == 0.0) rv = NOECHO; + else if (rv > 255.0) rv = BADVAL; + else rv = (rv-128.0)/128.0*nyq_vel; + sw = (float)EDGE_ray[k*bytes_bin+3]; + if (sw == 0.0) sw = NOECHO; + else if (sw > 255.0) sw = BADVAL; + else sw = sw/128.0*nyq_vel; + if (bytes_bin == 5) + { + zdr = (float)EDGE_ray[k*bytes_bin+4]; + if (zdr == 0.0) zdr = NOECHO; + else if (zdr > 255.0) zdr = BADVAL; + else zdr = (zdr-128.0)/16.0; + } + sweep_u->ray[j]->range[k] = DZ_INVF(uz); + sweep_z->ray[j]->range[k] = CZ_INVF(cz); + sweep_v->ray[j]->range[k] = VR_INVF(rv); + sweep_w->ray[j]->range[k] = SW_INVF(sw); + if (bytes_bin == 5) sweep_d->ray[j]->range[k] = DR_INVF(zdr); + } + } + } + if (radar_verbose_flag) + printf("EDGE to RSL conversion complete\n"); + free(EDGE_vol); + RSL_rad = RSL_prune_radar(RSL_rad); + return RSL_rad; +} +/*-END OF MODULE--------------------------------------------------------*/ +#else +Radar *RSL_EDGE_to_radar(char *infile) +{ + fprintf(stderr, +"The library libetor.a (or .so) was not found when RSL was installed,\n\ +therefore, EDGE capability was disabled. If you now have libetor, then\n\ +you must reinstall RSL to enable EDGE.\n" +); + return NULL; +} +#endif diff --git a/endian.c b/endian.c new file mode 100644 index 0000000..9120e80 --- /dev/null +++ b/endian.c @@ -0,0 +1,73 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +int big_endian(void); +int little_endian(void); +void swap_4_bytes(void *word); +void swap_2_bytes(void *word); + +int big_endian(void) +{ + union { + unsigned char byte[4]; + int val; + } word; + + word.val = 0; + word.byte[3] = 0x1; + return word.val == 1; +} + +int little_endian(void) +{ + union { + unsigned char byte[4]; + int val; + } word; + word.val = 0; + word.byte[3] = 0x1; + return word.val != 1; +} + + +void swap_4_bytes(void *word) +{ + unsigned char *byte; + unsigned char temp; + byte = word; + temp = byte[0]; + byte[0] = byte[3]; + byte[3] = temp; + temp = byte[1]; + byte[1] = byte[2]; + byte[2] = temp; +} + +void swap_2_bytes(void *word) +{ + unsigned char *byte; + unsigned char temp; + byte = word; + temp = byte[0]; + byte[0] = byte[1]; + byte[1] = temp; +} diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..3fdf629 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,24 @@ +## Use automake to generate Makefile.in from this file ## + +AUTOMAKE_OPTIONS = foreign + +INCLUDES = -I$(prefix)/include +LOCAL_LIB = ../.libs/librsl.a +LDADD = @LIBS@ $(LOCAL_LIB) +bin_PROGRAMS = any_to_gif any_to_uf +any_to_gif_LDFLAGS = -static +any_to_uf_LDFLAGS = -static +# Additional program to build but not install +noinst_PROGRAMS = any_to_ppm any_to_ufgz bscan \ + cappi_image dorade_main killer_sweep \ + kwaj_subtract_one_day lassen_to_gif print_hash_table \ + print_header_info qlook sector test_get_win \ + wsr88d_to_gif wsr_hist_uf_test + + +# Only this one has more than one source. All the others use the +# default *.c format. + +qlook_SOURCES = qlook.c qlook_usage.c adjust_gate_size.c + +EXTRA_DIST = run_tests diff --git a/examples/adjust_gate_size.c b/examples/adjust_gate_size.c new file mode 100644 index 0000000..7c7ff4c --- /dev/null +++ b/examples/adjust_gate_size.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include "rsl.h" + +void adjust_gate_size(Radar *radar, float gate_size_adjustment) +{ + + int i,j,k,nvolumes; + Volume *volume; + Sweep *sweep; + Ray *ray; + + if(gate_size_adjustment != 1.0) { + nvolumes = radar->h.nvolumes; + for(i=0; iv[i] != NULL) { + volume=radar->v[i]; + for(j=0; jh.nsweeps; j++) { + if(volume->sweep[j] != NULL) { + sweep = volume->sweep[j]; + for(k=0; kh.nrays; k++) { + if(sweep->ray[k] != NULL) { + ray = sweep->ray[k]; + ray->h.gate_size = ray->h.gate_size*gate_size_adjustment; + } + } + } + } + } + } + } + +/* + If Gate Size Adjustment is not unity, then we must change the + following: + old_gs = radar->v[i]->sweep[sweepIndex]->ray[rayIndex=]->h.gate_size + radar->v[i]->sweep[sweepIndex]->ray[rayIndex=]->h.gate_size = + old_gs*gate_size_adjustment + Here are some comments from Sandra Yuter on the necessity of this fix. + > I dug into the revelant code and it looks like we can do a relatively + > simple workaround for the SIGMET raw product file range bin size + > errors for the RHB data pulses widths of 0.5 usec and 2.0 usec as follows. + > + > Since we are all converting from sigmet to UF I suggest we resize + > the range bin size values in the ray headers in the qlook step + > where the sigmet to UF conversion occurs. + > + > The resize requires only 1 additional line of code (I have included + > a few others for context) in qlook.c + > + > rangeToFirstGate = 0.001 * + > radar->v[i]->sweep[sweepIndex]->ray[rayIndex]->h.range_bin1; + > gateSize = 0.001 * + > radar->v[i]->sweep[sweepIndex]->ray[rayIndex]->h.gate_size; + > radar->v[i]->sweep[sweepIndex]->ray[rayIndex]->h.gate_size= + > gateSize*0.6*1000; + > + > I have used 0.6 adjustment factor since that is 75/125 which corresponds + > to the error in my 0.5 usec data, for the SUR scans, this adjustment + > factor is 133.33/125 or 1.067. + + The following is from Joe Holmes from SIGMET + + > + > I think you have experienced a problem with the RVP7 range resolution + > configuration. Both in IRIS and in the RVP7 you manually type in + > the range resolution. The RVP7 allows a separate resolution for + > each pulsewidth, while IRIS only allows 1 value. There is no feedback + > if these values are not typed in the same. Based on setup information + > we have here from the RH Brown from Oct 23, 1998, you had the following + > configuration: + > + > RVP7: + > 0 0.50 usec 75.0m + > 1 0.80 usec 125.0m + > 2 1.39 usec 125.0m + > 3 2.00 usec 133.3m + > + > IRIS: 125.0 meters + > + > I think the error at PW#0 was corrected a while back, but + > the error in PW#3 was never corrected. Next time someone is + > at the ship, they should check this, fix the long pulse, and remake + > the bandpass filter for the long pulse. + > + > In the short term, you can correct the error by taking all your + > long pulse data and changing the header to correctly document the + > range resolution. We have a program to do this, it is called "change_raw". + > The source is on any IRIS system, which was installed with the + > source, headers, and objects turned on. It is in the + > ${IRIS_ROOT}utils/examples directory. We can supply you with + > a compiled version of this program, if you want. Available platforms + > are Linux, HP-UX, and IRIX. + +*/ + + return; +} diff --git a/examples/any_to_gif.c b/examples/any_to_gif.c new file mode 100644 index 0000000..f598033 --- /dev/null +++ b/examples/any_to_gif.c @@ -0,0 +1,167 @@ +/* + * Ingest NEXRAD (wsr88d) data and output images representing + * all field types found. + * + * This example is the most minimum of coding that you need to do + * to achieve good results from using the RSL code. + * + * This is short and sweet to demonstrate the simplicity of use for + * the RSL. + * + */ + +#define USE_RSL_VARS +#include "rsl.h" + +/* Example use for getopt; argument processing */ +/* ------ + * Remember that to pass back strings you must pass the + * address of the pointer to the string; argument is char **. + * (Note: arrays of characters; the name is char **) + * Ex. + * char *file + * process_args(... &file); + * DECLARE as: process_args(... char **file) + * *file = strdup(argv[optind]); + * + * char infile[80]; + * process_args(... infile ...); + * DECLARE as: process_args(... char *infile ...) + * strcpy(infile, argv[optind]); + */ +#include +#include +#include +#include +int usage(char **argv) +{ + fprintf(stderr, "Usage: %s (v1.20) [-v] [-V] [-x n] [-y n] [-r x] infile [callid_or_firstfile]\n\n", argv[0]); + fprintf(stderr, "Where: -v = verbose print. Default = no printing.\n"); + fprintf(stderr, " -V = Output entire volume. Default = output first sweep only.\n"); + fprintf(stderr, " -x n = Image dimension, image is n x n pixels. Default = 400x400 pixels.\n"); + fprintf(stderr, " -r x = Range of radar data. Default = 400.0 km.\n"); + fprintf(stderr, " -b x = Make black for dbz below x. Default = 0 (no action).\n"); + exit(-1); +} +process_args(int argc, char **argv, + char **in_file, char **callid, int *verbose, int *wholevolume, + int *xdim, float *range, int *dbz_black) +{ + int c; + + while ((c = getopt(argc, argv, "x:r:b:vV")) != -1) + switch (c) { + case 'v': *verbose = 1; break; + case 'V': *wholevolume = 1; break; + case 'x': *xdim = atoi(optarg); break; + case 'r': *range = atof(optarg); break; + case 'b': *dbz_black = atoi(optarg); break; + case '?': usage(argv); break; + default: break; + } + +/* must have 2 files listed */ + if (argc - optind != 1 && argc - optind != 2) usage(argv); + +/* Can use strdup, if desired */ +/* strdup allocates memory */ +/* in_file = strdup(argv[optind]); */ + *in_file = strdup(argv[optind]); + if (argc - optind == 2) *callid = strdup(argv[optind+1]); + else *callid = NULL; + +} + + +void main(int argc, char **argv) +{ + Radar *radar; + Sweep *sweep; + Ray *ray; + int i, j; + char fname[1000]; + char *infile, *callid; + char time_string[100]; + int verbose; + int wholevolume; + int xdim; + float range; + int dbz_black; + + verbose = 0; + wholevolume = 0; + xdim = 400; + range = 400.0; + dbz_black = 0; + process_args(argc, argv, &infile, &callid, &verbose, &wholevolume, + &xdim, &range, &dbz_black); + + if (verbose) + RSL_radar_verbose_on(); /* Not needed; it bides the time. */ + RSL_select_fields("all", NULL); + RSL_read_these_sweeps("all", NULL); + radar = RSL_anyformat_to_radar(infile, callid); + + if (radar == NULL) exit(-1); + + if (0) { + RSL_write_radar(radar, "rsl.rsl"); + exit(0); + } + + sprintf(time_string,"%2.2d%2.2d%2.2d_%2.2d%2.2d", + radar->h.month, radar->h.day, radar->h.year-1900, + radar->h.hour, radar->h.minute); + + for (i=0; iv[i]); + ray = RSL_get_first_ray_of_volume(radar->v[i]); + + if (sweep) { + if (i == SW_INDEX) + RSL_load_sw_color_table(); + else if (i == VR_INDEX || i == VE_INDEX) { + RSL_load_vel_color_table(); + RSL_rebin_velocity_volume(radar->v[i]); + } else + RSL_load_refl_color_table(); + + { + char r[256], g[256], b[256]; + int nc; + int i; + RSL_get_color_table(RSL_RED_TABLE, r, &nc); + RSL_get_color_table(RSL_GREEN_TABLE, g, &nc); + RSL_get_color_table(RSL_BLUE_TABLE, b, &nc); + for (i=0; ih.name, sizeof(radar->h.name)); + for (j=0; jh.name); j++) + if (fname[j] == '\0' || fname[j] == ' ') break; + if (j==sizeof(radar->h.name)) j--; + + if (! wholevolume) { + sprintf(&fname[j], "_%s_%s.gif", RSL_ftype[i], time_string); + /* printf("FNAME = <%s>\n", fname); */ + RSL_sweep_to_gif(sweep, fname, xdim, xdim, range); + printf("%s\n", fname); + } else { + sprintf(&fname[j], "_%s_%s", RSL_ftype[i], time_string); + /* RSL_volume_to_gif outputs to stdout the filenames produced. */ + RSL_volume_to_gif(radar->v[i], fname, xdim, xdim, range); + } + } + } + exit(0); + +} + + + diff --git a/examples/any_to_ppm.c b/examples/any_to_ppm.c new file mode 100644 index 0000000..62293b1 --- /dev/null +++ b/examples/any_to_ppm.c @@ -0,0 +1,78 @@ +/* + * Ingest NEXRAD (wsr88d) data and output images representing + * all field types found. + * + * This example is the most minimum of coding that you need to do + * to achieve good results from using the RSL code. + * + * This is short and sweet to demonstrate the simplicity of use for + * the RSL. + * + */ + +#define USE_RSL_VARS +#include "rsl.h" + +void main(int argc, char **argv) +{ + Radar *radar; + Sweep *sweep; + Ray *ray; + int i; + char fname[100]; + + if (argc < 2 || argc > 3) { + fprintf(stderr, "Usage: %s infile [callid_or_firstfile]\n", argv[0]); + exit(-1); + } + + RSL_radar_verbose_on(); /* Not needed; it bides the time. */ + RSL_select_fields("all", NULL); + radar = RSL_anyformat_to_radar(argv[1], argv[2]); + + if (radar == NULL) exit(-1); + + if (0) { + RSL_write_radar(radar, "rsl.rsl"); + exit(0); + } + + { + char time_string[100]; + sprintf(time_string,"%2.2d%2.2d%2.2d_%2.2d%2.2d", + radar->h.month, radar->h.day, radar->h.year-1900, + radar->h.hour, radar->h.minute); + } + + for (i=0; iv[i]); + ray = RSL_get_first_ray_of_volume(radar->v[i]); + + if (sweep) { + if (i == SW_INDEX) + RSL_load_sw_color_table(); + else if (i == VR_INDEX || i == VE_INDEX) { + RSL_load_vel_color_table(); + RSL_rebin_velocity_volume(radar->v[i]); + } else + RSL_load_refl_color_table(); + + +#undef DO_SWEEP +#define DO_SWEEP +#ifdef DO_SWEEP + sprintf(fname, "%s_sweep.ppm", RSL_ftype[i]); + RSL_sweep_to_ppm(sweep, fname, 400, 400, 200.0); + fprintf(stderr, "Wrote %s\n", fname); +#else + sprintf(fname, "%s_sweep", RSL_ftype[i]); + RSL_volume_to_gif(radar->v[i], fname, 400, 400, 200.0); +#endif + } + } + exit(0); + +} + + + diff --git a/examples/any_to_uf.c b/examples/any_to_uf.c new file mode 100644 index 0000000..eecca35 --- /dev/null +++ b/examples/any_to_uf.c @@ -0,0 +1,52 @@ +#include +#include "rsl.h" + +#include +#include +#include +#include + +void usage(char **argv) +{ + fprintf(stderr, "Usage: %s [-f firstfile] infile outfile\n", argv[0]); + exit(-1); +} + +process_args(int argc, char **argv, + char **in_file, char **out_file, char **first_file) +{ + int c; + + while ((c = getopt(argc, argv, "f:")) != -1) + switch (c) { + case 'f': *first_file = strdup(optarg); break; + case '?': usage(argv); break; + default: break; + } + +/* must have 2 files listed */ + if (argc - optind != 2) usage(argv); + +/* Can use strdup, if desired */ +/* strdup allocates memory */ +/* in_file = strdup(argv[optind]); */ + *in_file = strdup(argv[optind]); + *out_file = strdup(argv[optind+1]); +} + + +main (int argc, char **argv) +{ + + Radar *radar; + char *infile, *outfile, *first_file; + + first_file = NULL; + process_args(argc, argv, &infile, &outfile, &first_file); + RSL_radar_verbose_on(); + radar = RSL_anyformat_to_radar(infile, first_file); + RSL_radar_to_uf(radar, outfile); + +} + + diff --git a/examples/any_to_ufgz.c b/examples/any_to_ufgz.c new file mode 100644 index 0000000..cd8af70 --- /dev/null +++ b/examples/any_to_ufgz.c @@ -0,0 +1,52 @@ +#include +#include "rsl.h" + +#include +#include +#include +#include + +void usage(char **argv) +{ + fprintf(stderr, "Usage: %s [-f firstfile] infile outfile\n", argv[0]); + exit(-1); +} + +process_args(int argc, char **argv, + char **in_file, char **out_file, char **first_file) +{ + int c; + + while ((c = getopt(argc, argv, "f:")) != -1) + switch (c) { + case 'f': *first_file = strdup(optarg); break; + case '?': usage(argv); break; + default: break; + } + +/* must have 2 files listed */ + if (argc - optind != 2) usage(argv); + +/* Can use strdup, if desired */ +/* strdup allocates memory */ +/* in_file = strdup(argv[optind]); */ + *in_file = strdup(argv[optind]); + *out_file = strdup(argv[optind+1]); +} + + +main (int argc, char **argv) +{ + + Radar *radar; + char *infile, *outfile, *first_file; + + first_file = NULL; + process_args(argc, argv, &infile, &outfile, &first_file); + + radar = RSL_anyformat_to_radar(infile, first_file); + RSL_radar_to_uf_gzip(radar, outfile); + +} + + diff --git a/examples/bscan.c b/examples/bscan.c new file mode 100644 index 0000000..7f4dd41 --- /dev/null +++ b/examples/bscan.c @@ -0,0 +1,88 @@ +/* + * For RSL version 0.28 and higher. + * + * v1.0 Began 2/16/94 by John Merritt. + * + * Demonstrates reading NEXRAD files and loading the Radar structure. + */ + + + +#include +#ifdef sgi +#include +#endif +#include +#include + +#include "rsl.h" + +usage() +{ + fprintf(stderr,"Usage: bscan infile [callid]\n"); + exit(-1); +} + +process_args(int argc, char **argv, + char **in_file, char **callid) +{ + + if (argc < 2) usage(); + else if (argc == 2) *in_file = strdup(argv[1]); + else if (argc == 3) { + *in_file = strdup(argv[1]); + *callid = strdup(argv[2]); + } else { + usage(); + } +} + + +main(int argc, char **argv) +{ + char *infile, *callid; + + Radar *radar; + Volume *cappi_vol; + char *index_str[] = {"DZ", "VR", "SW"}; + + int i; + +/* 1. Process the arguments. */ + callid = NULL; + process_args(argc, argv, &infile, &callid); /* malloc for in/outfile */ + + +/* + * Pass bitwise or of DZ_MASK, VR_MASK, SW_MASK + */ + i = DZ_INDEX; + + RSL_radar_verbose_on(); + if ((radar = RSL_anyformat_to_radar(infile, callid)) == NULL) exit(-1); + + printf("Radar date: %2.2d/%2.2d/%2.2d\n", radar->h.month, radar->h.day, radar->h.year); + printf("Radar time: %2.2d:%2.2d:%f\n", radar->h.hour, radar->h.minute, radar->h.sec); + + printf("Radar file: %s\n", infile); + printf("Radar site: %c%c%c%c\n", + radar->h.name[0], + radar->h.name[1], + radar->h.name[2], + radar->h.name[3]); + printf("Radar date: %2.2d/%2.2d/%2.2d\n", radar->h.month, radar->h.day, radar->h.year); + printf("Radar time: %2.2d:%2.2d:%f\n", radar->h.hour, radar->h.minute, radar->h.sec); + + + if (i == DZ_INDEX) RSL_load_refl_color_table(); + if (i == VR_INDEX) RSL_load_vel_color_table(); + if (i == SW_INDEX) RSL_load_sw_color_table(); + if (i == VR_INDEX) RSL_rebin_velocity_volume(radar->v[i]); /* Modifies v[i]. */ + + printf("Generating bscan ppm images of %s\n", index_str[i]); + RSL_bscan_volume((Volume *) radar->v[i], "bscan.ppm"); + printf("----> BSCAN complete.\n"); + + exit(0); + +} diff --git a/examples/cappi_image.c b/examples/cappi_image.c new file mode 100644 index 0000000..f2ab637 --- /dev/null +++ b/examples/cappi_image.c @@ -0,0 +1,82 @@ +/* + * For RSL version 0.28 and higher. + * + * v1.0 Began 2/16/94 by John Merritt. + * + * Demonstrates reading NEXRAD files and loading the Radar structure. + */ + +#include +#include +#include "rsl.h" + +usage(int argc, char **argv) +{ + fprintf(stderr,"Usage: %s infile [firstfile | callid]\n", argv[0]); + exit(-1); +} + +process_args(int argc, char **argv, + char **in_file, char **out_file) +{ + + if (argc == 2) { + *in_file = strdup(argv[1]); + *out_file = NULL; + } else if (argc == 3) { + *in_file = strdup(argv[1]); + *out_file = strdup(argv[2]); + } else { + usage(argc, argv); + } +} + + +main(int argc, char **argv) +{ + char *infile, *firstfile; + char outfile[100]; + + Radar *radar; + Cappi *cappi; + + int i, j; + +/* 1. Process the arguments. */ + process_args(argc, argv, &infile, &firstfile); /* malloc for in/outfile */ + + + i = DZ_INDEX; + + RSL_radar_verbose_on(); + if ((radar = RSL_anyformat_to_radar(infile, firstfile)) == NULL) exit(-1); + + printf("Radar date: %2.2d/%2.2d/%2.2d\n", radar->h.month, radar->h.day, radar->h.year); + printf("Radar time: %2.2d:%2.2d:%f\n", radar->h.hour, radar->h.minute, radar->h.sec); + printf("Radar file: %s\n", infile); + printf("Radar site: %c%c%c%c\n", + radar->h.name[0], + radar->h.name[1], + radar->h.name[2], + radar->h.name[3]); + printf("Radar date: %2.2d/%2.2d/%2.2d\n", radar->h.month, radar->h.day, radar->h.year); + printf("Radar time: %2.2d:%2.2d:%f\n", radar->h.hour, radar->h.minute, radar->h.sec); + + + if (i == DZ_INDEX) RSL_load_refl_color_table(); + if (i == VR_INDEX) RSL_load_vel_color_table(); + if (i == SW_INDEX) RSL_load_sw_color_table(); + if (i == VR_INDEX) RSL_rebin_velocity_volume(radar->v[i]); /* Modifies v[i]. */ + + for (j=1; j<=5; j++) { + cappi = RSL_cappi_at_h( radar -> v[i], (float)j/2.0, 200.0); + sprintf(outfile, "cappi_%2.2d.gif", j); + printf("Writing %s.\n", outfile); + RSL_sweep_to_gif(cappi->sweep, outfile, 400, 400, 200.0); + RSL_free_cappi(cappi); + } + + + exit(0); + +} diff --git a/examples/dorade_main.c b/examples/dorade_main.c new file mode 100644 index 0000000..120dd14 --- /dev/null +++ b/examples/dorade_main.c @@ -0,0 +1,21 @@ +#include +#include "rsl.h" + +int main(int argc, char **argv) +{ + Radar *radar; + + if (argc != 2) { + fprintf(stderr, "No filename specified.\n"); + exit(0); + } + + RSL_radar_verbose_on(); + radar = RSL_dorade_to_radar(argv[1]); + if (radar == NULL) + printf("radar == NULL\n"); + else + printf("radar == %x\n", radar); + + exit(0); +} diff --git a/examples/killer_sweep.c b/examples/killer_sweep.c new file mode 100644 index 0000000..139b231 --- /dev/null +++ b/examples/killer_sweep.c @@ -0,0 +1,180 @@ +/* + * This app tests what happens when a sweep has just one azimuth bin for + * all the rays. I will first read real data then permute the sweeps. + * Then, I'll check how the hash table were built. Based on print_hash_table. + */ + +#include "rsl.h" +#include +void print_link_list(Azimuth_hash *list) +{ + if (list == NULL) { + printf("\n"); + return; + } + printf("\n ray# %d azim %f, hi# %d lo# %d", list->ray->h.ray_num, list->ray->h.azimuth, list->ray_high->ray->h.ray_num, list->ray_low->ray->h.ray_num); + print_link_list(list->next); +} + + +/* + * Cannot compile if the hash table is static in volume.c. For + * testing we make it globally known. + */ + +typedef struct { + Sweep *s_addr; + Hash_table *hash; +} Sweep_list; + +extern int RSL_max_sweeps; /* Initial allocation for sweep_list. + * RSL_new_sweep will allocate the space first + * time around. + */ +extern int RSL_nsweep_addr; /* A count of sweeps in the table. */ +extern Sweep_list *RSL_sweep_list; +extern int RSL_nextents; + +void print_hash_table (Sweep *s) +{ + int i; + int sweep_index; + Azimuth_hash *index; + float azim; + float res; + + if (s == NULL) return; + sweep_index = SWEEP_INDEX(s); + res = 360.0/RSL_sweep_list[sweep_index].hash->nindexes; + printf("Azimuth resolution = %f for %d bins.\n", res, RSL_sweep_list[sweep_index].hash->nindexes); + for (i=0; inindexes; i++) { + index = RSL_sweep_list[sweep_index].hash->indexes[i]; + azim = i/res; + printf("RSL_sweep_list[%d].hash->indexes[%d] = ", sweep_index, i); + + if (index == NULL) + printf("IS NULL\n"); + else + print_link_list(index); + } +} + +void poke_about_sweep(Sweep *s) +{ + /* This routine demonstrates that the azimuth we want is the azimuth + * we get. + */ + float azim, res; + Ray *ray; + + ray = RSL_get_first_ray_of_sweep(s); + res = 360.0/s->h.nrays; + for (azim=0; azim<360; azim+=res) { + ray = RSL_get_ray_from_sweep(s, azim); + if (ray) + printf("Azimuth %f matched in ray # %d, h.azimuth= %f, diff=%f\n", + azim, ray->h.ray_num, ray->h.azimuth, + ray->h.azimuth-azim); + else + printf("Azimuth %f NOT FOUND within 1/2 beamwidth; 1/2beam=%f\n", + azim, s->h.horz_half_bw); + } +} + +float random_azim(void) +{ + double drand; + drand = drand48()*1; + return (float)drand; +} + +Sweep *permute_sweep(Sweep *sweep) +{ + int i; + Ray *ray; + if (sweep == NULL) return NULL; + for (i=0; ih.nrays; i++) { + ray = sweep->ray[i]; + if (ray == NULL) continue; + ray->h.azimuth = random_azim(); + } + return sweep; +} +Volume *permute_volume(Volume *volume) +{ + int i; + if (volume == NULL) return NULL; + for (i=0; ih.nsweeps; i++) + volume->sweep[i] = permute_sweep(volume->sweep[i]); + return volume; +} +Radar *permute_radar(Radar *radar) +{ + int i; + if (radar == NULL) return NULL; + for (i=0; ih.nvolumes; i++) + radar->v[i] = permute_volume(radar->v[i]); + printf("Radar permuted. Now, redo the ray_indexes.\n"); + return radar; +} + +void chase_hi_links(Sweep *sweep) +{ + int i; + Azimuth_hash *table; + Hash_table *hash_table; + float last_azimuth; + float azimuth; + + if (sweep == NULL) return; + hash_table = hash_table_for_sweep(sweep); + table = hash_table->indexes[0]; + + printf("Printing HI links. This has better be a sorted output.\n"); + printf("ELEVATION angle = %f\n", sweep->h.elev); + for (i=0, last_azimuth=-1;ih.nrays; i++) { + if (table == NULL) continue; + printf(" ray# %3d azim %8.6f hi# %3d lo# %3d\n", + table->ray->h.ray_num, + table->ray->h.azimuth, + table->ray_high->ray->h.ray_num, + table->ray_low->ray->h.ray_num); + azimuth = table->ray->h.azimuth; + if (azimuth < last_azimuth) printf("AZIMUTH OUT OF ORDER\n"); + last_azimuth = azimuth; + table = table->ray_high; + } +} + +void main(int argc, char **argv) +{ + Radar *radar; + Sweep *sweep; + int i; + + if (argc < 2 || argc > 3) {fprintf(stderr, "Usage: %s infile [callid_or_firstfile]\n", argv[0]); exit(-1);} + RSL_radar_verbose_on(); + radar = RSL_anyformat_to_radar(argv[1], argv[2]); + if (radar == NULL) { + printf("RADAR IS NULL.\n"); + exit(-1); + } + + printf("permute_radar\n"); + radar = permute_radar(radar); + + for (i=0; iv[DZ_INDEX]->h.nsweeps; i++) { + sweep = radar->v[DZ_INDEX]->sweep[i]; + chase_hi_links(sweep); + } +/* + print_hash_table(sweep); + + poke_about_sweep(sweep); +*/ + exit(0); + +} + + + diff --git a/examples/kwaj_subtract_one_day.c b/examples/kwaj_subtract_one_day.c new file mode 100644 index 0000000..65acfaa --- /dev/null +++ b/examples/kwaj_subtract_one_day.c @@ -0,0 +1,121 @@ +#include "rsl.h" + +/**********************************************************************/ +/* */ +/* usage */ +/* */ +/**********************************************************************/ +void usage(char **argv) +{ + fprintf(stderr, "Usage: %s in out.uf\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "Subtract one day from all time fields in all headers,\n"); + fprintf(stderr, "all the way down to the ray. Output to uf.\n"); + return; +} + +/**********************************************************************/ +/* */ +/* subtract_one_day_ray */ +/* */ +/**********************************************************************/ +#include +void *subtract_one_day(int month, int day, int year, + int *m, int *d, int *y) +{ + /* Connocialize and subtract. */ + struct tm *t; + time_t the_time; + + t = (struct tm *)calloc(1, sizeof(struct tm)); + t->tm_mon = month-1; /* 0 - 11 */ + t->tm_mday = day-1; /* 1 - 31 */ /* And, subtract one day. */ + t->tm_year = year-1900; /* since 1900 */ + the_time = mktime(t); + t = localtime(&the_time); + *m = t->tm_mon+1; + *d = t->tm_mday; + *y = t->tm_year+1900; + return; +} + +/**********************************************************************/ +/* */ +/* subtract_one_day_ray */ +/* */ +/**********************************************************************/ +Ray *subtract_one_day_ray(Ray *x) +{ + if (x == NULL) return x; + subtract_one_day(x->h.month, x->h.day, x->h.year, + &x->h.month, &x->h.day, &x->h.year); + return x; +} +/**********************************************************************/ +/* */ +/* subtract_one_day_sweep */ +/* */ +/**********************************************************************/ +Sweep *subtract_one_day_sweep(Sweep *x) +{ + int i; + + if (x == NULL) return x; + for(i=0; ih.nrays; i++) + x->ray[i] = subtract_one_day_ray(x->ray[i]); + return x; +} +/**********************************************************************/ +/* */ +/* subtract_one_day_volume */ +/* */ +/**********************************************************************/ +Volume *subtract_one_day_volume(Volume *x) +{ + int i; + + if (x == NULL) return x; + for(i=0; ih.nsweeps; i++) + x->sweep[i] = subtract_one_day_sweep(x->sweep[i]); + return x; +} +/**********************************************************************/ +/* */ +/* subtract_one_day_radar */ +/* */ +/**********************************************************************/ +Radar *subtract_one_day_radar(Radar *x) +{ + int i; + + if (x == NULL) return x; + for(i=0; ih.nvolumes; i++) + x->v[i] = subtract_one_day_volume(x->v[i]); + return x; +} + + + +/**********************************************************************/ +/* */ +/* m a i n */ +/* */ +/**********************************************************************/ +int main(int argc, char **argv) +{ + + Radar *radar; + + if (argc != 3) { + usage(argv); + exit(-1); + } + + radar = RSL_anyformat_to_radar(argv[1]); + radar = subtract_one_day_radar(radar); + subtract_one_day(radar->h.month, radar->h.day, radar->h.year, + &radar->h.month, &radar->h.day, &radar->h.year); + RSL_radar_to_uf_gzip(radar, argv[2]); + + exit(0); +} diff --git a/examples/lassen_to_gif.c b/examples/lassen_to_gif.c new file mode 100644 index 0000000..dd9a168 --- /dev/null +++ b/examples/lassen_to_gif.c @@ -0,0 +1,32 @@ +/* + * lassen_to_gif [file] + * + * This program can read the file from stdin. + */ + +#include "rsl.h" + +void main(int argc, char **argv) +{ + Radar *radar; + + RSL_radar_verbose_on(); + radar = RSL_lassen_to_radar(argv[1]); + if (radar == NULL) exit(-1); + + RSL_load_refl_color_table(); + RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0); + + RSL_load_vel_color_table(); + RSL_rebin_velocity_volume(radar->v[VR_INDEX]); /* Modifies v[i]. */ + RSL_volume_to_gif(radar->v[VR_INDEX], "vr_sweep", 400, 400, 200.0); + + RSL_load_sw_color_table(); + RSL_volume_to_gif(radar->v[SW_INDEX], "sw_sweep", 400, 400, 200.0); + + exit(0); + +} + + + diff --git a/examples/print_hash_table.c b/examples/print_hash_table.c new file mode 100644 index 0000000..0505fb8 --- /dev/null +++ b/examples/print_hash_table.c @@ -0,0 +1,121 @@ +/* + * Ingest NEXRAD (wsr88d) data and print the azimuth hash table created. + * + * This example is the most minimum of coding that you need to do + * to achieve good results from using the RSL code. + * + * This is short and sweet to demonstrate the simplicity of use for + * the RSL. + * + */ + +#include "rsl.h" + +void print_link_list(Azimuth_hash *list) +{ + if (list == NULL) { + printf("\n"); + return; + } + printf("ray# %d azim %f, hi# %d lo# %d|", list->ray->h.ray_num, list->ray->h.azimuth, list->ray_high->ray->h.ray_num, list->ray_low->ray->h.ray_num); + print_link_list(list->next); +} + + +/* + * Cannot compile if the hash table is static in volume.c. For + * testing we make it globally known. + */ + +typedef struct { + Sweep *s_addr; + Hash_table *hash; +} Sweep_list; + +extern int RSL_max_sweeps; /* Initial allocation for sweep_list. + * RSL_new_sweep will allocate the space first + * time around. + */ +extern int RSL_nsweep_addr; /* A count of sweeps in the table. */ +extern Sweep_list *RSL_sweep_list; +extern int RSL_nextents; + +void print_hash_table (Sweep *s) +{ + int i; + int sweep_index; + Azimuth_hash *index; + float azim; + float res; + + if (s == NULL) return; + sweep_index = SWEEP_INDEX(s); + res = 360.0/RSL_sweep_list[sweep_index].hash->nindexes; + printf("Azimuth resolution = %f for %d bins.\n", res, RSL_sweep_list[sweep_index].hash->nindexes); + for (i=0; inindexes; i++) { + index = RSL_sweep_list[sweep_index].hash->indexes[i]; + azim = i/res; + printf("RSL_sweep_list[%d].hash->indexes[%d] = ", sweep_index, i); + + if (index == NULL) + printf("IS NULL\n"); + else + print_link_list(index); + } +} + +void poke_about_sweep(Sweep *s) +{ + /* This routine demonstrates that the azimuth we want is the azimuth + * we get. + */ + float azim, res; + Ray *ray; + + ray = RSL_get_first_ray_of_sweep(s); + res = 360.0/s->h.nrays; + for (azim=0; azim<360; azim+=res) { + ray = RSL_get_ray_from_sweep(s, azim); + if (ray) + printf("Azimuth %f matched in ray # %d, h.azimuth= %f, diff=%f\n", + azim, ray->h.ray_num, ray->h.azimuth, + ray->h.azimuth-azim); + else + printf("Azimuth %f NOT FOUND within 1/2 beamwidth; 1/2beam=%f\n", + azim, s->h.horz_half_bw); + } +} + + +void main(int argc, char **argv) +{ + Radar *radar; + Sweep *sweep; + + if (argc != 3) {fprintf(stderr, "Usage: %s infile callid_or_firstfile\n", argv[0]); exit(-1);} + RSL_radar_verbose_on(); + radar = RSL_wsr88d_to_radar(argv[1], argv[2]); + if (radar == NULL) exit(-1); +/***********************************************************************/ +/* */ +/* You now have a pointer to Radar. */ +/* Now use *radar all you like. */ +/* */ +/***********************************************************************/ + +/* Use radar->v[DZ_INDEX] for REFELECTIVITY + * radar->v[VR_INDEX] for VELOCITY + * radar->v[SW_INDEX] for SPECTRUM_WIDTH + */ + + sweep = RSL_get_first_sweep_of_volume(radar->v[DZ_INDEX]); + print_hash_table(sweep); + + poke_about_sweep(sweep); + + exit(0); + +} + + + diff --git a/examples/print_header_info.c b/examples/print_header_info.c new file mode 100644 index 0000000..6167c81 --- /dev/null +++ b/examples/print_header_info.c @@ -0,0 +1,188 @@ + +#include +#include +#include +#include + +#include "rsl.h" + +int qprint_ray; + +usage(char **argv) +{ + fprintf(stderr,"Usage: %s [-v] [-f nexrad_id] [infile]\n", argv[0]); + exit(-1); +} + +process_args(int argc, char **argv, + char **in_file, int *qprint_ray, + char **site) +{ + + int c; + + while ((c = getopt(argc, argv, "vf:")) != -1) + switch (c) { + case 'v': *qprint_ray = 1; break; + case 'f': *site = strdup(optarg); break; + case '?': usage(argv); break; + default: break; + } + + if ((argc-optind) == 0) { + *in_file = NULL; + } else if ((argc-optind) == 1) { + *in_file = strdup(argv[optind]); + } else { + usage(argv); + } +} + +void print_ray_values(Ray *ray) +{ + int i,j; + + if (ray == NULL) { + printf("Ray = NULL\n"); + return; + } + + for (i=0; ih.nbins; i+=10) { + for (j=i; j<(i+10)&&jh.nbins; j++) + printf("%10.2f", ray->h.f(ray->range[j])); + printf("\n"); + } + return; +} + +void print_header_for_ray(Ray *ray) +{ + if (ray==NULL) {printf("NULL."); return;} + +printf(" month %d\n", ray->h.month); /* Time for this ray; month (1-12). */ +printf(" day %d\n", ray->h.day); /* Time for this ray; day (1-31). */ +printf(" year %d\n", ray->h.year); /* Time for this ray; year (eg. 1993). */ +printf(" hour %d\n", ray->h.hour); /* Date for this ray; hour (0-23). */ +printf(" minute %d\n", ray->h.minute);/* Date for this ray; minute (0-59).*/ +printf(" sec %f\n", ray->h.sec); /* Date for this ray; second + fraction of second. */ +printf(" unam %f\n", ray->h.unam_rng); /* Unambiguous range. (KM). */ +printf(" azimuth %f\n", ray->h.azimuth); /* Azimuth angle. (degrees). 0=North, 90=east, -90=west. */ +printf(" ray_num %d\n", ray->h.ray_num); /* Ray no. within elevation scan. */ +printf(" elev %f\n", ray->h.elev); /* Elevation angle. (degrees). */ +printf("elev_num %d\n", ray->h.elev_num); /* Elevation no. within volume scan. */ + +printf(" range_bin1 %d\n", ray->h.range_bin1); /* Range to first gate.(meters) */ +printf(" gate_size %d\n", ray->h.gate_size); /* Data gate size (meters)*/ + +printf(" vel_res %f\n", ray->h.vel_res); /* Doppler velocity resolution */ +printf(" sweep_rate %f\n", ray->h.sweep_rate); /* Sweep rate. Full sweeps/min. */ + +printf(" prf %f\n", ray->h.prf); /* Pulse repitition frequency, in Hz. */ +printf(" azim_rate %f\n", ray->h.azim_rate); +printf(" fix_angle %f\n", ray->h.fix_angle); +printf("pulse_count %f\n", ray->h.pulse_count); +printf("pulse_width %f\n", ray->h.pulse_width); /* Pulse width (micro-sec). */ +printf(" beam_width %f\n", ray->h.beam_width); /* Beamwidth in degrees. */ +printf(" frequency %f\n", ray->h.frequency); /* Bandwidth MHz. */ +printf(" wavelength %f\n", ray->h.wavelength); /* Wavelength. Meters. */ +printf(" nyq_vel %f\n", ray->h.nyq_vel); /* Nyquist velocity. m/s */ +printf(" latitude %f\n", ray->h.lat); /* Latitude (decimal) */ +printf(" longitude %f\n", ray->h.lon); /* Longitude (decimal) */ +printf(" nbins %d\n", ray->h.nbins); /* Number of array elements for 'Range'. */ + +if (!qprint_ray) return; + +print_ray_values(ray); + +} + +void print_header_for_sweep(Sweep *s) +{ + int i; + + if (s==NULL) return; + for (i=0; ih.nrays; i++) { + printf("ray[%d] ",i ); + print_header_for_ray(s->ray[i]); + printf("\n"); + } + +} + +void print_header_for_volume(Volume *v) +{ + int i; + if (v==NULL) return; + for (i=0; ih.nsweeps; i++) { + printf("-------- Sweep %d ---------\n", i); + print_header_for_sweep(v->sweep[i]); + } +} + + +main(int argc, char **argv) +{ + char *infile; + + Radar *radar; + char *site = NULL; + int i; + + qprint_ray = 0; /* Global flag for printing ray values. */ + process_args(argc, argv, &infile, &qprint_ray, &site); /* malloc for in/outfile */ + + RSL_radar_verbose_on(); + RSL_read_these_sweeps("all", NULL); + + radar = RSL_anyformat_to_radar(infile, site); + + printf("Radar date: %2.2d/%2.2d/%2.2d\n", radar->h.month, radar->h.day, radar->h.year); + printf("Radar time: %2.2d:%2.2d:%f\n", radar->h.hour, radar->h.minute, radar->h.sec); + + printf("Radar file: %s\n", infile); + printf("Radar site: %c%c%c%c\n", + radar->h.name[0], + radar->h.name[1], + radar->h.name[2], + radar->h.name[3]); + printf("Radar date: %2.2d/%2.2d/%2.2d\n", radar->h.month, radar->h.day, radar->h.year); + printf("Radar time: %2.2d:%2.2d:%f\n", radar->h.hour, radar->h.minute, radar->h.sec); + + +printf("Radar sec : %f\n", radar->h.sec); /* Second plus fractional part. */ +printf("Radar radar_type: %s\n", radar->h.radar_type); + /* Type of radar. Use for QC-ing the data. + * Supported types are: + * "wsr88d", "lassen", "uf", + * "nsig", "mcgill", + * "kwajalein", "rsl", "toga". + * Set by appropriate ingest routine. + */ +printf("Radar nvolumes : %d\n", radar->h.nvolumes); +printf("Radar number : %d\n", radar->h.number); +printf("Radar name : %s\n", radar->h.name); +printf("Radar radar_name: %s\n", radar->h.radar_name); +printf("Radar city : %s\n", radar->h.city); +printf("Radar state : %s\n", radar->h.state); +printf("Radar latd: %d\n", radar->h.latd); +printf("Radar latm: %d\n", radar->h.latm); +printf("Radar lats: %d\n", radar->h.lats); +printf("Radar lond: %d\n", radar->h.lond); +printf("Radar lonm: %d\n", radar->h.lonm); +printf("Radar lons: %d\n", radar->h.lons); +printf("Radar height: %d\n", radar->h.height); +printf("Radar spulse: %d\n", radar->h.spulse); +printf("Radar lpulse: %d\n", radar->h.lpulse); +printf("Radar lpulse: %d\n", radar->h.lpulse); + + +for (i=0; ih.nvolumes; i++) { + + if (radar->v[i]) { + printf("PRINT_HEADER_FOR_VOLUME, %d, ... nsweeps = %d\n", i, radar->v[i]->h.nsweeps); + print_header_for_volume(radar->v[i]); + } +} +exit(0); + +} diff --git a/examples/qlook.c b/examples/qlook.c new file mode 100644 index 0000000..dc767f6 --- /dev/null +++ b/examples/qlook.c @@ -0,0 +1,688 @@ +#define TRUE 1 +#define FALSE 0 +#include +#include +#include +#include +#include +#include "rsl.h" + +#define ZDR_WIDTH 10 +int verbose; + +void rebin_ray(Ray *r, int width); +void rebin_sweep(Sweep *s, int width); +void rebin_volume(Volume *v, int width); +void adjust_gate_size(Radar *radar, float gate_size_adjustment); + +void process_args(int argc, char **argv, char *in_file, int *verbose, + char *site_id, char *tape_id, + int *qc_reflectivity, int *total_reflectivity, + int *differential_reflectivity, + int *velocity, int *spectral_width, + int *make_gif, int *make_pgm, int *make_bscan, int *make_uf, + int *num_sweeps, float *dbz_offset, + int *xdim, int *ydim, float *range, + float *gate_size_adjustment, int *print_azim); + +/***********************************************************************/ +/* This program uses the NASA TRMM Office Radar Software Library (RSL) */ +/***********************************************************************/ +/*** DBW ***************************************************************/ +/***********************************************************************/ +main(int argc, char **argv) { + + Radar *radar; + Volume *dz_volume, *vr_volume; + Volume *dr_volume, *zt_volume; + Volume *sw_volume, *qc_volume, *volume; + + Sweep *sweep; + Sweep *dz_sweep, *qc_sweep; + Sweep *dr_sweep, *zt_sweep; + Sweep *vr_sweep, *sw_sweep; + + Ray *ray; + int reflectivity, qc_reflectivity, nvolumes; + int differential_reflectivity, total_reflectivity; + int velocity, spectral_width; + int make_catalog, make_gif, make_pgm; + int make_uf, make_bscan; + int xdim, ydim, num_sweeps; + int i,j,k,l,n, verbose, kk; + int month, day, year, hour, min; + int ncbins, width; + int print_azim; + float scale, dbz_offset; + float latitude, longitude; + + float sec; + float maxr; + float nyquist, max_range, gate_size_adjustment; + + char tape_id[100]; + char in_file[100], site_id[100]; + char filename[100], outfile[100], nexfile[100]; + char command[100], file_prefix[100], file_suffix[3]; + char dir_string[100], red[120], grn[120], blu[120]; + char time_string[14], site_string[10],img_base[20]; + FILE *fp; + +/* Set default values */ + + strcpy(site_id, "KMLB"); + strcpy(tape_id, "WSR88D"); + + verbose = FALSE; + reflectivity = TRUE; + qc_reflectivity = FALSE; + total_reflectivity = FALSE; + differential_reflectivity = FALSE; + velocity = FALSE; + spectral_width = FALSE; + make_gif = FALSE; + make_pgm = FALSE; + make_catalog = FALSE; + make_uf = FALSE; + print_azim = FALSE; + num_sweeps = 1; + xdim = ydim = 400; + maxr = 200.; + dbz_offset = 0.0; + gate_size_adjustment = 1.0; + +/* Process command_line arguments */ + + process_args(argc, argv, in_file, &verbose, + site_id, tape_id, + &qc_reflectivity, &total_reflectivity, + &differential_reflectivity, + &velocity, &spectral_width, + &make_gif, &make_pgm, &make_bscan, &make_uf, + &num_sweeps, &dbz_offset, + &xdim, &ydim, &maxr, &gate_size_adjustment, + &print_azim); + +/* Be a chatty Kathy? */ + + if(verbose) + RSL_radar_verbose_on(); + else + RSL_radar_verbose_off(); + +/* Read data into radar */ + + if(verbose) printf("Calling any_format_to_radar\n"); + radar = RSL_anyformat_to_radar(in_file, site_id); + if(verbose) printf("Called any_format_to_radar\n"); + if(radar==NULL) { + if (verbose) + printf("No radar loaded, bye\n"); + exit(-1); + } + +/* Print command line parameters */ + + if(verbose) { + printf("Site ID = %s\n",site_id); + printf("Tape ID = %s\n",tape_id); + printf("Do reflectivity = %d\n",reflectivity); + printf("Do qc_reflectivity = %d\n",qc_reflectivity); + printf("Do differential_reflectivity = %d\n", + differential_reflectivity); + printf("Do total_reflectivity = %d\n", + total_reflectivity); + printf("Do qc_reflectivity = %d\n",qc_reflectivity); + printf("Do velocity = %d\n",velocity); + printf("Do spectral_width = %d\n",spectral_width); + printf("Make gif = %d\n",make_gif); + printf("Make pgm = %d\n",make_pgm); + printf("Make UF file = %d\n",make_uf); + printf("dBZ Offset = %.2f\n",dbz_offset); + printf("Gate Size Adjust = %.2f\n",gate_size_adjustment); + printf("Print Azimuths = %d\n",print_azim); + } + + +/* + If Gate Size Adjustment is not unity, then we must change the + following: + old_gs = radar->v[i]->sweep[sweepIndex]->ray[rayIndex=]->h.gate_size + radar->v[i]->sweep[sweepIndex]->ray[rayIndex=]->h.gate_size = + old_gs*gate_size_adjustment + + Here are some comments from Sandra Yuter on the necessity of this fix. + > I dug into the revelant code and it looks like we can do a relatively + > simple workaround for the SIGMET raw product file range bin size + > errors for the RHB data pulses widths of 0.5 usec and 2.0 usec as follows. + > + > Since we are all converting from sigmet to UF I suggest we resize + > the range bin size values in the ray headers in the qlook step + > where the sigmet to UF conversion occurs. + > + > The resize requires only 1 additional line of code (I have included + > a few others for context) in qlook.c + > + > rangeToFirstGate = 0.001 * + > radar->v[i]->sweep[sweepIndex]->ray[rayIndex]->h.range_bin1; + > gateSize = 0.001 * + > radar->v[i]->sweep[sweepIndex]->ray[rayIndex]->h.gate_size; + > radar->v[i]->sweep[sweepIndex]->ray[rayIndex]->h.gate_size= + > gateSize*0.6*1000; + > + > I have used 0.6 adjustment factor since that is 75/125 which corresponds + > to the error in my 0.5 usec data, for the SUR scans, this adjustment + > factor is 133.33/125 or 1.067. + + The following is from Joe Holmes from SIGMET + + > + > I think you have experienced a problem with the RVP7 range resolution + > configuration. Both in IRIS and in the RVP7 you manually type in + > the range resolution. The RVP7 allows a separate resolution for + > each pulsewidth, while IRIS only allows 1 value. There is no feedback + > if these values are not typed in the same. Based on setup information + > we have here from the RH Brown from Oct 23, 1998, you had the following + > configuration: + > + > RVP7: + > 0 0.50 usec 75.0m + > 1 0.80 usec 125.0m + > 2 1.39 usec 125.0m + > 3 2.00 usec 133.3m + > + > IRIS: 125.0 meters + > + > I think the error at PW#0 was corrected a while back, but + > the error in PW#3 was never corrected. Next time someone is + > at the ship, they should check this, fix the long pulse, and remake + > the bandpass filter for the long pulse. + > + > In the short term, you can correct the error by taking all your + > long pulse data and changing the header to correctly document the + > range resolution. We have a program to do this, it is called "change_raw". + > The source is on any IRIS system, which was installed with the + > source, headers, and objects turned on. It is in the + > ${IRIS_ROOT}utils/examples directory. We can supply you with + > a compiled version of this program, if you want. Available platforms + > are Linux, HP-UX, and IRIX. + +*/ + + if(gate_size_adjustment != 1.0) { + printf("Adjusting Gate Size by Factor: %.3f\n",gate_size_adjustment); + adjust_gate_size(radar, gate_size_adjustment); + } + + /* + Create the filename prefix. Consists of the Site ID, + and time string (YYMMDD_hhmm). The file suffix is + like MIME type (e.g, .gif, .pgm, .uf, etc.) +*/ + sprintf(time_string,"%4d/%2.2d%2.2d %2.2d:%2.2d UTC", + radar->h.year, radar->h.month, radar->h.day, + radar->h.hour, radar->h.minute); +/* + Determine the location (lat/lon) of the radar. + */ + latitude = radar->h.latd + radar->h.latm/60. + radar->h.lats/3600.; + longitude = radar->h.lond + radar->h.lonm/60. + radar->h.lons/3600.; + + printf("%s %s %s %.6f %.6f \n", + in_file, radar->h.radar_name, time_string, longitude, latitude); + + sprintf(time_string,"%4d_%2.2d%2.2d_%2.2d%2.2d", + radar->h.year, radar->h.month, radar->h.day, + radar->h.hour, radar->h.minute); + +/* + Print the radar/volume info. +*/ + +/* + * DZ Reflectivity (dBZ), may contain some DZ_INDEX + * signal-processor level QC and/or + * filters. This field would contain + * Darwin's CZ, or WSR88D's standard + * reflectivity. In other words, unless + * the field is described otherwise, it + * should always go here. In essence, this + * is the "cleanest" reflectivity field + * for a radar. + * + * VR Radial Velocity (m/s) VR_INDEX + * + * SW Spectral Width (m2/s2) SW_INDEX + * + * CZ QC Reflectivity (dBZ), contains + * post-processed QC'd data CZ_INDEX + * + * ZT Total Reflectivity (dBZ) ZT_INDEX + * May be uncommon, but important + * + * DR Differential reflectivity DR_INDEX + * DR and LR are for dual-polarization + * radars only. Unitless or in dB. + * + * LR Another form of differential ref LR_INDEX + * called LDR, not sure of units + * + * ZD ZDR: Reflectivity Depolarization Ratio ZD_INDEX + * ZDR = 10log(ZH/ZV) (dB) + * + * DM Received power measured by the radar. DM_INDEX + * Units are dBm. + * + * RH Rho : Correlation coefficient RH_INDEX + * + * PH Phi (MCTEX parameter) PH_INDEX + * + * XZ X-band reflectivity XZ_INDEX + * + * CR Corrected DR reflectivity (differential) CR_INDEX + * + * MZ DZ mask volume for HDF 1C-51 product. MZ_INDEX + * + * MR DR mask volume for HDF 1C-51 product. MR_INDEX + * + * ZE Edited Reflectivity. ZE_INDEX + * + * VE Edited Velocity. VE_INDEX + * + * + * 0 = DZ_INDEX = reflectivity. + * 1 = VR_INDEX = velocity. + * 2 = SW_INDEX = spectrum_width. + * 3 = CZ_INDEX = corrected reflectivity. + * 4 = ZT_INDEX = uncorrected reflectivity. + * 5 = DR_INDEX = differential refl. + * 6 = LR_INDEX = another differential refl. + * 7 = ZD_INDEX = another differential refl. + * 8 = DM_INDEX = received power. + * 9 = RH_INDEX = RhoHV: Horz-Vert power corr coeff + *10 = PH_INDEX = PhiDP: Differential phase angle + *11 = XZ_INDEX = X-band reflectivity. + *12 = CR_INDEX = Corrected DR. + *13 = MZ_INDEX = DZ mask for 1C-51 HDF. + *14 = MR_INDEX = DR mask for 1C-51 HDF. + *15 = ZE_INDEX = Edited reflectivity. + *16 = VE_INDEX = Edited velocity. + *17 = KD_INDEX = KDP deg/km. + *18 = TI_INDEX = TIME (unknown) for MCTEX data. + *19 = DX_INDEX + *20 = CH_INDEX + *21 = AH_INDEX + *22 = CV_INDEX + *23 = AV_INDEX +*/ + + + if(verbose) { + for(i=0; i< radar->h.nvolumes; i++) { + if(radar->v[i] != NULL) { + printf("Vol[%2.2d] has %d sweeps\n",i,radar->v[i]->h.nsweeps); + } else { + printf("Vol[%2.2d] == NULL\n",i); + } + } + printf("--------------------------------------------\n"); + printf("Number of volumes in radar: %d\n",radar->h.nvolumes); + } + + /* DZ_INDEX */ + if(radar->v[DZ_INDEX] == NULL) { + printf("DZ_INDEX == NULL\n"); + reflectivity = FALSE; + } else { + dz_volume = radar->v[DZ_INDEX]; + if(verbose) printf("Number of sweeps in dz_volume = %d\n", + dz_volume->h.nsweeps); + } + + /* CZ_INDEX */ + if(radar->v[CZ_INDEX] == NULL) { + if(verbose) printf("CZ_INDEX == NULL\n"); + qc_reflectivity = FALSE; + } else { + qc_volume = radar->v[CZ_INDEX]; + if(verbose) printf("Number of sweeps in qc_volume = %d\n", + qc_volume->h.nsweeps); + } + + /* ZT_INDEX */ + if(radar->v[ZT_INDEX] == NULL) { + if(verbose) printf("ZT_INDEX == NULL\n"); + total_reflectivity = FALSE; + } else { + zt_volume = radar->v[ZT_INDEX]; + if(verbose) printf("Number of sweeps in zt_volume = %d\n", + zt_volume->h.nsweeps); + } + /* ZD_INDEX */ + if(radar->v[ZD_INDEX] == NULL) { + if(verbose) printf("ZD_INDEX == NULL\n"); + differential_reflectivity = FALSE; + } else { + dr_volume = radar->v[ZD_INDEX]; + if(verbose) printf("Number of sweeps in dr_volume = %d\n", + dr_volume->h.nsweeps); + } + /* VR_INDEX */ + if(radar->v[VR_INDEX] == NULL) { + if(verbose) printf("VR_INDEX == NULL\n"); + velocity = FALSE; + } else { + vr_volume = radar->v[VR_INDEX]; + if(verbose) printf("Number of sweeps in vr_volume = %d\n", + vr_volume->h.nsweeps); + } + + /* SW_INDEX */ + if(radar->v[SW_INDEX] == NULL) { + if(verbose) printf("SW_INDEX == NULL\n"); + spectral_width = FALSE; + } else { + sw_volume = radar->v[SW_INDEX]; + if(verbose) printf("Number of sweeps in sw_volume = %d\n", + sw_volume->h.nsweeps); + } + if(verbose) printf("--------------------------------------------\n"); + +/* + Print out the elevation angles +*/ + if(verbose) { + if(reflectivity) { + printf("Reflectivity Tilts\n"); + printf("----------------------\n"); + if(dz_volume != NULL) { + for(i=0; ih.nsweeps; i++) { + sweep = dz_volume->sweep[i]; + if(sweep == NULL) { + printf("sweep[%d]==NULL\n",i); + continue; + } + printf("Tilt %2d, Elev=%4.1f\n",i,sweep->h.elev); + } + printf("----------------------\n"); + } + } + } + /* + Print out the values of the rays in each sweep requsted + */ + + if(print_azim) { + printf("Ray angles\n"); + if(reflectivity) { + for(i=0; ih.nsweeps; i++) { + if(dz_volume->sweep[i] != NULL) sweep = dz_volume->sweep[i]; + printf("Elevation angle: %f\n",sweep->h.elev); + printf("Number of rays in sweep[%d] = %d\n",i,sweep->h.nrays); + + for(j=0; jh.nrays-1; j++) { + if(sweep->ray[j] != NULL) { + ray = sweep->ray[j]; + printf("%d: %7.2f\n ",j,sweep->ray[j]->h.azimuth); + } + } + } + } + } +/* + Write out some volume statistics +*/ + if(verbose) { + printf("******************* Volume Statistics *******************\n"); + if(reflectivity) { + sweep = RSL_get_first_sweep_of_volume(dz_volume); + if(sweep != NULL) { + printf("Number rays = %d\n", sweep->h.nrays); + printf("Beam width = %.2f deg\n", sweep->h.beam_width); + ray = RSL_get_first_ray_of_sweep(sweep); + if(ray!= NULL) { + max_range = ray->h.range_bin1/1000.0 + + ray->h.nbins*ray->h.gate_size/1000.0; + printf("Number of bins = %d\n",ray->h.nbins); + printf("Max range = %.1f km\n", max_range); + printf("Range to first bin = %d m\n",ray->h.range_bin1); + printf("Gate size = %d m\n",ray->h.gate_size); + printf("Pulse Rep. Freq. = %d Hz\n",ray->h.prf); + printf("Pulse width = %.2f us\n",ray->h.pulse_width); + printf("Wavelength = %.2f m\n",ray->h.wavelength); + printf("Frequency = %.2f \n",ray->h.frequency); + } + } + } + } + +/* + Add a dBZ offset if requested. The offset can be positive or negative. + if(dbz_offset != 0.0) { + printf("Adding dbz_offset to dz_volume: %.2f\n", dbz_offset); + RSL_add_dbzoffset_to_volume(dz_volume, dbz_offset); + printf("Added dbz_offset to dz_volume: %.2f\n", dbz_offset); + exit(0); + } +*/ + +/* + **************************************************************** + * Make images * + **************************************************************** +*/ + + + /* CZ_INDEX */ + if(qc_reflectivity) { + if(verbose) printf("Loading refl colortable...\n"); + RSL_load_refl_color_table(); + for(i=0; isweep[i]; + if(sweep == NULL) { + printf("sweep[%d]==NULL\n",i); + continue; + } + if(make_pgm) { + sprintf(file_suffix,"pgm"); + sprintf(filename,"qc_%s_%2.2d.%s", time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_pgm(sweep, filename, xdim, ydim, maxr); + } + if(make_gif) { + sprintf(file_suffix,"gif"); + sprintf(filename,"qc_%s_%2.2d.%s", time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_gif(sweep,filename,xdim, ydim, maxr); + } + } + } + + /* DZ_INDEX */ + if(reflectivity) { + if(verbose) printf("Loading refl colortable...\n"); + RSL_load_refl_color_table(); + for(i=0; isweep[i]; + if(sweep == NULL) { + printf("sweep[%d]==NULL\n",i); + continue; + } + if(make_pgm) { + sprintf(file_suffix,"pgm"); + sprintf(filename,"dz_%s_%2.2d.%s", + time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_pgm(sweep, filename, xdim, ydim, maxr); + } + if(make_gif) { + sprintf(file_suffix,"gif"); + sprintf(filename,"dz_%s_%2.2d.%s", time_string,i,file_suffix); +/* + sprintf(filename,"dz_%s.%s.%s", time_string,in_file,file_suffix); +*/ + printf("Creating: %s\n", filename); + RSL_sweep_to_gif(sweep,filename,xdim, ydim, maxr); + } + } + } + + /* ZT_INDEX */ + if(total_reflectivity) { + if(verbose) printf("Loading refl colortable...\n"); + RSL_load_refl_color_table(); + for(i=0; isweep[i]; + if(sweep == NULL) { + printf("sweep[%d]==NULL\n",i); + continue; + } + if(make_pgm) { + sprintf(file_suffix,"pgm"); + sprintf(filename,"zt_%s_%2.2d.%s", + time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_pgm(sweep, filename, xdim, ydim, maxr); + } + if(make_gif) { + sprintf(file_suffix,"gif"); + sprintf(filename,"zt_%s_%2.2d.%s", + time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_gif(sweep,filename,xdim, ydim, maxr); + } + } + } + + /* DR_INDEX */ + if(differential_reflectivity) { + scale = 0.5; + ncbins = 21; + width = 10; + printf("Calling RSL_rebin, %d %d %.2f\n", width); + RSL_rebin_volume(dr_volume, width); + if(verbose) printf("Loading zdr colortable...\n"); + RSL_load_zdr_color_table(); + for(i=0; isweep[i]; + if(sweep == NULL) { + printf("sweep[%d]==NULL\n",i); + continue; + } + if(make_pgm) { + sprintf(file_suffix,"pgm"); + sprintf(filename,"dr_%s_%2.2d.%s", + time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_pgm(sweep, filename, xdim, ydim, maxr); + } + if(make_gif) { + sprintf(file_suffix,"gif"); + sprintf(filename,"dr_%s_%2.2d.%s", + time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_gif(sweep,filename,xdim, ydim, maxr); + } + } + } + + + /* VR_INDEX */ + if(velocity) { + if(verbose) printf("Loading vel colortable...\n"); + RSL_load_vel_color_table(); + for(i=0; isweep[i]; + if(sweep == NULL) { + printf("sweep[%d]==NULL\n",i); + continue; + } + if(make_pgm) { + sprintf(file_suffix,"pgm"); + sprintf(filename,"vr_%s_%2.2d.%s", time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_pgm(sweep, filename, xdim, ydim, maxr); + } + if(make_gif) { + sprintf(file_suffix,"gif"); + sprintf(filename,"vr_%s_%2.2d.%s", time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_gif(sweep,filename,xdim, ydim, maxr); + } + } + } + + /* SW_INDEX */ + if(spectral_width) { + if(verbose) printf("Loading sw colortable...\n"); + RSL_load_sw_color_table(); + for(i=0; isweep[i]; + if(sweep == NULL) { + printf("sweep[%d]==NULL\n",i); + continue; + } + if(make_pgm) { + sprintf(file_suffix,"pgm"); + sprintf(filename,"sw_%s_%2.2d.%s", + time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_pgm(sweep, filename, xdim, ydim, maxr); + } + if(make_gif) { + sprintf(file_suffix,"gif"); + sprintf(filename,"sw_%s_%2.2d.%s", + time_string,i,file_suffix); + printf("Creating: %s\n", filename); + RSL_sweep_to_gif(sweep,filename,xdim, ydim, maxr); + } + } + } + +/* + Write uf file if requested +*/ + if(make_uf) { + sprintf(file_suffix,"uf.gz"); + sprintf(filename,"%s_%s.%s",site_id, time_string,file_suffix); + printf("Creating UF file: %s\n", filename); + RSL_radar_to_uf_gzip(radar, filename); + } + + printf("-->> FIELDS: [ "); + if(radar->v[0] != NULL) printf("DZ "); + if(radar->v[1] != NULL) printf("VR "); + if(radar->v[2] != NULL) printf("SW "); + if(radar->v[3] != NULL) printf("CZ "); + if(radar->v[4] != NULL) printf("ZT "); + if(radar->v[5] != NULL) printf("DR "); + if(radar->v[6] != NULL) printf("LR "); + if(radar->v[7] != NULL) printf("ZD "); + if(radar->v[8] != NULL) printf("DM "); + if(radar->v[9] != NULL) printf("RH "); + if(radar->v[10] != NULL) printf("PH "); + if(radar->v[11] != NULL) printf("XZ "); + if(radar->v[12] != NULL) printf("CR "); + if(radar->v[13] != NULL) printf("MZ "); + if(radar->v[14] != NULL) printf("MR "); + if(radar->v[15] != NULL) printf("ZE "); + if(radar->v[16] != NULL) printf("VE "); + if(radar->v[17] != NULL) printf("KD "); + if(radar->v[18] != NULL) printf("TI "); + if(radar->v[19] != NULL) printf("DX "); + if(radar->v[20] != NULL) printf("CH "); + if(radar->v[21] != NULL) printf("AH "); + if(radar->v[22] != NULL) printf("CV "); + if(radar->v[23] != NULL) printf("AV "); + if(radar->v[24] != NULL) printf("SQ "); + printf("] \n\n"); +/* + Wrap it up! +*/ + + if(verbose) + printf("Finished!\n"); + exit (0); + +} /* End of main */ + diff --git a/examples/qlook_usage.c b/examples/qlook_usage.c new file mode 100644 index 0000000..80ca2e5 --- /dev/null +++ b/examples/qlook_usage.c @@ -0,0 +1,141 @@ +#define TRUE 1 +#define FALSE 0 + +#include +#include +#include +#include + +void process_args(int argc, char **argv, char *in_file, int *verbose, + char *site_id, char *tape_id, + int *qc_reflectivity, int *total_reflectivity, + int *differential_reflectivity, + int *velocity, int *spectral_width, + int *make_gif, int *make_pgm, int *make_bscan, int *make_uf, + int *num_sweeps, float *dbz_offset, + int *xdim, int *ydim, float *range, + float *gate_size_adjustment, int *print_azim) +{ + extern char *optarg; + extern int optind, optopt; + char c; + + while ((c = getopt(argc, argv, "vgpus:t:n:x:y:r:o:a:ADCQTWV")) != -1) { + + switch(c) { +/* + RSL Verbose flag +*/ + case 'v': *verbose = TRUE; break; + +/* + s: First file or call sign +*/ + case 's': strcpy(site_id, optarg); break; + case 't': strcpy(tape_id, optarg); break; + +/* + x: x dimension + y: y dimension + r: max range + z: zoom factor (km/pixel) +*/ + case 'x': *xdim = atoi(optarg); break; + case 'y': *ydim = atoi(optarg); break; + case 'r': *range = atof(optarg); break; + case 'a': *gate_size_adjustment = atof(optarg); break; + +/* dBZ Offset +*/ + case 'o': *dbz_offset = atof(optarg); break; +/* + T: Total reflectivity + Q: Do qc'd reflectivity + V: Do radial velocity + W: Do spectral width +*/ + case 'Q': *qc_reflectivity = TRUE; break; + case 'T': *total_reflectivity = TRUE; break; + case 'V': *velocity = TRUE; break; + case 'W': *spectral_width = TRUE; break; + case 'A': *print_azim = TRUE; break; + case 'D': *differential_reflectivity = TRUE; break; + +/* + g: Make gif images + p: Make pgm images + u: Make uf files +*/ + case 'g': *make_gif = TRUE; break; + case 'p': *make_pgm = TRUE; break; + case 'u': *make_uf = TRUE; break; + +/* + num_sweeps: Number of sweeps to make images of +*/ + case 'n': *num_sweeps = atoi(optarg); break; + +/* + Deal with bad input +*/ + case '?': fprintf(stderr, "ERROR: option -%c is undefined\n", optopt); + goto Usage; + case ':': fprintf(stderr, "ERROR: option -%c requires an argument\n",optopt); + goto Usage; + default: break; + } + } + +/* + Must have at the least a file listed on the command lines, everything + can be defaulted. + */ + + if (argc - optind != 1) { +Usage: + fprintf(stderr,"ERROR:::\n"); + fprintf(stderr,"%s [options] input_file:",argv[0]); + fprintf(stderr,"\n[options]: "); + fprintf(stderr,"\n\t[-v verbose_flag?] "); + fprintf(stderr,"\n\t[-s First file or call sign?] "); + fprintf(stderr,"\n\t[-t Tape ID] "); + fprintf(stderr,"\n\t[-u Make UF file]"); + fprintf(stderr,"\n\t[-g Make GIF images?]"); + fprintf(stderr,"\n\t[-p Make PGM images?]"); + fprintf(stderr,"\n\t[-x X dimension]"); + fprintf(stderr,"\n\t[-y Y dimension]"); + fprintf(stderr,"\n\t[-r max range]"); + fprintf(stderr,"\n\t[-n Number of sweeps to make images]"); + fprintf(stderr,"\n\t[-Q Do qc reflectivity]"); + fprintf(stderr,"\n\t[-T Do total reflectivity]"); + fprintf(stderr,"\n\t[-V Do velocity]"); + fprintf(stderr,"\n\t[-W Do spectral_width]"); + fprintf(stderr,"\n\t[-D Do differential reflectivity"); + fprintf(stderr,"\n\t[-o Apply dBZ offset"); + fprintf(stderr,":::\n"); + exit(-1); + } + + strcpy(in_file, argv[optind]); + +} + + + + + + + + + + + + + + + + + + + + diff --git a/examples/run_tests b/examples/run_tests new file mode 100755 index 0000000..76222b2 --- /dev/null +++ b/examples/run_tests @@ -0,0 +1,225 @@ +#!/usr/bin/perl +#-*-Perl-*- +# Pretty unsophisicated. + + +sub runit { + print "COMMAND @_\n"; + system("@_"); +} + +sub diffimage { +# Convert to ppm. GIF stores date in header! + local ($gif) = @_; + $ipath = '../../rsl_test_images'; + system("giftoppm $gif > img_junk1.ppm"); + system("giftoppm $ipath/$gif > img_junk2.ppm"); + $s = `diff -q img_junk1.ppm img_junk2.ppm`; + unlink(); + if ($s eq "") { + print "MATCH: $gif and $ipath/$gif are identical ... good.\n"; + } else { + print "-------- Files $gif and $ipath/$gif are different.\n"; + } +} + +&runit('any_to_gif -r200 /d8/merritt/l00038.ppi'); +&diffimage('radtec_DZ_051298_1429.gif'); +print "---------------------------------------------\n"; + + +&runit('any_to_gif -r 200 /d8/merritt/1C51.921002.13.MELB.1.HDF'); +#runit('xv MELB_DZ_100292_1205.gif'); +#runit('xv MELB_CZ_100292_1205.gif'); +&diffimage('MELB_DZ_100292_1205.gif'); +&diffimage('MELB_CZ_100292_1205.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif -r 200 /d8/merritt/19980127050001.vol'); +#runit('xv Berrima_ZT_012798_0500.gif'); +#runit('xv Berrima_VR_012798_0500.gif'); +#runit('xv Berrima_SW_012798_0500.gif'); +&diffimage('Berrima_ZT_012798_0500.gif'); +&diffimage('Berrima_VR_012798_0500.gif'); +&diffimage('Berrima_SW_012798_0500.gif'); +print "---------------------------------------------\n"; + +&runit('qlook -v -g -D -V /d8/merritt/Lassen_mp.vol'); +#runit('xv dz_951117_0730_00.gif'); +#runit('xv dr_951117_0730_00.gif'); +#runit('xv vr_951117_0730_00.gif'); +&diffimage('dz_951117_0730_00.gif'); +&diffimage('dr_951117_0730_00.gif'); +&diffimage('vr_951117_0730_00.gif'); +print "---------------------------------------------\n"; + +&runit('qlook -v -g -W -V /d8/merritt/nex.file.2'); +#runit('xv dz_930701_1957_00.gif'); +#runit('xv vr_930701_1957_00.gif'); +#runit('xv sw_930701_1957_00.gif'); +&diffimage('dz_930701_1957_00.gif'); +&diffimage('vr_930701_1957_00.gif'); +&diffimage('sw_930701_1957_00.gif'); +print "---------------------------------------------\n"; + +&runit('qlook -v -g -W -V /d8/merritt/nex.file.2.gz'); +#runit('xv vr_930701_1957_00.gif'); +&diffimage('dz_930701_1957_00.gif'); +&diffimage('sw_930701_1957_00.gif'); +&diffimage('vr_930701_1957_00.gif'); +print "---------------------------------------------\n"; + +&runit('cappi_image /d8/merritt/nex.file.2.gz KMLB'); +#runit('xv cappi_03.gif'); +&diffimage('cappi_01.gif'); +&diffimage('cappi_02.gif'); +&diffimage('cappi_03.gif'); +&diffimage('cappi_04.gif'); +&diffimage('cappi_05.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif /d8/merritt/nex.file.2.gz /d8/merritt/nex.file.1'); +#runit('xv KMLB_DZ_070193_1957.gif'); +#runit('xv KMLB_VR_070193_1957.gif'); +#runit('xv KMLB_SW_070193_1957.gif'); +&diffimage('KMLB_DZ_070193_1957.gif'); +&diffimage('KMLB_VR_070193_1957.gif'); +&diffimage('KMLB_SW_070193_1957.gif'); +print "---------------------------------------------\n"; + +#&runit('any_to_gif -r 150 /d8/merritt/34598DE1.vol.gz'); +#runit('xv Gunn_Pt_DZ_103197_0739.gif'); +#&diffimage('Gunn_Pt_DZ_103197_0739.gif'); +#&diffimage('Gunn_Pt_VR_103197_0739.gif'); +#&diffimage('Gunn_Pt_SW_103197_0739.gif'); +#&diffimage('Gunn_Pt_ZT_103197_0739.gif'); +#&diffimage('Gunn_Pt_ZD_103197_0739.gif'); +#&diffimage('Gunn_Pt_RH_103197_0739.gif'); +#&diffimage('Gunn_Pt_PH_103197_0739.gif'); +#print "---------------------------------------------\n"; + +&runit('any_to_gif -r 150 /d8/merritt/2D17FBB4.vol'); +#runit('xv Berrima_DZ_122293_0747.gif'); +&diffimage('Berrima_DZ_122293_0747.gif'); +&diffimage('Berrima_VR_122293_0747.gif'); +&diffimage('Berrima_SW_122293_0747.gif'); +&diffimage('Berrima_ZT_122293_0747.gif'); +&diffimage('Berrima_LR_122293_0747.gif'); +&diffimage('Berrima_RH_122293_0747.gif'); +&diffimage('Berrima_PH_122293_0747.gif'); +&diffimage('Berrima_KD_122293_0747.gif'); +&diffimage('Berrima_TI_122293_0747.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif -r 150 /d8/merritt/30BE3D11.vol.gz'); +#runit('xv Nguiu_DZ_113095_2319.gif'); +&diffimage('Nguiu_DZ_113095_2319.gif'); +&diffimage('Nguiu_VR_113095_2319.gif'); +&diffimage('Nguiu_SW_113095_2319.gif'); +&diffimage('Nguiu_ZT_113095_2319.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif -r 150 /d8/merritt/tog_930129_1731.raw'); +#runit('xv TOGA_DZ_012993_1731.gif'); +&diffimage('TOGA_DZ_012993_1731.gif'); +&diffimage('TOGA_VR_012993_1731.gif'); +&diffimage('TOGA_SW_012993_1731.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif -r 133 /d8/merritt/kwaj.new'); +#runit('xv KWAJ_DZ_021496_2351.gif'); +&diffimage('KWAJ_DZ_021496_2351.gif'); +&diffimage('KWAJ_VR_021496_2351.gif'); +&diffimage('KWAJ_SW_021496_2351.gif'); +&diffimage('KWAJ_ZT_021496_2351.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif -r 150 /d8/merritt/KWA980324084320.ARCPYLY'); +#runit('xanim KWAJ_??_032498_0843.gif'); +&diffimage('KWAJ_DZ_032498_0843.gif'); +&diffimage('KWAJ_VR_032498_0843.gif'); +&diffimage('KWAJ_SW_032498_0843.gif'); +&diffimage('KWAJ_ZT_032498_0843.gif'); +&diffimage('KWAJ_DR_032498_0843.gif'); +&diffimage('KWAJ_KD_032498_0843.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif -r 150 /d8/merritt/VIC.930129.213153.sig'); +#runit('xv MIT-CSU_DZ_012993_2131.gif'); +&diffimage('MIT-CSU_DZ_012993_2131.gif'); +&diffimage('MIT-CSU_VR_012993_2131.gif'); +&diffimage('MIT-CSU_SW_012993_2131.gif'); +&diffimage('MIT-CSU_ZT_012993_2131.gif'); +print "---------------------------------------------\n"; + +&runit('any_to_gif -r 150 /d8/merritt/VIC.930130.213215.sig.gz'); +#runit('xv MIT-CSU_DZ_013093_2132.gif'); +&diffimage('MIT-CSU_DZ_013093_2132.gif'); +&diffimage('MIT-CSU_VR_013093_2132.gif'); +&diffimage('MIT-CSU_SW_013093_2132.gif'); +&diffimage('MIT-CSU_ZT_013093_2132.gif'); +print "---------------------------------------------\n"; + +print "You will be placed in 'less'. Search for the string 'OUT' and\n"; +print "examine the angles. You should only see the 'OUT OF ORDER' message\n"; +print "when the angle changes from the maximum to the minimum.\n"; +&runit('killer_sweep /d8/merritt/nex.file.2.gz /d8/merritt/nex.file.1 | less'); +print "---------------------------------------------\n"; + +&runit('wsr88d_to_gif /d8/merritt/nex.file.2.gz /d8/merritt/nex.file.1'); +#runit('xanim dz_sweep.??.gif'); +#runit('xanim vr_sweep.??.gif'); +#runit('xanim sw_sweep.??.gif'); +&diffimage('dz_sweep.00.gif'); +&diffimage('dz_sweep.01.gif'); +&diffimage('dz_sweep.02.gif'); +&diffimage('dz_sweep.03.gif'); +&diffimage('dz_sweep.04.gif'); +&diffimage('dz_sweep.05.gif'); +&diffimage('dz_sweep.06.gif'); +&diffimage('dz_sweep.07.gif'); +&diffimage('dz_sweep.08.gif'); +&diffimage('dz_sweep.09.gif'); +&diffimage('dz_sweep.10.gif'); +&diffimage('vr_sweep.00.gif'); +&diffimage('vr_sweep.01.gif'); +&diffimage('vr_sweep.02.gif'); +&diffimage('vr_sweep.03.gif'); +&diffimage('vr_sweep.04.gif'); +&diffimage('vr_sweep.05.gif'); +&diffimage('vr_sweep.06.gif'); +&diffimage('vr_sweep.07.gif'); +&diffimage('vr_sweep.08.gif'); +&diffimage('vr_sweep.09.gif'); +&diffimage('vr_sweep.10.gif'); +&diffimage('sw_sweep.00.gif'); +&diffimage('sw_sweep.01.gif'); +&diffimage('sw_sweep.02.gif'); +&diffimage('sw_sweep.03.gif'); +&diffimage('sw_sweep.04.gif'); +&diffimage('sw_sweep.05.gif'); +&diffimage('sw_sweep.06.gif'); +&diffimage('sw_sweep.07.gif'); +&diffimage('sw_sweep.08.gif'); +&diffimage('sw_sweep.09.gif'); +&diffimage('sw_sweep.10.gif'); +print "---------------------------------------------\n"; + +&runit('wsr_hist_uf_test /d8/merritt/nex.file.2.gz'); +$s = `diff *.dat`; + if ($s != "") { + print "==> Unexpected differences. FAILED test.\n"; + } else { + print "==> No differences, good. PASSED test.\n"; + } + +##print "---------------------------------------------\n"; +##&runit('bscan /d8/merritt/pafb_swap'); +##system('mv bscan.00.ppm bscan.00.swap.ppm'); +##&runit('bscan /d8/merritt/pafb_unswap'); +##$s = `diff bscan.00.ppm bscan.00.swap.ppm`; +## if ($s != "") { +## print "==> Unexpected differences. FAILED test.\n"; +## } else { +## print "==> No differences, good. PASSED test.\n"; +## } diff --git a/examples/sector.c b/examples/sector.c new file mode 100644 index 0000000..f1655ce --- /dev/null +++ b/examples/sector.c @@ -0,0 +1,110 @@ +#include +#include "rsl.h" + +/* + * Cannot compile if the hash table is static in volume.c. For + * testing we make it globally known. + */ + +typedef struct { + Sweep *s_addr; + Hash_table *hash; +} Sweep_list; + +extern int RSL_max_sweeps; /* Initial allocation for sweep_list. + * RSL_new_sweep will allocate the space first + * time around. + */ +extern int RSL_nsweep_addr; /* A count of sweeps in the table. */ +extern Sweep_list *RSL_sweep_list; +extern int RSL_nextents; + + +void print_link_list(Azimuth_hash *list) +{ + if (list == NULL) { + printf("\n"); + return; + } + printf("ray# %d azim %f |", list->ray->h.ray_num, list->ray->h.azimuth); + print_link_list(list->next); +} + + +void print_hash_table (Sweep *s) +{ + int i; + int sweep_index; + Azimuth_hash *index; + float azim; + float res; + + if (s == NULL) return; + sweep_index = SWEEP_INDEX(s); + res = 360.0/RSL_sweep_list[sweep_index].hash->nindexes; + printf("Azimuth resolution = %f for %d bins.\n", res, RSL_sweep_list[sweep_index].hash->nindexes); + for (i=0; inindexes; i++) { + index = RSL_sweep_list[sweep_index].hash->indexes[i]; + azim = i/res; + printf("RSL_sweep_list[%d].hash->indexes[%d] = ", sweep_index, i); + + if (index == NULL) + printf("IS NULL\n"); + else + print_link_list(index); + } +} + +Sweep * get_sector(Sweep *s, float lo_azimuth, float hi_azimuth) +{ + int i, j; + Sweep *new_sweep; + Ray *saved_ray; + + if (s == NULL) return NULL; + + if ((new_sweep = RSL_new_sweep(s->h.nrays)) == NULL) + return NULL; + new_sweep->h = s->h; + + for (i = 0,j = 0; i < s->h.nrays; i++) { + if (s->ray[i] == NULL) continue; + if (s->ray[i]->h.azimuth >= lo_azimuth && + s->ray[i]->h.azimuth < hi_azimuth) { + + + new_sweep->ray[j] =RSL_copy_ray(s->ray[i]); + + j++; + } + } + + return new_sweep; + +} + + +void main(int argc, char **argv) +{ + Radar *radar; + Sweep *sector; + + if (argc != 3) {fprintf(stderr, "Usage: %s infile callid_or_firstfile\n", argv[0]); exit(-1);} + RSL_radar_verbose_on(); + radar = RSL_wsr88d_to_radar(argv[1], argv[2]); + if (radar == NULL) exit(-1); + + RSL_load_refl_color_table(); + + sector = get_sector(radar->v[DZ_INDEX]->sweep[0], 0.0, 90.0); + +/* sector = RSL_copy_sweep(radar->v[DZ_INDEX]->sweep[0]); +*/ + + print_hash_table(sector); + + RSL_sweep_to_gif(sector, "dz_sector.gif", 400, 400, 200.0); + + exit(0); + +} diff --git a/examples/test_get_win.c b/examples/test_get_win.c new file mode 100644 index 0000000..f01b8cc --- /dev/null +++ b/examples/test_get_win.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include + +#include "rsl.h" + +Sweep *load_sweep(Sweep *s) +{ + int i, j; + Ray *ray; + + if (!s) { + printf("sweep is NULL-can't load\n"); + return NULL; + } + + printf("loading sweep with %d rays\n", s->h.nrays); + for (i = 0; i < s->h.nrays; i++) { + ray = s->ray[i]; + /* set range */ + for (j = 0; j < ray->h.nbins; j++) { + + ray->range[j] = ray->h.invf(40.0); + } + } + + return s; +} + + +main (int argc, char **argv) +{ + + Radar *new_radar, *tmp_radar, *radar; + Sweep *s, *new_sweep; + float min_range, max_range, low_azim, hi_azim; + int j, i; + char type; + Volume *new_volume, *v; + +/* + RSL_radar_verbose_on(); +*/ + if (argc < 8) { + fprintf(stderr, "%s type(r|v|s) min_range max_range low_azim hi_azim ref_uf_file out_file\n", argv[0]); + exit(-1); + } + + i = 1; + type = argv[i++][0]; + min_range = (float) atoi(argv[i++]); + max_range = (float) atoi(argv[i++]); + low_azim = (float) atoi(argv[i++]); + hi_azim = (float) atoi(argv[i++]); + + radar = RSL_uf_to_radar(argv[i++]); + if (!radar) exit(-1); + + RSL_load_refl_color_table(); + + switch(type) { + case 'r': + case 'v': + v = RSL_copy_volume(radar->v[DZ_INDEX]); + if (!v) exit(-1); + if ((v = RSL_clear_volume(v)) == NULL) exit(-1); + + printf("volume's nsweeps - %d\n", v->h.nsweeps); + for (j = 0; j < v->h.nsweeps; j++) { + printf("loading sweep %d\n", j); + v->sweep[j] = load_sweep(v->sweep[j]); + + } + /* test get*from radar */ + if (type == 'r') { + if ((tmp_radar = RSL_new_radar(radar->h.nvolumes)) == NULL) exit (-1); + tmp_radar->h = radar->h; + tmp_radar->v[DZ_INDEX] = v; + new_radar = RSL_get_window_from_radar(tmp_radar,min_range, max_range, + low_azim, hi_azim); + if (new_radar == NULL) { + printf("null new radar\n"); + exit(-1); + } + RSL_volume_to_gif(new_radar->v[DZ_INDEX], argv[i], 500, 500, max_range); + RSL_free_radar(tmp_radar); + RSL_free_radar(new_radar); + } + else { + new_volume = RSL_get_window_from_volume(v, min_range, max_range, low_azim, + hi_azim); + if (new_volume != NULL) + RSL_volume_to_gif(new_volume, argv[i], 500, 500, max_range); +/* + RSL_bscan_volume(new_volume); +*/ + RSL_free_volume(new_volume); + } + break; + case 's': + s = RSL_copy_sweep(radar->v[DZ_INDEX]->sweep[0]); + s = RSL_clear_sweep(s); + s = load_sweep(s); + if (!s) { + printf("null sweep\n"); + exit(-1); + } + new_sweep = RSL_get_window_from_sweep(s, min_range, max_range, + low_azim, hi_azim ); + + RSL_sweep_to_gif(new_sweep, argv[i], 500, 500, max_range); +/* + RSL_bscan_sweep(new_sweep); +*/ + RSL_free_sweep(new_sweep); + + break; + default: + break; + } + RSL_free_radar(radar); + printf("done\n"); + exit (0); + +} + diff --git a/examples/wsr88d_to_gif.c b/examples/wsr88d_to_gif.c new file mode 100644 index 0000000..08969eb --- /dev/null +++ b/examples/wsr88d_to_gif.c @@ -0,0 +1,59 @@ +/* + * Ingest NEXRAD (wsr88d) data and output 3 gif images representing + * Reflectivity, Velocity and Spectrum width. + * + * This example is the most minimum of coding that you need to do + * to achieve good results from using the RSL code. + * + * This is short and sweet to demonstrate the simplicity of use for + * the RSL. + * + * CAN READ STDIN. + * + * wsr88d_to_gif < file + * wsr88d_to_gif file [tape_header_file] + */ + +#include "rsl.h" + +void main(int argc, char **argv) +{ + Radar *radar; + +/* + * Pass bitwise or of DZ_MASK, VR_MASK, SW_MASK + */ + RSL_radar_verbose_on(); /* Not needed; on a slow network it bides the time. */ + radar = RSL_wsr88d_to_radar(argv[1], argv[2]); + if (radar == NULL) exit(-1); + +/* RSL_sort_radar(radar); */ + +/***********************************************************************/ +/* */ +/* You now have a pointer to Radar. */ +/* Now use *radar all you like. */ +/* */ +/***********************************************************************/ + +/* Use radar->v[DZ_INDEX] for REFELECTIVITY + * radar->v[VR_INDEX] for VELOCITY + * radar->v[SW_INDEX] for SPECTRUM_WIDTH + */ + + RSL_load_refl_color_table(); + RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0); + + RSL_load_vel_color_table(); + RSL_rebin_velocity_volume(radar->v[VR_INDEX]); /* Modifies v[i]. */ + RSL_volume_to_gif(radar->v[VR_INDEX], "vr_sweep", 400, 400, 200.0); + + RSL_load_sw_color_table(); + RSL_volume_to_gif(radar->v[SW_INDEX], "sw_sweep", 400, 400, 200.0); + + exit(0); + +} + + + diff --git a/examples/wsr_hist_uf_test.c b/examples/wsr_hist_uf_test.c new file mode 100644 index 0000000..615b572 --- /dev/null +++ b/examples/wsr_hist_uf_test.c @@ -0,0 +1,86 @@ +/* + * Test reading and writing of UF files by using the histogram function. + * + * 1. Read WSR88D file. + * 2. Print histogram of DZ volume. + * 3. Output Radar to UF. + * 3. Free Radar structure. + * 4. Read UF into Radar. + * 5. Print histogram of DZ volume. + * + * The two outputted histograms should be identical. + * + */ + + + +#include +#ifdef sgi +#include +#endif +#include +#include + +#include "rsl.h" + + +usage() +{ + fprintf(stderr,"Usage: wsr_hist_uf_test infile\n"); + exit(-1); +} + +process_args(int argc, char **argv, char **in_file) +{ + if (argc == 2) *in_file = strdup(argv[1]); + else usage(); +} + + +main(int argc, char **argv) +{ + char *infile; + + Radar *radar; + Histogram *histogram = NULL; + + process_args(argc, argv, &infile); + RSL_radar_verbose_on(); + + if ((radar = RSL_anyformat_to_radar(infile, "KMLB")) == NULL) { + /* RSL_wsr88d_to_radar writes an error message to stdout. */ + exit(-1); + } + +/***********************************************************************/ +/* */ +/* You now have a pointer to Radar. */ +/* Now use *radar all you like. */ +/* */ +/***********************************************************************/ + +/* Use radar->v[DZ_INDEX] for REFELECTIVITY + * radar->v[VR_INDEX] for VELOCITY + * radar->v[SW_INDEX] for SPECTRUM_WIDTH + */ + printf("Radar date: %2.2d/%2.2d/%2.2d\n", radar->h.month, radar->h.day, radar->h.year); + printf("Radar time: %2.2d:%2.2d:%f\n", radar->h.hour, radar->h.minute, radar->h.sec); + + + RSL_radar_to_uf(radar, "uf_file.uf"); + histogram = RSL_get_histogram_from_volume(radar->v[DZ_INDEX], + histogram, -30, 70, 0, 200); + RSL_print_histogram(histogram, 0, 200, "hist_wsr88d_to_radar.dat"); + RSL_free_radar(radar); + + RSL_radar_verbose_on(); + printf("RSL_uf_to_radar\n"); + radar = RSL_uf_to_radar("uf_file.uf"); + histogram = NULL; /* There should be a free here. */ + histogram = RSL_get_histogram_from_volume(radar->v[DZ_INDEX], + histogram, -30, 70, 0, 200); + RSL_print_histogram(histogram, 0, 200, "hist_uf_to_radar.dat"); + + exit(0); + +} diff --git a/farea.c b/farea.c new file mode 100644 index 0000000..d3561dd --- /dev/null +++ b/farea.c @@ -0,0 +1,142 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include + +# define M_PI 3.14159265358979323846 + +#include "rsl.h" +/**********************************************************************/ +/* */ +/* RSL_area_of_ray */ +/* RSL_fractional_area_of_sweep */ +/* */ +/* Compute fractional area of a sweep given a range of dBZ and */ +/* a maximum range in km. */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ + +float get_pixel_area(Ray *r, float min_range, float max_range) +{ + float h1, h2, r1, r2; /* height and radius in km*/ + float volume; + float theta; /* in radian */ + + /* returns volume area of ray between min range and max range + */ + if (r == NULL) return 0.0; + + h1 = min_range; + h2 = max_range; + /* convert from degree to radian */ + theta = (r->h.beam_width/2) * 2 * M_PI / 360; + + r1 = h1 * tan(theta); + r2 = h2 * tan(theta); + volume = (M_PI/3) * (pow((double)r2, (double) 2) * h2 - pow((double) r1, (double) 2) *h1); + + return volume; +} /* get_pixel_area */ + + +float RSL_area_of_ray(Ray *r, float lo, float hi, float min_range, float max_range) +{ + int i; + float start_km; + float xdBZ; + float r1, r2, area; + int nbins, bin1; + float binsize; + + if (r == NULL) return 0.0; + /* Check if min_range is closer to the radar than the first bin. + * If so, we can't use it. + */ + + if (hi <= 0.0) + hi = 100.0; /* default to max dbz*/ + start_km = r->h.range_bin1/1000.0; + binsize = r->h.gate_size/1000.0; + + nbins = ((max_range - start_km) / binsize); + bin1 = (min_range - start_km) / binsize; + + if (bin1 < 0) bin1 = 0; + if (nbins > r->h.nbins) nbins = r->h.nbins; + + /* Compute the number of pixels with lo < dBZ <= hi */ + area = 0.0; + + for(i=bin1; ih.f(r->range[i]); + if(lo < xdBZ && xdBZ <= hi) { /*MAX_DBZ = hi (typically 70?) */ + /* get r1 and r2 in km */ + r1 = i * binsize + start_km; + r2 = (i+1) * binsize + start_km; + area += get_pixel_area(r, r1, r2); + } + r1 = i * binsize + start_km; + } + + return area; +} + + + +float RSL_fractional_area_of_sweep(Sweep *s, float lo, float hi, float min_rng, float max_rng) +{ +/* + * Compute the fractional area of the Sweep. + * + * This doesn't take care of a sector (window). The caller will + * have to multiply the answer by some appropriate constant. + * + */ + + + float sweep_area; + float area; + float frac_area; + float total_sys_area=0.0; + int iazm; + + if (s == NULL) return 0.0; + + sweep_area = 0; + for (iazm=0; iazmh.nrays; iazm++) { + /* get total system volume area */ + total_sys_area += RSL_area_of_ray(s->ray[iazm], -71, 0.0, min_rng, max_rng); + area = RSL_area_of_ray(s->ray[iazm], lo, hi, min_rng, max_rng); + sweep_area += area; +/* + fprintf(stderr,"iazm = %d, totalsysarea = %f, area = %f, sweep_area = %f\n", + iazm, total_sys_area, area, sweep_area); +*/ + } + frac_area = sweep_area / total_sys_area; + return (float) frac_area; +} + diff --git a/fix_headers.c b/fix_headers.c new file mode 100644 index 0000000..8a22a2f --- /dev/null +++ b/fix_headers.c @@ -0,0 +1,131 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * Fix header fields in ray headers. + * + * This routine is initially written to support 1C-51. + * It has been noticed that several radar files contain bad header + * information. Herein, we correct it by simple linear interpolation. + * + * By: John Merritt + * Space Applications Corporation + * Copyright 7/16/96 + * + */ + +#include +#include "rsl.h" + +Ray *RSL_fix_ray_header(Ray *ray) +{ + return ray; +} + +Sweep *RSL_fix_sweep_header(Sweep *sweep) +{ + int i; + int nfixed = 0; + int needed_to_fix = 0; + Ray *ray; + + if (sweep == NULL) return sweep; + + for (i=0; ih.nrays; i++) { + /* Here, we check and use more than one ray. */ + ray = sweep->ray[i]; + + if (ray == NULL) continue; + if (ray->h.month < 1 || ray->h.month > 12) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.month = %d\n", i, ray->h.month); + } + if (ray->h.day < 1 || ray->h.day > 31) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.day = %d\n", i, ray->h.day); + } + if (ray->h.year < 1980 || ray->h.year > 2020) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.year = %d\n", i, ray->h.year); + } + if (ray->h.hour < 0 || ray->h.hour > 23) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.hour = %d\n", i, ray->h.hour); + } + if (ray->h.minute < 0 || ray->h.minute > 59) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.minute= %d\n", i, ray->h.minute); + } + if (ray->h.sec < 0 || ray->h.sec > 59) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.sec = %f\n", i, ray->h.sec); + } + if (ray->h.elev < 0 || ray->h.elev > 90) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.elev = %f\n", i, ray->h.elev); + } + if (ray->h.range_bin1 < 0 || ray->h.range_bin1 > 150000) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.range_bin1 = %d\n", i, ray->h.range_bin1); + } + if (ray->h.gate_size < 0 || ray->h.gate_size > 100000) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.gate_size = %d\n", i, ray->h.gate_size); + } + if (ray->h.beam_width <= 0 || ray->h.beam_width > 10) { + needed_to_fix = 1; + fprintf(stderr, "ray[%3.3d]->h.beam_width = %f\n", i, ray->h.beam_width); + } + if (needed_to_fix) { + needed_to_fix = 0; + nfixed++; + } + } + + fprintf(stderr, "Repaired %d rays in this sweep.\n", nfixed); + + return sweep; +} + +Volume *RSL_fix_volume_header(Volume *v) +{ + int i; + if (v == NULL) return v; + + for (i=0; ih.nsweeps; i++) + RSL_fix_sweep_header(v->sweep[i]); + + return v; +} + +Radar *RSL_fix_radar_header(Radar *radar) +{ + int i; + if (radar == NULL) return radar; + + for (i=0; ih.nvolumes; i++) + RSL_fix_volume_header(radar->v[i]); + + return radar; +} + + diff --git a/fraction.c b/fraction.c new file mode 100644 index 0000000..978f922 --- /dev/null +++ b/fraction.c @@ -0,0 +1,131 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/**********************************************************************/ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* June 12, 1994 */ +/**********************************************************************/ + + +#include +#include "rsl.h" + +/**********************************************************************/ +/* */ +/* RSL_fraction_of_ray */ +/* RSL_fraction_of_sweep */ +/* RSL_fraction_of_volume */ +/* */ +/* Compute fraction of dBz within a specified range. */ +/* Loops are unrolled in each higher function because we are */ +/* computing fractiion. I thought about a returning a Ratio */ +/* structure, but dismissed it. */ +/* */ +/**********************************************************************/ +typedef struct { + int n; + int ntotal; +} Frac_ratio; + + +Frac_ratio RSL_ratio_of_ray(Ray *r, float lo, float hi, float range) +{ + int i; + int ibin_range; /* Maximum bin include, based on range. */ + Frac_ratio fr; + + fr.n = fr.ntotal = 0; + + if (r == NULL) return fr; + fr.n = 0; + ibin_range = range /( (float)r->h.gate_size / 1000.0 ); + if (ibin_range > r->h.nbins) ibin_range = r->h.nbins; + for (i=0; ih.f(r->range[i]) && r->h.f(r->range[i]) <= hi) fr.n++; + fr.ntotal++; + } + return fr; +} + +float RSL_fraction_of_ray(Ray *r, float lo, float hi, float range) +{ + Frac_ratio fr; + + fr = RSL_ratio_of_ray(r, lo, hi, range); + return (float)fr.n / (float)fr.ntotal; +} + + +Frac_ratio RSL_ratio_of_sweep(Sweep *s, float lo, float hi, float range) +{ + Frac_ratio total_ratio; + Frac_ratio ray_ratio; + int i; + + total_ratio.n = total_ratio.ntotal = 0; + if (s == NULL) return total_ratio; + for (i = 0; ih.nrays; i++) { + ray_ratio = RSL_ratio_of_ray(s->ray[i], lo, hi, range); + total_ratio.n += ray_ratio.n; + total_ratio.ntotal += ray_ratio.ntotal; + } + return total_ratio; +} + + +float RSL_fraction_of_sweep(Sweep *s, float lo, float hi, float range) +{ + Frac_ratio fr; + + fr = RSL_ratio_of_sweep(s, lo, hi, range); + return (float)fr.n / (float)fr.ntotal; +} + + + +Frac_ratio RSL_ratio_of_volume(Volume *v, float lo, float hi, float range) +{ + Frac_ratio total_ratio; + Frac_ratio sweep_ratio; + int i; + + total_ratio.n = total_ratio.ntotal = 0; + if (v == NULL) return total_ratio; + for (i = 0; ih.nsweeps; i++) { + sweep_ratio = RSL_ratio_of_sweep(v->sweep[i], lo, hi, range); + total_ratio.n += sweep_ratio.n; + total_ratio.ntotal += sweep_ratio.ntotal; + } + return total_ratio; +} + + +float RSL_fraction_of_volume(Volume *v, float lo, float hi, float range) +{ + Frac_ratio fr; + + fr = RSL_ratio_of_volume(v, lo, hi, range); + return (float)fr.n / (float)fr.ntotal; +} + + diff --git a/get_win.c b/get_win.c new file mode 100644 index 0000000..765b4d9 --- /dev/null +++ b/get_win.c @@ -0,0 +1,204 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996 Thuy Nguyen of International Database Systems + a NASA/GSFC on-site contractor. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "rsl.h" + +extern int radar_verbose_flag; + + +/*************************************************************************** + * RSL_get_window_from_radar + * RSL_get_window_from_volume + * RSL_get_window_from_sweep + * RSL_get_window_from_ray + * + * These routines get window (area) defined by minimum range, maximum range, + * low azimuth, and hi azimuth. + * + * By: Thuy Nguyen + * International Database Systems + * + y***************************************************************************/ + +Radar *RSL_get_window_from_radar(Radar *r, float min_range, float max_range, + float low_azim, float hi_azim) +{ + int i; + Radar *new_radar; + + if (min_range > max_range || min_range < 0 || max_range < 0){ + if (radar_verbose_flag) + fprintf(stderr,"Get win from radar: given invalid min range (%f) or max range (%f)\n", + min_range, max_range); + return NULL; + } + if (!r) return NULL; + + if ((new_radar = RSL_new_radar(r->h.nvolumes)) == NULL) return NULL; + new_radar->h = r->h; + + for (i = 0; i < r->h.nvolumes; i++) { + if (radar_verbose_flag) + fprintf(stderr,"Getting window from volume for v[%d] out of %d volumes\n", + i,r->h.nvolumes ); + + new_radar->v[i] = RSL_get_window_from_volume(r->v[i], min_range, max_range, + low_azim, hi_azim); + } + return new_radar; +} + + +Volume *RSL_get_window_from_volume(Volume *v, float min_range, float max_range, + float low_azim, float hi_azim) +{ + int i; + Volume *new_volume; + Sweep *new_sweep; + + if (min_range > max_range || min_range < 0 || max_range < 0){ + if (radar_verbose_flag) + fprintf(stderr,"Get win from volume: given invalid min range (%f) or max range (%f)\n", + min_range, max_range); + return NULL; + } + if (!v) return NULL; + + if ((new_volume = RSL_new_volume(v->h.nsweeps)) == NULL) return NULL; + new_volume->h = v->h; + + for (i = 0; i < v->h.nsweeps; i++) { + if (radar_verbose_flag) + fprintf(stderr,"Getting window from sweep for s[%d] out of %d sweeps\n", + i,v->h.nsweeps); + + new_sweep = RSL_get_window_from_sweep(v->sweep[i], min_range, max_range, + low_azim, hi_azim); + new_volume->sweep[i] = new_sweep; + } + + if (radar_verbose_flag) + fprintf(stderr,"Got win from volume: orig volume has %d sweeps, new " + "volume has %d sweeps\n",v->h.nsweeps,new_volume->h.nsweeps); + + return new_volume; +} + +Sweep *RSL_get_window_from_sweep(Sweep *s, float min_range, float max_range, + float low_azim, float hi_azim) +{ + int i; + Sweep *new_sweep; + Ray *new_ray; + + if (min_range > max_range || min_range < 0 || max_range < 0){ + if (radar_verbose_flag) + fprintf(stderr,"Get win from sweep: given invalid min range (%f) or max range (%f)\n", + min_range, max_range); + return NULL; + } + if (s == NULL) return NULL; + + if ((new_sweep = RSL_new_sweep(s->h.nrays)) == NULL) + return NULL; + + new_sweep->h = s->h; + + for (i = 0; i < s->h.nrays; i++) { + new_ray = RSL_get_window_from_ray(s->ray[i], min_range, max_range, + low_azim, hi_azim); + new_sweep->ray[i] = new_ray; + + } + + + if (radar_verbose_flag) + fprintf(stderr,"Got win from sweep: orig sweep has %d rays, new sweep " + "has %d rays.\n",s->h.nrays,new_sweep->h.nrays); + + return new_sweep; +} + + +Ray *RSL_get_window_from_ray(Ray *r, float min_range, float max_range, + float low_azim, float hi_azim) +{ + float start_km, binsize; + int start_index, end_index; + Ray *new_ray; + int i; + + if (min_range > max_range || min_range < 0 || max_range < 0){ + if (radar_verbose_flag) + fprintf(stderr,"Get win from ray: given invalid min range (%f) or max range (%f)\n", + min_range, max_range); + return NULL; + } + + if (r == NULL || r->h.azimuth < low_azim || r->h.azimuth >= hi_azim) + return NULL; + + /* convert from meter to km */ + start_km = r->h.range_bin1/1000.0; + binsize = r->h.gate_size/1000.0; + + end_index = (int) ( (max_range - start_km) / binsize) + 1; + if (end_index > r->h.nbins) + end_index = r->h.nbins; + + if (min_range == 0.0) + start_index = 0; + else + start_index = (int) ( (min_range - start_km) / binsize); + + + if ((new_ray = RSL_copy_ray(r)) == NULL) return NULL; + if ((new_ray = RSL_clear_ray(new_ray)) == NULL) return NULL; + + + for (i = start_index; i < end_index; i++) { + new_ray->range[i] = r->range[i]; + } + return new_ray; +} + + + + + + + + + + + + + + + + + + + diff --git a/gts.c b/gts.c new file mode 100644 index 0000000..87861e6 --- /dev/null +++ b/gts.c @@ -0,0 +1,111 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + David B. Wolff + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "rsl.h" +/* + * Author: David B. Wolff + * Date: 8/4/94 + */ +/************************************************************************** + Ideally this would be done via a CAPPI, but could also be done via + the PPI. Here we will send a volume to produce a CAPPI. From the CAPPI(Z) + we compute the CAPPI(R) given a Z-R relationship. Then convert that to + a cartesian array for imaging or later fiddling. + + NOTE: + In keep with the object oriented approach to the library, the following + approach is used to deal with the Z-R conversion: + + Four functions are produced: RSL_volume_Z_to_R, RSL_sweep_Z_to_R, + RSL_ray_Z_to_r, z_to_r. RSL_volume_Z_to_R call RSL_sweep_Z_to_R for each + sweep, RSL_sweep_Z_to_R calls RSL__ray_Z_to_R for each ray, RSL__ray_Z_to_R + calls z_to_r for each range bin. + +***************************************************************************/ + +Volume *RSL_volume_z_to_r(Volume *z_volume, float k, float a); +Sweep *RSL_sweep_z_to_r(Sweep *z_sweep, float k, float a); +Ray *RSL_ray_z_to_r(Ray *z_ray, float k, float a); +float RSL_z_to_r(float z, float k, float a); + + +Volume *RSL_volume_z_to_r(Volume *z_volume, float k, float a) +{ + Volume *r_volume; + int i; + if(z_volume == NULL) return NULL; + r_volume = RSL_new_volume(z_volume->h.nsweeps); + r_volume->h = z_volume->h; + for(i=0; ih.nsweeps; i++) { + r_volume->sweep[i] = RSL_sweep_z_to_r(z_volume->sweep[i], k, a); + } + return r_volume; +} + +Sweep *RSL_sweep_z_to_r(Sweep *z_sweep, float k, float a) +{ + Sweep *r_sweep; + int i; + if(z_sweep == NULL) return NULL; + r_sweep = RSL_new_sweep(z_sweep->h.nrays); + r_sweep->h = z_sweep->h; + for(i=0; ih.nrays; i++) { + r_sweep->ray[i] = RSL_ray_z_to_r(z_sweep->ray[i], k, a); + } + return r_sweep; +} + +Ray *RSL_ray_z_to_r(Ray *z_ray, float k, float a) +{ + Ray *r_ray; + int i; + Range (*invf)(float x); + float (*f)(Range x); + + if (z_ray == NULL) return NULL; + r_ray = RSL_new_ray(z_ray->h.nbins); + r_ray->h = z_ray->h; + f = r_ray->h.f; + invf = r_ray->h.invf; + for(i=0; ih.nbins; i++) { + r_ray->range[i] = invf(RSL_z_to_r( f(z_ray->range[i]), k, a)); + } + return r_ray; + +} + +#include + +float RSL_z_to_r(float dbz, float k, float a) { + + float dbr, dbk, r; + + if (dbz >= NOECHO) return dbz; /* Be careful, NOECHO is the smallest, + so far, of the reserved numbers. */ + + dbk = (float)10*log10((double)k); + dbr = 1./a*(dbz- dbk); + r = (float)pow((double)10., (double)(dbr/10.) ); +/* fprintf(stderr,"dbz=%.1f; \tdbr=%.1f \tRate= %.3f\n",dbz,dbr,r); */ + return r; +} + diff --git a/gzip.c b/gzip.c new file mode 100644 index 0000000..09d0198 --- /dev/null +++ b/gzip.c @@ -0,0 +1,109 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include +#include +#define _USE_BSD +#include +#include +#include +#include + +/* Prototype definitions within this file. */ +int no_command (char *cmd); +FILE *uncompress_pipe (FILE *fp); +FILE *compress_pipe (FILE *fp); + + +/* Avoids the 'Broken pipe' message by reading the rest of the stream. */ +void rsl_readflush(FILE *fp) +{ + if (fork() == 0) { /* Child */ + char buf[1024]; + while(fread(buf, sizeof(char), sizeof(buf), fp)) continue; + exit(0); + } +} + +int rsl_pclose(FILE *fp) +{ + int rc; + if ((rc=pclose(fp)) == EOF) { + perror ("pclose"); /* This or fclose do the job. */ + if ((rc=fclose(fp)) == EOF) + perror ("fclose"); /* This or fclose do the job. */ + } + return rc; +} + +int no_command (char *cmd) +{ + int rc; + /* Return 0 if there is the command 'cmd' on the system. */ + /* Return !0 otherwise. */ + rc = system(cmd); + if (rc == 0) return rc; + else return !0; +} + +FILE *uncompress_pipe (FILE *fp) +{ + /* Pass the file pointed to by 'fp' through the gzip pipe. */ + + FILE *fpipe; + int save_fd; + + if (no_command("gzip --version > /dev/null 2>&1")) return fp; + save_fd = dup(0); + close(0); /* Redirect stdin for gzip. */ + dup(fileno(fp)); + + fpipe = popen("gzip -q -d -f --stdout", "r"); + if (fpipe == NULL) perror("uncompress_pipe"); + close(0); + dup(save_fd); + return fpipe; +} + +FILE *compress_pipe (FILE *fp) +{ + /* Pass the file pointed to by 'fp' through the gzip pipe. */ + + FILE *fpipe; + int save_fd; + + if (no_command("gzip --version > /dev/null 2>&1")) return fp; + fflush(NULL); /* Flush all buffered output before opening this pipe. */ + save_fd = dup(1); + close(1); /* Redirect stdout for gzip. */ + dup(fileno(fp)); + + fpipe = popen("gzip -q -1 -c", "w"); + if (fpipe == NULL) perror("compress_pipe"); + close(1); + dup(save_fd); + return fpipe; +} + + diff --git a/hdf_to_radar.c b/hdf_to_radar.c new file mode 100644 index 0000000..e6e5dd8 --- /dev/null +++ b/hdf_to_radar.c @@ -0,0 +1,966 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBTSDISTK +/****************************************************************** + Reads one volume scan from a HDF file into a RSL radar structure. + + ----------------------------------------------------------------- + Libraries required for execution of this code : + -ltsdistk : tsdis toolkit + -lmfhdf -ldf -ljpeg -lz : HDF + -lrsl : rsl + -lm : C math + + ----------------------------------------------------------------- +*******************************************************************/ + + +#include +#include +#include +#include +#include +#include +/* TSDIS toolkit function and structure definitions. */ +#include "IO.h" +#include "IO_GV.h" +/* RSL function and structure definitions. */ +#include "rsl.h" +/* Parameter definitions for 1B-51 and 1C-51 HDF + file handling applications using the TSDIS toolkit. */ +#include "toolkit_1BC-51_appl.h" + +#define MISSING_VAL 0 + + +/*************************************************************/ +/* */ +/* Function Prototypes */ +/* */ +/*************************************************************/ +void RayFillFrom1B51(Ray *ray, int16 *rayData, PARAMETER_DESCRIPTOR *parmDesc); +void RayFillFrom1C51(Ray *ray, int vindex, int16 *rayData, int8 *rayMaskData, + PARAMETER_DESCRIPTOR *parmDesc, float calibr); +static void Ray_headerFill(Ray *ray, L1B_1C_GV *gvl1, VosSize *vs, + int pindex, int tk_sindex, int rindex); +Ray *RayBuild(L1B_1C_GV *gvl1, VosSize *vs, float calibr, + int vindex, int pindex, int sindex, int rindex); +static void Sweep_headerFill(Sweep *sweep, SENSORS *sensor, int sindex, int nrays); +Sweep *SweepBuild(L1B_1C_GV *gvl1, VosSize *vs, float calibr, + int vindex, int pindex, int sindex); +static void Volume_headerFill(Volume *volume, char *parmDesc, int vindex, + int nsweeps, float calibr); +Volume *VolumeBuild(L1B_1C_GV *gvl1, VosSize *vs, float calibr, + int vindex, int pindex); +int parmIdentify(char *parmName); +static void Radar_headerFill(Radar *radar, L1B_1C_GV *gvl1); +Radar *RadarBuild(L1B_1C_GV *gvl1, VosSize *vs, float zCal); +int commentsRead(VosSize *vs, float *zCal, char *comments, int productID); +static L1B_1C_GV *GVL1Build(IO_HANDLE *granuleHandle, int vosNum, + VosSize *vs); +int metaDataRead(Radar *radar, IO_HANDLE *granuleHandle); +static int hdfFileOpen(char *infile, IO_HANDLE *granuleHandle, + char *hdfFileName, int *vosNum); +Radar *RSL_hdf_to_radar(char *infile); + + +/* Toolkit memory management functions. */ +extern void TKfreeGVL1(L1B_1C_GV *gvl1); +extern int8 ***TKnewParmData1byte(int nsweep, int nray, int ncell); +extern int16 ***TKnewParmData2byte(int nsweep, int nray, int ncell); +extern PARAMETER *TKnewGVL1parm(void); +extern L1B_1C_GV *TKnewGVL1(void); + + +static float (*f)(Range x); +static Range (*invf)(float x); + +extern int radar_verbose_flag; + + +static void ymd(int jday, int yy, int *mm, int *dd); + +static int daytab[2][13] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} +}; + +static void ymd(int jday, int year, int *mm, int *dd) +{ + /* Input: jday, yyyy */ + /* Output: mm, dd */ + int leap; + int i; + + leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; + for (i=0; daytab[leap][i]h.nbins; j++) + { + if (rayData[j] <= AP_VALUE) /* Handle anomalous condition flags. */ + { + if (rayData[j] == NO_VALUE) ray->range[j] = invf((float)BADVAL); + else if (rayData[j] == RNG_AMBIG_VALUE) ray->range[j] = invf((float)RFVAL); + else if (rayData[j] == NOECHO_VALUE) ray->range[j] = invf((float)NOECHO); + else ray->range[j] = invf((float)APFLAG); + } + else /* Valid data value */ + { + ray->range[j] = invf( (rayData[j] - parmDesc->offsetFactor) / + parmDesc->scaleFactor ); + } + } /* end for (j=0... */ +} + +/*************************************************************/ +/* */ +/* RayFillFrom1C51 */ +/* */ +/*************************************************************/ +void RayFillFrom1C51(Ray *ray, int vindex, int16 *rayData, int8 *rayMaskData, + PARAMETER_DESCRIPTOR *parmDesc, float calibr) +{ +/* + Fill the RSL bin slots of one ray of a CZ or a DZ volume using the + corresponding ray data and ray_mask data from a 1C-51 HDF file. +*/ + int j; + + for (j=0; jh.nbins; j++) + { + if (rayData[j] <= AP_VALUE) /* Handle anomalous condition flags. */ + { + if (rayData[j] == NO_VALUE) ray->range[j] = invf((float)BADVAL); + else if (rayData[j] == RNG_AMBIG_VALUE) ray->range[j] = invf((float)RFVAL); + else if (rayData[j] == NOECHO_VALUE) ray->range[j] = invf((float)NOECHO); + else ray->range[j] = invf((float)APFLAG); + } + else /* Valid data value */ + { + if ((vindex == CZ_INDEX) || (vindex == CD_INDEX)) + { + if (rayMaskData[j] == 1) + ray->range[j] = invf((float)BADVAL); + else + ray->range[j] = invf( (rayData[j] - parmDesc->offsetFactor) / + parmDesc->scaleFactor ); + } /* end if (vindex == CZ_INDEX) */ + else if (vindex == DZ_INDEX) + { + ray->range[j] = invf( + ((rayData[j] - parmDesc->offsetFactor) / parmDesc->scaleFactor) - + calibr + X * rayMaskData[j] ); + + } /* end else if DZ_INDEX */ + else if (vindex == ZD_INDEX) + { + ray->range[j] = invf( + ((rayData[j] - parmDesc->offsetFactor) / parmDesc->scaleFactor) + + X * rayMaskData[j] ); + } /* end else if ZD_INDEX */ + else + fprintf(stderr, "RayFillFrom1C51(): Illegal volume index..\n"); + } /* else valid data value */ + } /* end for (j=0; ... */ +} + +/*************************************************************/ +/* */ +/* Ray_headerFill */ +/* */ +/*************************************************************/ +void Ray_headerFill(Ray *ray, L1B_1C_GV *gvl1, VosSize *vs, + int pindex, int tk_sindex, int rindex) +{ + ray->h.year = (int)gvl1->volDes.year; + /* Get calendar date (month, day) from (year, Julian day) */ + ymd((int)gvl1->sensor.rayInfoInteger[tk_sindex][rindex][1], + ray->h.year, &ray->h.month, &ray->h.day); + ray->h.hour = (int)gvl1->sensor.rayInfoInteger[tk_sindex][rindex][2]; + ray->h.minute = (int)gvl1->sensor.rayInfoInteger[tk_sindex][rindex][3]; + ray->h.sec = (float)(gvl1->sensor.rayInfoInteger[tk_sindex][rindex][4] + + gvl1->sensor.rayInfoInteger[tk_sindex][rindex][5]/1000.0); + + ray->h.azimuth = gvl1->sensor.rayInfoFloat[tk_sindex][rindex][0]; + ray->h.ray_num = rindex + 1; + ray->h.elev = gvl1->sensor.rayInfoFloat[tk_sindex][rindex][1]; /* degrees */ + ray->h.elev_num = tk_sindex + 1; + ray->h.gate_size = (int) + (gvl1->sensor.parm[pindex]->cellRangeVector.distanceToCell[2] - + gvl1->sensor.parm[pindex]->cellRangeVector.distanceToCell[1]); /*meters*/ + + ray->h.range_bin1 = (int) + (gvl1->sensor.parm[pindex]->cellRangeVector.distanceToCell[0] - + 0.5 * ray->h.gate_size); /* meters */ + + ray->h.vel_res = MISSING_VAL; /* ?? */ + /* Sweeps/min */ + ray->h.sweep_rate = (float)(gvl1->sensor.radarDesc.nomScanRate / 6.0); + ray->h.prf = (int)gvl1->sensor.rayInfoFloat[tk_sindex][rindex][3]; + ray->h.azim_rate = (float)gvl1->sensor.radarDesc.nomScanRate; + ray->h.fix_angle = (float)gvl1->sensor.sweepInfo[tk_sindex].fixedAngle; + ray->h.pulse_count = (int)gvl1->sensor.rayInfoFloat[tk_sindex][rindex][2]; + /* Pulse width (microsec) */ + ray->h.pulse_width = (float)(gvl1->sensor.parm[pindex]->parmDesc.pulseWidth / + 300.0); + ray->h.beam_width = (float)gvl1->sensor.radarDesc.horBeamWidth; + /* Carrier freq (GHz) */ + ray->h.frequency = (float)gvl1->sensor.radarDesc.frequency1; + /* wavelength (m) */ + if (ray->h.frequency != 0.0) + ray->h.wavelength = (RSL_SPEED_OF_LIGHT / ray->h.frequency) * 1.0e-9; + else + ray->h.wavelength = 0.0; + ray->h.nyq_vel = (float) (ray->h.prf * ray->h.wavelength / 4.0); + if (ray->h.prf != 0) + ray->h.unam_rng = (float) RSL_SPEED_OF_LIGHT / (2.0 * ray->h.prf * 1000.0); + else + ray->h.unam_rng = (float) 0.0; + ray->h.nbins = vs->tk.ncell[tk_sindex][pindex]; + ray->h.f = f; + ray->h.invf = invf; +} + +/*************************************************************/ +/* */ +/* RayBuild */ +/* */ +/*************************************************************/ +Ray *RayBuild(L1B_1C_GV *gvl1, VosSize *vs, float calibr, + int vindex, int pindex, int tk_sindex, int rindex) +{ + Ray *ray; + + /* Create a Ray structure. */ + ray = RSL_new_ray(vs->tk.ncell[tk_sindex][pindex]); + if (ray == NULL) + { + perror("RayBuild(): RSL_new_ray failed\n"); + return(NULL); + } + Ray_headerFill(ray, gvl1, vs, pindex, tk_sindex, rindex); + /* Is this a 1C-51 file? */ + if ((strcmp(gvl1->sensor.parm[pindex]->parmDesc.parmName, "QCZ") == 0) || + (strcmp(gvl1->sensor.parm[pindex]->parmDesc.parmName, "QCZDR") == 0)) + RayFillFrom1C51(ray, vindex, + gvl1->sensor.parm[pindex]->parmData2byte[tk_sindex][rindex], + gvl1->sensor.parm[pindex-1]->parmData1byte[tk_sindex][rindex], + &gvl1->sensor.parm[pindex]->parmDesc, calibr); + else /* 1B-51 file */ + RayFillFrom1B51(ray, + gvl1->sensor.parm[pindex]->parmData2byte[tk_sindex][rindex], + &gvl1->sensor.parm[pindex]->parmDesc); + return(ray); +} + +/*************************************************************/ +/* */ +/* Sweep_headerFill */ +/* */ +/*************************************************************/ +void Sweep_headerFill(Sweep *sweep, SENSORS *sensor, int tk_sindex, int nrays) +{ +/* sweep->h.sweep_num filled in VolumeBuild() */ + sweep->h.elev = sensor->sweepInfo[tk_sindex].fixedAngle; + sweep->h.beam_width = sensor->radarDesc.horBeamWidth; + sweep->h.horz_half_bw = sensor->radarDesc.horBeamWidth / 2.0; + sweep->h.vert_half_bw = sensor->radarDesc.verBeamWidth / 2.0; + sweep->h.nrays = sensor->sweepInfo[tk_sindex].numRays; + sweep->h.f = f; + sweep->h.invf = invf; +} + +/*************************************************************/ +/* */ +/* SweepBuild */ +/* */ +/*************************************************************/ +Sweep *SweepBuild(L1B_1C_GV *gvl1, VosSize *vs, float calibr, + int vindex, int pindex, int tk_sindex) +{ + int rindex; + Sweep *sweep; + + /* Create a Sweep structure. */ + sweep = RSL_new_sweep(vs->rsl.maxNray); + if (sweep == NULL) + { + perror("SweepBuild(): RSL_new_sweep failed\n"); + return(NULL); + } + /* Initialize the Sweep_header values. */ + Sweep_headerFill(sweep, &gvl1->sensor, tk_sindex, vs->rsl.maxNray); + + /* Loop to fill each of the rays of this rsl sweep structure. */ + for (rindex=0; rindextk.nray[tk_sindex]; rindex++) + sweep->ray[rindex] = RayBuild(gvl1, vs, calibr, vindex, pindex, + tk_sindex, rindex); + return(sweep); +} + +/*************************************************************/ +/* */ +/* Volume_headerFill */ +/* */ +/*************************************************************/ +void Volume_headerFill(Volume *volume, char *parmDesc, int vindex, + int nsweeps, float calibr) +{ + if (vindex == DZ_INDEX) + volume->h.type_str = strdup("Reflectivity"); + else if (vindex == ZD_INDEX) + volume->h.type_str = strdup("Differential Reflectivity"); + else volume->h.type_str = strdup(parmDesc); + volume->h.f = f; + volume->h.invf = invf; + volume->h.nsweeps = nsweeps; + volume->h.calibr_const = calibr; +} + +/*************************************************************/ +/* */ +/* VolumeBuild */ +/* */ +/*************************************************************/ +Volume *VolumeBuild(L1B_1C_GV *gvl1, VosSize *vs, float calibr, + int vindex, int pindex) +{ + Volume *v; + int sindex, tk_sindex; + extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */ + extern int rsl_qsweep_max; + + /* Create a Volume structure. */ + v = RSL_new_volume(vs->tk.nsweep); + if (v == NULL) + { + perror("VolumeBuild(): RSL_new_volume failed\n"); + return(NULL); + } + /* Initialize the Volume_header values. */ + Volume_headerFill(v, gvl1->sensor.parm[pindex]->parmDesc.parmDesc, + vindex, vs->tk.nsweep, calibr); + if (radar_verbose_flag) + fprintf(stderr, "RSL volume type: %s\n", v->h.type_str); + + /* Build each of the sweeps of this radar volume structure. */ + sindex = -1; + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + { + if (rsl_qsweep != NULL) { + if (tk_sindex > rsl_qsweep_max) break; + if (rsl_qsweep[tk_sindex] == 0) continue; + } + /* If data for this parm type exists in this toolkit sweep, + then move it into a rsl sweep. */ + if (vs->tk.ncell[tk_sindex][pindex] > 0) + { + sindex++; + v->sweep[sindex] = SweepBuild(gvl1, vs, calibr, vindex, pindex, + tk_sindex); + v->sweep[sindex]->h.sweep_num = sindex + 1; + if (radar_verbose_flag) + fprintf(stderr, " rsl_sweep[%02d] elev=%4.1f nrays=%d cells/ray=%d\n", + v->sweep[sindex]->h.sweep_num-1, v->sweep[sindex]->h.elev, + vs->tk.nray[tk_sindex], vs->tk.ncell[tk_sindex][pindex]); + } + } /* end for (tk_sindex=0;...*/ + return(v); +} + +/*************************************************************/ +/* */ +/* parmIdentify */ +/* */ +/*************************************************************/ +int parmIdentify(char *parmName) +/* Identify the parameter type stored in the L1B_1C_GV structure. + Upon success, return the corresponding RSL radar volume XX_INDEX + value. + Upon failure, return -1 . +*/ +{ + int vindex; + + if (strcmp(parmName, "Z") == 0) + { + vindex = DZ_INDEX; invf = DZ_INVF; f = DZ_F; + } + else if (strcmp(parmName, "V") == 0) + { + vindex = VR_INDEX; invf = VR_INVF; f = VR_F; + } + else if (strcmp(parmName, "QCZ") == 0) + { + vindex = CZ_INDEX; invf = CZ_INVF; f = CZ_F; + } + else if (strcmp(parmName, "ZDR") == 0) + { + vindex = ZD_INDEX; invf = ZD_INVF; f = ZD_F; + } + else if (strcmp(parmName, "QCZDR") == 0) + { + vindex = CD_INDEX; invf = CD_INVF; f = CD_F; + } + else if (strcmp(parmName, "QCMZ") == 0) + { + vindex = MZ_INDEX; invf = MZ_INVF; f = MZ_F; + } + else if (strcmp(parmName, "QCMZDR") == 0) + { + vindex = MD_INDEX; invf = MD_INVF; f = MD_F; + } + else /* Unknown */ + { + return(-1); + } + + return(vindex); +} + +/*************************************************************/ +/* */ +/* Radar_headerFill */ +/* */ +/*************************************************************/ +void Radar_headerFill(Radar *radar, L1B_1C_GV *gvl1) +{ + double x; + + radar->h.month = (int)gvl1->volDes.month; + radar->h.day = (int)gvl1->volDes.day; + radar->h.year = (int)gvl1->volDes.year; + radar->h.hour = (int)gvl1->volDes.hour; + radar->h.minute = (int)gvl1->volDes.minute; + radar->h.sec = (float)gvl1->volDes.second; + strncpy(radar->h.radar_type, "**", 48); /*********/ + radar->h.nvolumes = MAX_RADAR_VOLUMES; + radar->h.number = MISSING_VAL; + strncpy(radar->h.name, gvl1->sensor.radarDesc.radarName, 7); + strncpy(radar->h.radar_name, gvl1->sensor.sweepInfo[0].radarName, 7); + + /* Radar Latitude */ + x = fabs(gvl1->sensor.radarDesc.radarLat); + radar->h.latd = (int)floor(x); + x = (x - radar->h.latd) * 60.0; + radar->h.latm = (int)floor(x); + x = (x - radar->h.latm) * 60.0; + radar->h.lats = (int)floor(x + 0.5); /* round up */ + if (gvl1->sensor.radarDesc.radarLat < 0) + { + radar->h.latd = -radar->h.latd; + radar->h.latm = -radar->h.latm; + radar->h.lats = -radar->h.lats; + } + + /* Radar Longitude */ + x = fabs(gvl1->sensor.radarDesc.radarLon); + radar->h.lond = (int)floor(x); + x = (x - radar->h.lond) * 60.0; + radar->h.lonm = (int)floor(x); + x = (x - radar->h.lonm) * 60.0; + radar->h.lons = (int)floor(x + 0.5); /* round up */ + if (gvl1->sensor.radarDesc.radarLon < 0) + { + radar->h.lond = -radar->h.lond; + radar->h.lonm = -radar->h.lonm; + radar->h.lons = -radar->h.lons; + } + + radar->h.height = (int)(1000.0 * gvl1->sensor.radarDesc.radarAlt + 0.5); + radar->h.spulse = MISSING_VAL; /* ns */ + radar->h.lpulse = MISSING_VAL; /* ns */ +} + +/*************************************************************/ +/* */ +/* RadarBuild */ +/* */ +/*************************************************************/ +Radar *RadarBuild(L1B_1C_GV *gvl1, VosSize *vs, float zCal) +/* Creates and fills a RSL radar structure with data obtained + from the L1B_1C_GV structure. + + If success, returns a pointer to the radar structure. + If failure, returns NULL. +*/ +{ + Radar *radar; + extern int rsl_qfield[]; + int pindex, vindex; + + if (radar_verbose_flag) + { + fprintf(stderr, "\n****** Moving VOS from toolkit L1GV structure -> RSL structure ...\n"); + } + /* Create a structure of type Radar */ + radar = (Radar *)RSL_new_radar(MAX_RADAR_VOLUMES); + if (radar == NULL) + { + perror("RadarBuild(): Error creating radar structure.\n"); + return(NULL); + } + /* Initialize the Radar_header values. */ + Radar_headerFill(radar, gvl1); + + /* Build each of the 'nparm' volumes of the radar structure. */ + for (pindex=0; pindextk.nparm; pindex++) + { + /* Identify parameter type, so we know which RSL volume to load the data + into. */ + vindex = parmIdentify(gvl1->sensor.parm[pindex]->parmDesc.parmName); + if (vindex < 0) + { + fprintf(stderr, + "RadarBuild(): Unexpected parameter type: %s found in HDF file.\n", + gvl1->sensor.parm[pindex]->parmDesc.parmName); + } + /* Don't build mask volumes. */ + else if ((vindex == MZ_INDEX) || (vindex == MD_INDEX)) continue; + else if (rsl_qfield[vindex] == 0) /* Don't build unselected volumes. */ + { + if (radar_verbose_flag) + { + fprintf(stderr, "Field %s not selected for retrieval from HDF file.\n", + gvl1->sensor.parm[pindex]->parmDesc.parmName); + if (vindex == CZ_INDEX) + fprintf(stderr, "Field 'DZ' unselected for retrieval from 1C-51 file.\n"); + else if (vindex == CD_INDEX) + fprintf(stderr, "Field 'ZD' unselected for retrieval from 1C-51 file.\n"); + } + } /* end else if (rsl_qfield[vindex] == 0) */ + else if (vindex == CZ_INDEX) /* Handle CZ and DZ volumes. */ + { + /* Build the RSL CZ volume. */ + radar->v[vindex] = VolumeBuild(gvl1, vs, zCal, vindex, pindex); + /* If required, build a RSL DZ volume. */ + if (rsl_qfield[DZ_INDEX]) + { + if (radar_verbose_flag) + fprintf(stderr, "Constructing reflectivity volume 'DZ'\n"); + radar->v[DZ_INDEX] = VolumeBuild(gvl1, vs, zCal, DZ_INDEX, pindex); + } + } /* end if (vindex == CZ_INDEX) */ + else if (vindex == CD_INDEX) /* Handle CD and ZD volumes. */ + { + /* Build the RSL CD volume. */ + radar->v[vindex] = VolumeBuild(gvl1, vs, 0.0, vindex, pindex); + /* If required, build a RSL ZD volume. */ + if (rsl_qfield[ZD_INDEX]) + { + if (radar_verbose_flag) + fprintf(stderr, "Constructing reflectivity volume 'ZD'\n"); + radar->v[ZD_INDEX] = VolumeBuild(gvl1, vs, 0.0, ZD_INDEX, pindex); + } + } /* end if (vindex == CD_INDEX) */ + else /* Handle all 1B-51 fields. (DZ, ZD, VR) */ + { + radar->v[vindex] = VolumeBuild(gvl1, vs, 0.0, vindex, pindex); + } + } /* end for (pindex=0; ...) */ + + return(radar); +} + +/*************************************************************/ +/* */ +/* commentsRead */ +/* */ +/*************************************************************/ +int commentsRead(VosSize *vs, float *zCal, char *comments, int productID) +{ +/* Parse the comments field of the 'L1B_1C_GV' structure. + Retrieve the number_of_cells/ray values for each parameter, and + store in the 'VosSize' structure. + + Returns: OK if success. + <0 if failure. +*/ + char *spointer; + char record[2][2048]; /* 2 records is maximum possible. */ + char parseString[1024]; + int nrecords, pindex, tk_sindex; + float qcParm[NUMBER_QC_PARAMS]; + + /* Construct a format string to read the records in the comments + field. A logical record here is the block of ascii characters + which details the toolkit dimensions of one VOS. + For a 1B-51 file, there should be 1 such record. + For a 1C-51 file, there is one additional record for QC parms.*/ + + strcpy(parseString, ""); + strcat(parseString, "%[^*] %*[*\n]"); + nrecords = 1; + if (productID == TK_L1C_GV) + { + strcat(parseString, "%[^\n]"); + nrecords++; + } + /* Read all records from the comments field into the record buffers. */ + if (sscanf(comments, parseString, record[0], record[1]) != nrecords) + goto quit; + + + if (sscanf(record[0], "nSweep=%d", &vs->tk.nsweep) != 1) goto quit; + + strcpy(parseString, "nRay=%d\n"); + for (pindex=0; pindextk.nparm; pindex++) + strcat(parseString, "nCell_parm[%*d]=%d\n"); + + spointer = record[0]; + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + { + spointer = strstr(spointer, "nRay="); + if (sscanf(spointer, parseString, &vs->tk.nray[tk_sindex], + &vs->tk.ncell[tk_sindex][0], &vs->tk.ncell[tk_sindex][1], + &vs->tk.ncell[tk_sindex][2], &vs->tk.ncell[tk_sindex][3]) + != vs->tk.nparm+1) goto quit; + spointer = spointer + 5; + } + + + /* If 1C-51 file, read the QC parameters into the qcParm array. */ + if (productID == TK_L1C_GV) + { + if (sscanf(record[1], "-hThresh1 %f -hThresh2 %f -hThresh3 %f -zThresh0 %f -zThresh1 %f -zThresh2 %f -zThresh3 %f -hFreeze %f -dbzNoise %f -zCal %f", + &qcParm[HTHRESH1], &qcParm[HTHRESH2], &qcParm[HTHRESH3], + &qcParm[ZTHRESH0], &qcParm[ZTHRESH1], &qcParm[ZTHRESH2], &qcParm[ZTHRESH3], + &qcParm[HFREEZE], &qcParm[DBZNOISE], &qcParm[ZCAL]) != NUMBER_QC_PARAMS) + goto quit; + /* Print out the QC parameters we've just read in. */ + /* + if (radar_verbose_flag) + { + fprintf(stderr, "\n****** Reading VOS QC Parameters from HDF file...\n"); + fprintf(stderr, "hThresh1: %.2f hThresh2: %.2f hThresh3: %.2f\n", + qcParm[HTHRESH1], qcParm[HTHRESH2], qcParm[HTHRESH3]); + fprintf(stderr, "zThresh0: %.2f zThresh1: %.2f zThresh2: %.2f zThresh3: %.2f\n", + qcParm[ZTHRESH0], qcParm[ZTHRESH1], qcParm[ZTHRESH2], qcParm[ZTHRESH3]); + fprintf(stderr, "hFreeze: %.2f dbzNoise: %.2f zCal: %.2f\n\n", + qcParm[HFREEZE], qcParm[DBZNOISE], qcParm[ZCAL]); + } + */ + if (qcParm[ZCAL] <= NOVAL_FLOAT) *zCal = 0.0; + else *zCal = qcParm[ZCAL]; + } /* end if (productID == TK_L1C_GV) */ + + return(OK); + + quit: + if (radar_verbose_flag) + fprintf(stderr, "commentsRead(): Failure reading comments field\n"); + return(ABORT); +} + +/*************************************************************/ +/* */ +/* GVL1Build */ +/* */ +/*************************************************************/ +static L1B_1C_GV *GVL1Build(IO_HANDLE *granuleHandle, int vosNum, + VosSize *vs) +{ +/* Build a toolkit 'L1B_1C_GV' structure sized for the VOS we + will later read in from the HDF file. + Returns: + gvl1 if success. + NULL if fails. +*/ + int ncell, pindex; + L1B_1C_GV *gvl1; + + /* Using the toolkit, get the toolkit VOS dimensions from + the HDF file. Note that the toolkit dimensions are distinct + from the RSL VOS dimensions. */ + vs->tk.nparm = TKgetNparm(granuleHandle, vosNum); +/* TK_FAIL is now defined as 1?????? */ + if (vs->tk.nparm <= 0) + { + fprintf(stderr, "GVL1Build(): TKgetNparm() failed.\n"); + return(NULL); + } + vs->tk.nsweep = TKgetNsweep(granuleHandle, vosNum); + if (vs->tk.nsweep <= 0) + { + fprintf(stderr, "GVL1Build(): TKgetNsweep() failed.\n"); + return(NULL); + } + vs->rsl.maxNray = TKgetNray(granuleHandle, vosNum); + if (vs->rsl.maxNray <= 0) + { + fprintf(stderr, "GVL1Build(): TKgetNray() failed.\n"); + return(NULL); + } + + /* Allocate memory for a TSDIS 'L1B_1C_GV' structure. */ + gvl1 = (L1B_1C_GV *)TKnewGVL1(); + for (pindex=0; pindextk.nparm; pindex++) + { + /* Allocate memory for a new parameter. */ + gvl1->sensor.parm[pindex] = (PARAMETER *)TKnewGVL1parm(); + ncell = TKgetNcell(granuleHandle, vosNum, pindex); + /* Allocate memory for a 3D array to contain mask values and/or data. */ + if (granuleHandle->productID == TK_L1B_GV) + { + gvl1->sensor.parm[pindex]->parmData2byte = + (int16 ***)TKnewParmData2byte(vs->tk.nsweep, vs->rsl.maxNray, ncell); + } + else /* 1C-51 */ + { + /* Odd parameters contain data, even parameters contain masks. */ + if ((pindex % 2) == 0) /* Mask? */ + gvl1->sensor.parm[pindex]->parmData1byte = + (int8 ***)TKnewParmData1byte(vs->tk.nsweep, vs->rsl.maxNray, ncell); + else /* data */ + gvl1->sensor.parm[pindex]->parmData2byte = + (int16 ***)TKnewParmData2byte(vs->tk.nsweep, vs->rsl.maxNray, ncell); + } + } /* end for (pindex=0; ... */ + + return(gvl1); +} + +/*************************************************************/ +/* */ +/* metaDataRead */ +/* */ +/*************************************************************/ +int metaDataRead(Radar *radar, IO_HANDLE *granuleHandle) +{ + char buf[64]; + + TKreadMetadataChar(granuleHandle, TK_RADAR_CITY, buf); + strncpy(radar->h.city, buf, 14); + TKreadMetadataChar(granuleHandle, TK_RADAR_STATE, buf); + strncpy(radar->h.state, buf, 2); + return(OK); +} + +/*************************************************************/ +/* */ +/* hdfFileOpen */ +/* */ +/*************************************************************/ +static int hdfFileOpen(char *infile, IO_HANDLE *granuleHandle, + char *hdfFileName, int *vosNum) +{ +/* Opens, if necessary, an HDF file. Checks that a VOS, not previously + retrieved, exists in the HDF file. + + Returns: + OK, if success. + <0, if failure. +*/ + char *product; + int productID, nvos, status; + + /* If we presently have an open HDF file, check that it is the + file requested; ie, 'infile'. If it's not, we first close + the open HDF file. */ + if (*vosNum != 0) + { + if (strcmp(hdfFileName, infile) != 0) + { + if (TKclose(granuleHandle) != TK_SUCCESS) + { + fprintf(stderr, "hdfFileOpen(): *** TKclose() error\n"); + return(ABORT); + } + *vosNum = 0; + } + } /* end if (*vosNum != 0) */ + + /* If first VOS of HDF file, we need first to open the file. */ + if (*vosNum == 0) + { + strncpy(hdfFileName, infile, TK_MAX_FILENAME-1); + /* Get the desired product out of the HDF filename. */ + product = strrchr(hdfFileName, '/'); + if (product == NULL) + product = hdfFileName; + else + product = (char *)(product + 1); + if (strncmp(product, "1B51", 4) == 0) + productID = TK_L1B_GV; + else if (strncmp(product, "1C51", 4) == 0) + productID = TK_L1C_GV; + else + { + fprintf(stderr, "hdfFileOpen(): Invalid HDF filename.\n"); + return(ABORT); + } + status = TKopen(hdfFileName, productID, TK_READ_ONLY, granuleHandle); + if (status != TK_SUCCESS) + { + fprintf(stderr, "hdfFileOpen(): *** TKopen() error\n"); + return(ABORT); + } + } /* end if (*vosNum == 0) */ + + /* Check if the requested VOS exists in the HDF granule. */ + nvos = (int)TKgetNvos(granuleHandle); + if (nvos == 0) + { + if (radar_verbose_flag) + fprintf(stderr, "\nEmpty granule.\n"); + return(QUIT); + } + else if (*vosNum+1 > nvos) + { + if (radar_verbose_flag) + fprintf(stderr, "\nAll VOSs read from HDF file: %s\n", hdfFileName); + return(QUIT); + } + else if (nvos < 0) + { + fprintf(stderr, "hdfFileOpen():*** TKgetNvos() error\n"); + return(QUIT); + } + + return(OK); +} + +/*************************************************************/ +/* */ +/* RSL_hdf_to_radar */ +/* */ +/*************************************************************/ +Radar *RSL_hdf_to_radar(char *infile) +{ + /* Reads one volume scan from a HDF file into a RSL radar structure. + It is envisioned that all VOSs will normally be retrieved, + one after the other, from an HDF file. Therefore, in the + interest of efficiency, this function is designed to keep + an HDF file open between VOS retrievals. + + Returns: + - pointer to a filled radar structure, if success. + - NULL pointer, if failure. + */ + int pindex, status; + float zCal=0.0; /* Z Calibration constant. */ + VosSize vs; /* VOS dimensions storage. */ + Radar *radar; /* RSL structure for VOS storage. */ + L1B_1C_GV *gvl1; /* TSDIS structure for VOS storage. */ + /* Following values must remain between invocations of this function. */ + static IO_HANDLE granuleHandle; + static char hdfFileName[TK_MAX_FILENAME]; + static int vosNum=0; /* No. of last VOS read from HDF file. (1...N) */ + + /* Open, if necessary, an HDF file. */ + status = hdfFileOpen(infile, &granuleHandle, hdfFileName, &vosNum); + if (status < 0) goto quit; + + /* Initialize the 'VosSize' structure. */ + memset(&vs, '\0', sizeof(VosSize)); + + /* Build a toolkit 'L1B_1C_GV' structure correctly sized for the VOS we + will next read in from the HDF file. */ + gvl1 = (L1B_1C_GV *)GVL1Build(&granuleHandle, vosNum, &vs); + if (gvl1 == NULL) goto quit; + + /* Read VOS from HDF file into the toolkit L1B_1C_GV structure. */ + if (radar_verbose_flag) + fprintf(stderr, "\n\n***** Moving VOS from HDF file -> toolkit L1GV structure ...\n"); + status = TKreadL1GV(&granuleHandle, gvl1); + if (status != TK_SUCCESS) + { + fprintf(stderr, "RSL_hdf_to_radar(): *** TKreadL1GV() error\n"); + goto quit; + } + + if (radar_verbose_flag) + { + fprintf(stderr, "Input file: %s\n", hdfFileName); + fprintf(stderr, "VOS date: %.2d/%.2d/%d\n", gvl1->volDes.month, + gvl1->volDes.day, gvl1->volDes.year); + fprintf(stderr, "VOS time: %.2d:%.2d:%.2d\n", gvl1->volDes.hour, + gvl1->volDes.minute, gvl1->volDes.second); + + fprintf(stderr, "Granule VOS #: %d\n", gvl1->volDes.volNum); + fprintf(stderr, "VOS Fields:\n"); + for (pindex=0; pindexsensor.parm[pindex]->parmDesc.parmDesc); + } + + /* Scan thru the comments field of the 'gvl1' structure for + the number_of_cells/ray/sweep for each parameter, and store + the values in vs, so we can next build a correctly sized RSL + structure to contain the VOS. + */ + if (commentsRead(&vs, &zCal, gvl1->comments, granuleHandle.productID) < 0) + goto quit; + + /* Move VOS from L1B_1C_GV structure to radar structure. */ + radar = (Radar *)RadarBuild(gvl1, &vs, zCal); + /* There are a couple metadata items needed for insertion into the + radar->header. */ + status = metaDataRead(radar, &granuleHandle); + + /* Free memory allocated to the toolkit GVL1 structure. */ + TKfreeGVL1(gvl1); + if (radar == NULL) goto quit; + + vosNum++; + return(radar); + + quit: + if (status == QUIT) + TKclose(&granuleHandle); + return(NULL); +} + +#else +/* + * Just declare and return something when we're told we don't have + * TSDISTK nor HDF. Do this because RSL_anyformat_to_radar references + * this routine; linking won't fail because of no HDF. + */ + +#include "rsl.h" +Radar *RSL_hdf_to_radar(char *infile) +{ + return NULL; +} +#endif diff --git a/histogram.c b/histogram.c new file mode 100644 index 0000000..ffefe1e --- /dev/null +++ b/histogram.c @@ -0,0 +1,280 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + David B. Wolff + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include +#include +#include "rsl.h" + +/*********************************************************************/ +/* */ +/* Unless otherwise stated, all routines in this file are */ +/* were coded by David B. Wolff, Space Applications Corporation, */ +/* Landover, MD. */ +/* */ +/*********************************************************************/ + +extern int radar_verbose_flag; + +/**********************************************************/ +/* This set of functions and typedefs create a histogram */ +/* from a volume, sweep or ray. The structure of the */ +/* histogram is as such: */ +/* */ +/* histogram->nbins # number of bins in histogram */ +/* histogram->low # Low end of histogram */ +/* histogram->hi # High end of histogram */ +/* histogram->ucount # Total number of bins looked at */ +/* # in calculating histogram */ +/* histogram->ccount # Valid number of bins looked at */ +/* # in calculating histogram */ +/* histogram->data[] # Counts of each bin (How is this */ +/* # allocated???? */ +/**********************************************************/ +/** DBW and JHM *******************************************/ +/**********************************************************/ + + +Histogram *RSL_allocate_histogram(int low, int hi) +{ + Histogram *histogram; + int nbins; + + nbins = hi - low + 1; + histogram = (Histogram *)calloc(1, sizeof(Histogram)); + if (histogram) { + histogram->nbins = nbins; + histogram->low = low; + histogram->hi = hi; + histogram->ucount = 0; + histogram->ccount = 0; + histogram->data = (int *)calloc(nbins, sizeof(int)); + } + return histogram; +} + +/*********************************************************************/ +/* */ +/* RSL_free_histogram */ +/* */ +/*********************************************************************/ +void RSL_free_histogram(Histogram *histogram) +{ + if (histogram == NULL) return; + if (histogram->data) free(histogram->data); + free(histogram); +} + +/*********************************************************/ +/** DBW and JHM ******************************************/ +/*********************************************************/ +void RSL_print_histogram(Histogram *histogram, int min_range, int max_range, + char *filename) +{ + float PDF[200], CDF[200]; + + int nbins; + float ucount, ccount; + + int i, index; + FILE *fp; + +/* Print the stats on this histogram */ + + if(histogram == NULL) { + perror("Cannot print NULL histogram"); + return; + } + + if (radar_verbose_flag) fprintf(stderr,"print_histogram: %s\n",filename); + if((fp = fopen(filename,"w")) == NULL ) { + perror(filename); + return; + } + fprintf(fp,"Min range = %d\n", min_range); + fprintf(fp,"Max range = %d\n", max_range); + fprintf(fp,"histogram->nbins = %d\n",histogram->nbins); + fprintf(fp,"histogram->low = %d\n",histogram->low); + fprintf(fp,"histogram->hi = %d\n",histogram->hi); + fprintf(fp,"histogram->ucount = %d\n",histogram->ucount); + fprintf(fp,"histogram->ccount = %d\n",histogram->ccount); + +/* + Compute the PDF and CDF from the histogram. + PDF = histogram->data[i]/ucount (PDF) + CDF = runsum(PDF) (CDF) +*/ + nbins = histogram->nbins; + ucount = histogram->ucount; + ccount = histogram->ccount; + + for(i=0; idata[i]/ucount; + PDF[i] = histogram->data[i]/ccount; + } + + CDF[0] = PDF[0]; + for(i=0; ilow; + + fprintf(fp,"\nBin Count PDF CDF\n"); + for(i=0; idata[i], PDF[i],CDF[i]); + index++; + } + fclose(fp); +} + +Histogram *RSL_read_histogram(char *infile) +{ + + FILE *fp; + int n; + int low, hi; + int nbins; + Histogram *histogram; + + if ((fp = fopen(infile, "r")) == NULL) { + perror(infile); + return NULL; + } + +/* + 1. nbins, ucount, count + 2. data[0..nbins-1] +*/ + n = 0; + n += fread(&nbins, sizeof(nbins), 1, fp); + n += fread(&low, sizeof(int), 1, fp); + n += fread(&hi, sizeof(int), 1, fp); + + if ((histogram = RSL_allocate_histogram(low, hi)) == NULL) { + perror("read_histogram"); + return NULL; + } + if(histogram->low != low || histogram->hi != hi) { + perror("Incompatible histograms"); + return NULL; + } + n += fread(&histogram->ucount, sizeof(int), 1, fp); + n += fread(&histogram->ccount, sizeof(int), 1, fp); + n += fread(histogram->data, sizeof(int), nbins, fp); + fclose(fp); + return histogram; +} + +int RSL_write_histogram(Histogram *histogram, char *outfile) +{ + + FILE *fp; + int n; + + if ((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + return -1; + } + +/* + 1. nbins, ucount, count + 2. data[0..nbins-1] +*/ + n = 0; + n += fwrite(&histogram->nbins, sizeof(int), 1, fp); + n += fwrite(&histogram->low, sizeof(int), 1, fp); + n += fwrite(&histogram->hi, sizeof(int), 1, fp); + n += fwrite(&histogram->ucount, sizeof(int), 1, fp); + n += fwrite(&histogram->ccount, sizeof(int), 1, fp); + n += fwrite(histogram->data, sizeof(int), histogram->nbins, fp); + fclose(fp); + return n; +} +/*********************************************************/ +/** DBW and JHM ******************************************/ +/*********************************************************/ + +Histogram *RSL_get_histogram_from_ray(Ray *ray, Histogram *histogram, + int low, int hi, int min_range, int max_range) +{ + int i, index; + float dbz, ray_resolution, range; + float (*f)(Range x); + + if (histogram == NULL ) { + if (radar_verbose_flag) fprintf(stderr,"Allocating histogram at ray level\n"); + histogram = RSL_allocate_histogram(low, hi); + } + + if(ray != NULL) { + ray_resolution = ray->h.gate_size/1000.0; + f = ray->h.f; + for(i=0; ih.nbins; i++) { + histogram->ucount++; + range = i*ray_resolution + ray->h.range_bin1/1000.; + if(range < min_range) continue; + if(range > max_range) break; + dbz = f(ray->range[i]); + if(dbz >= histogram->low && dbz <= histogram->hi) { + index = dbz - histogram->low; + histogram->ccount++; + histogram->data[index]++; + } + } + } + return histogram; +} + +Histogram *RSL_get_histogram_from_sweep(Sweep *sweep, Histogram *histogram, + int low, int hi, int min_range, int max_range) +{ + int i; + if (histogram == NULL ) { + if (radar_verbose_flag) fprintf(stderr,"Allocating histogram at sweep level\n"); + histogram = RSL_allocate_histogram(low, hi); + } + if(sweep != NULL) { + for(i=0; ih.nrays; i++) { + histogram = RSL_get_histogram_from_ray(sweep->ray[i], histogram, + low, hi, min_range, max_range); + } + } + + return histogram; +} + +Histogram *RSL_get_histogram_from_volume(Volume *volume, Histogram *histogram, + int low, int hi, int min_range, int max_range) +{ + int i; + if (histogram == NULL ) { + if (radar_verbose_flag) fprintf(stderr,"Allocating histogram at volume level\n"); + histogram = RSL_allocate_histogram(low, hi); + } + if(volume == NULL) return NULL; + for(i=0; ih.nsweeps; i++) { + histogram = RSL_get_histogram_from_sweep(volume->sweep[i], histogram, + low, hi, min_range,max_range); + } + return histogram; +} diff --git a/image_gen.c b/image_gen.c new file mode 100644 index 0000000..cfedc8c --- /dev/null +++ b/image_gen.c @@ -0,0 +1,1255 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + *--------------------------------------------------------------------- + * Image generation functions: + * + * void RSL_load_color_table(char *infile, char buffer[256], int *ncolors); + * void RSL_load_red_table(char *infile); + * void RSL_load_green_table(char *infile); + * void RSL_load_blue_table(char *infile); + * void RSL_load_refl_color_table(); + * void RSL_load_vel_color_table(); + * void RSL_load_sw_color_table(); + * void RSL_load_height_color_table(); + * void RSL_load_rainfall_color_table(); + * void RSL_bscan_ray(FILE *fp, Ray *r); + * void RSL_bscan_sweep(Sweep *s, char *outfile); + * void RSL_bscan_volume(Volume *v, char *basename); + * unsigned char *RSL_sweep_to_cart(Sweep *s, int xdim, int ydim, float range); + * unsigned char *RSL_rhi_sweep_to_cart(Sweep *s, int xdim, int ydim, float range, int vert_scale); + * void RSL_write_gif(char *outfile, unsigned char *image, int xdim, int ydim, char c_table[256][3]); + * void RSL_write_pict(char *outfile, unsigned char *image, int xdim, int ydim, char c_table[256][3]); + * void RSL_write_ppm(char *outfile, unsigned char *image, int xdim, int ydim, char c_table[256][3]); + * void RSL_write_pgm(char *outfile, unsigned char *image, int xdim, int ydim); + * void RSL_sweep_to_gif(Sweep *s, char *outfile, int xdim, int ydim, float range); + * void RSL_rhi_sweep_to_gif(Sweep *s, char *outfile, int xdim, int ydim, float range, int vert_scale); + * void RSL_sweep_to_pict(Sweep *s, char *outfile, int xdim, int ydim, float range); + * void RSL_sweep_to_ppm(Sweep *s, char *outfile, int xdim, int ydim, float range); + * void RSL_sweep_to_pgm(Sweep *s, char *outfile, int xdim, int ydim, float range); + * void RSL_volume_to_gif(Volume *v, char *basename, int xdim, int ydim, float range); + * void RSL_volume_to_pict(Volume *v, char *basename, int xdim, int ydim, float range); + * void RSL_volume_to_ppm(Volume *v, char *basename, int xdim, int ydim, float range); + * void RSL_volume_to_pgm(Volume *v, char *basename, int xdim, int ydim, float range); + * void RSL_rebin_velocity_ray(Ray *r); + * void RSL_rebin_velocity_sweep(Sweep *s); + * void RSL_rebin_velocity_volume(Volume *v); + * void RSL_rebin_zdr_ray(Ray *r); + * void RSL_rebin_zdr_sweep(Sweep *s); + * void RSL_rebin_zdr_volume(Volume *v); + */ +#include +#include +#include "rsl.h" +extern FILE *popen(const char *, const char *); +extern int pclose(FILE *stream); +extern int radar_verbose_flag; + +static char color_table[256][3]; +static int ncolors = 0; + + +/**********************************************************************/ +/* */ +/* RSL_load_color_table */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_load_color_table(char *infile, char buffer[256], int *num_colors) +{ + FILE *fp; + + fp = fopen(infile, "r"); + if (fp == NULL) { + perror(infile); + exit(-1); + } + *num_colors = fread(buffer, sizeof(char), 256, fp); + + (void)fclose(fp); +} + +/**********************************************************************/ +/* */ +/* RSL_set_color_table */ +/* */ +/* By: John Merritt */ +/* SM&A Corporation */ +/* Jan 21, 1999 */ +/**********************************************************************/ +void RSL_set_color_table(int icolor, char buffer[256], int ncolors) +{ + int i; + /* In RSL: Red table=RSL_RED_TABLE, + * green table=RSL_GREEN_TABLE, + * blue table=RSL_BLUE_TABLE. + */ + for (i=0; i +/**********************************************************************/ +/* */ +/* RSL_load_refl_color_table */ +/* RSL_load_vel_color_table */ +/* RSL_load_sw_color_table */ +/* RSL_load_zdr_color_table */ +/* RSL_load_rainfall_color_table */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_load_refl_color_table() +{ + char buffer[256]; + char *fnames[3] = { REFL_RED_FILE, REFL_GREEN_FILE, REFL_BLUE_FILE }; + + int i, igun; + + for (igun=0; igun<3; igun++) { + RSL_load_color_table(fnames[igun], buffer, &ncolors); + for (i=0; ih.nbins); + f = r->h.f; + for (i=0; ih.nbins; i++) + if (f(r->range[i]) != BADVAL) { + if (f(r->range[i]) >= 0) outvect[i] = (unsigned char) f(r->range[i]); + } + else + outvect[i] = (unsigned char) (255 + f(r->range[i])); + + for(i=0; ih.nbins; i++) + (void)fwrite(color_table[outvect[i]], sizeof(char), 3, fp); + +} +void RSL_bscan_sweep(Sweep *s, char *outfile) +{ + int i, j, nrecs, nbins; + Ray *first_ray; + FILE *fp; + if (s == NULL) return; + + fp = fopen(outfile,"w"); + if (fp == NULL) { + perror(outfile); + return; + } + first_ray = RSL_get_first_ray_of_sweep(s); + nrecs = s->h.nrays; + nbins = first_ray->h.nbins; + fprintf(fp, "P6\n# %s\n%d %d\n255\n",outfile, nbins, nrecs); + outvect = NULL; + outvect = (unsigned char *) calloc(nbins, sizeof(unsigned char)); + if (outvect == NULL) { + perror((char *)outvect); + return; + } + +/* Now, write the bscan. */ + for (j=0; jh.nrays; j++) { + if (s->ray[j]) RSL_bscan_ray(s->ray[j], fp); + else { + memset(outvect, 0, nbins); + for(i=0; ih.nsweeps; i++) { + (void)sprintf(outfile,"bscan.%2.2d.ppm", i); + + RSL_bscan_sweep(v->sweep[i], outfile); + if (radar_verbose_flag) + fprintf(stderr,"Output: %s\n", outfile); + } + free (outfile); +} + + +/**********************************************************************/ +/**********************************************************************/ +/* */ +/* Volume to cartesean GIF */ +/* (polar to cartesean) */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +/**********************************************************************/ +#include + + +/**********************************************************************/ +/* */ +/* RSL_sweep_to_cart */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +unsigned char *RSL_sweep_to_cart(Sweep *s, int xdim, int ydim, float range) +{ + /* Range specifies the maximum range to load that points into the image. */ + + int x, y; + float azim, r; + float val; + int the_index; + Ray *ray; + float beam_width; + + + static unsigned char *cart_image = NULL; + + if (s == NULL) return NULL; + if (xdim != ydim || ydim < 0 || xdim < 0) { + fprintf(stderr, "(xdim=%d) != (ydim=%d) or either negative.\n", xdim, ydim); + return NULL; + } + cart_image = (unsigned char *) calloc(xdim*ydim, sizeof(unsigned char)); + + beam_width = s->h.beam_width/2.0 * 1.2; + if (beam_width == 0) beam_width = 1.2; /* Sane image generation. */ + + for (y=-ydim/2; y=0 && x<0) /* Quad: 2 */ + azim += 180; + + /* Radar is clockwise increasing. */ + azim = -azim; + + azim -= 90.0; + if (azim < 0) azim += 360.0; + + r = (float)sqrt((double)x*x + (double)y*y); + if (ydim < xdim) r *= range/(.5*ydim); + else r *= range/(.5*xdim); + if (r > range) val = BADVAL; + else { + ray = RSL_get_closest_ray_from_sweep(s, azim, beam_width); + val = RSL_get_value_from_ray(ray, r); + } + the_index = (y+ydim/2)*ydim + (xdim-1)-(x+xdim/2); + if (val == BADVAL || val == NOTFOUND_V || val == NOTFOUND_H) + cart_image[the_index] = (unsigned char) 0; + else if (val >= 0) + cart_image[the_index] = (unsigned char) val; + else + cart_image[the_index] = (unsigned char) (256+val); + + } + return cart_image; +} + +/**********************************************************************/ +/* */ +/* RSL_rhi_sweep_to_cart */ +/* */ +/* A modified version of RSL_sweep_to_cart() */ +/* -> Handles rhi (vertical) sweeps */ +/* Kolander */ +/* Space Applications Corporation */ +/* July 27, 1995 */ +/**********************************************************************/ +unsigned char *RSL_rhi_sweep_to_cart(Sweep *s, int xdim, int ydim, + float range, int vert_scale) +{ + int x, y, xx, yy, i, j; + float angle, r; + float val; + int the_index; + + static unsigned char *rhi_cart_image = NULL; + static unsigned char *buffer = NULL; + + if (s == NULL) return NULL; + if (buffer == NULL) + buffer = (unsigned char *)calloc(xdim*ydim, sizeof(unsigned char)); + if (rhi_cart_image == NULL) + rhi_cart_image = (unsigned char *)calloc(xdim*ydim, sizeof(unsigned char)); + memset(buffer, (unsigned char)0, xdim*ydim); + memset(rhi_cart_image, (unsigned char)0, xdim*ydim); + + for (y=0; y range) + val = BADVAL; + else + val = RSL_get_value_from_sweep(s, angle, r); + + /* A vertical sweep extends from 0 deg to perhaps 25 deg in + elevation. For proper orientation of a displayed rhi + vertical sweep: + 1. reflect image about the line y=x . + 2. translate image downward so that radar site is located + at the bottom left corner of the image. The sweep will + then extend upward from the bottom of the image. + */ + xx = y; /* reflection about line y=x */ + yy = x; /* reflection about line y=x */ + the_index = (ydim - 1 - yy)*xdim + xx; + if (val == BADVAL || val == NOTFOUND_V || val == NOTFOUND_H) + buffer[the_index] = (unsigned char) 0; + else if (val >= 0) + buffer[the_index] = (unsigned char) val; + else + buffer[the_index] = (unsigned char) (256+val); + } + + /* To see details in the sweep, it is customary to scale the image + so that the scale of the vertical axis is 5 or 10 times the scale + of the horizontal axis. + Copy each row of pixel values from buffer[] a constant multiple + number of times into rhi_cart_image[], in order to vertically + expand the image. + */ + for (j=0; j +/**********************************************************************/ +/* */ +/* RSL_write_gif */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_write_gif(char *outfile, unsigned char *image, int xdim, int ydim, char c_table[256][3]) +{ + int i; + int nbytes; + char pipecmd[300]; + FILE *fpipe; + + if (image == NULL) { + fprintf(stderr, "No image for file %s\n", outfile); + return; + } + fpipe = NULL; + nbytes = xdim*ydim; + (void)sprintf(pipecmd, "ppmtogif > %s 2>/dev/null", outfile); + fpipe = popen(pipecmd, "w"); /* Global FILE * */ + if (fpipe == NULL) { + perror("RSL_write_gif1"); + return; + } + if (fprintf(fpipe, "P6\n# %s\n%d %d\n255\n",outfile, xdim, ydim) < 0) { + perror("RSL_write_gif2"); + pclose(fpipe); + return; + } + + for (i=0; i %s 2>/dev/null", outfile); + fpipe = popen(pipecmd, "w"); /* Global FILE * */ + fprintf(fpipe, "P6\n# %s\n%d %d\n255\n",outfile, xdim, ydim); + for (i=0; i %s.gz 2>/dev/null", outfile); + fpipe = popen(pipecmd, "w"); /* Global FILE * */ + fprintf(fpipe, "P5\n# %s\n%d %d\n255\n",outfile, xdim, ydim); + (void)fwrite(image, sizeof(char), nbytes, fpipe); + (void)pclose(fpipe); + +/* The following is commented and is for non compressed. */ +#ifdef COMPILE + nbytes = xdim*ydim; + fpipe = fopen(outfile, "w"); /* Global FILE * */ + fprintf(fpipe, "P5\n# %s\n%d %d\n255\n",outfile, xdim, ydim); + (void)fwrite(image, sizeof(char), nbytes, fpipe); + (void)fclose(fpipe); +#endif +} + +/**********************************************************************/ +/* */ +/* RSL_sweep_to_gif */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_sweep_to_gif(Sweep *s, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (s == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_sweep_to_cart(s, xdim, ydim, range); + RSL_write_gif(outfile, cart_image, xdim, ydim, color_table); + free(cart_image); +} + +/**********************************************************************/ +/* */ +/* RSL_rhi_sweep_to_gif */ +/* */ +/* Slightly modified version of RSL_sweep_to_gif() */ +/* */ +/* By: Kolander */ +/* Space Applications Corporation */ +/* July 27, 1995 */ +/**********************************************************************/ +void RSL_rhi_sweep_to_gif(Sweep *s, char *outfile, int xdim, int ydim, + float range, int vert_scale) +{ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (s == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_rhi_sweep_to_cart(s, xdim, ydim, range, vert_scale); + RSL_write_gif(outfile, cart_image, xdim, ydim, color_table); + free(cart_image); +} + +/**********************************************************************/ +/* */ +/* RSL_sweep_to_pict */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_sweep_to_pict(Sweep *s, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (s == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_sweep_to_cart(s, xdim, ydim, range); + RSL_write_pict(outfile, cart_image, xdim, ydim, color_table); + free(cart_image); +} +/**********************************************************************/ +/* */ +/* RSL_sweep_to_ppm */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_sweep_to_ppm(Sweep *s, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (s == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_sweep_to_cart(s, xdim, ydim, range); + RSL_write_ppm(outfile, cart_image, xdim, ydim, color_table); + free(cart_image); +} +/**********************************************************************/ +/* */ +/* RSL_sweep_to_pgm */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_sweep_to_pgm(Sweep *s, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + if (s == NULL) return; + cart_image = RSL_sweep_to_cart(s, xdim, ydim, range); + RSL_write_pgm(outfile, cart_image, xdim, ydim); + free(cart_image); +} + +/**********************************************************************/ +/* */ +/* RSL_volume_to_gif */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_volume_to_gif(Volume *v, char *basename, int xdim, int ydim, float range) +{ +/* + * Make a xdim by ydim cartesean image. Center of radar is xdim/2,ydim/2. + */ + int i; + char outfile[100]; + unsigned char *cart_image; + + if (v == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } +/* + * Sweep 0 has Reflectivity only. + * Sweep 1 has Velocity and Spectrum width, No Reflectivity. + * Sweep > 1 any. + * + */ + for (i=0; ih.nsweeps; i++) { + (void)sprintf(outfile,"%s.%2.2d.gif", basename, i); /* File name: sweep.[0-10] */ + if (v->sweep[i] == NULL) continue; + cart_image = RSL_sweep_to_cart(v->sweep[i], xdim, ydim, range); + if (radar_verbose_flag) + fprintf(stderr,"==> Sweep %d of %d\n",i, v->h.nsweeps); + if (cart_image != NULL) { + RSL_write_gif(outfile, cart_image, xdim, ydim, color_table); + printf("%s\n", outfile); + free (cart_image); + } else { + if (radar_verbose_flag) + fprintf(stderr,"No image. cart_image for sweep %d is NULL.\n", i); + } + } +} + +/**********************************************************************/ +/* */ +/* RSL_volume_to_pict */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_volume_to_pict(Volume *v, char *basename, int xdim, int ydim, float range) +{ +/* + * Make a xdim by ydim cartesean image. Center of radar is xdim/2,ydim/2. + */ + int i; + char outfile[100]; + unsigned char *cart_image; + + if (v == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } +/* + * Sweep 0 has Reflectivity only. + * Sweep 1 has Velocity and Spectrum width, No Reflectivity. + * Sweep > 1 any. + * + */ + for (i=0; ih.nsweeps; i++) { + cart_image = RSL_sweep_to_cart(v->sweep[i], xdim, ydim, range); + if (radar_verbose_flag) + fprintf(stderr,"==> Sweep %d of %d\n",i, v->h.nsweeps); + (void)sprintf(outfile,"%s.%2.2d.pict", basename, i); /* File name: sweep.[0-10] */ + if (cart_image != NULL) { + RSL_write_pict(outfile, cart_image, xdim, ydim, color_table); + if (radar_verbose_flag) + fprintf(stderr,"Wrote: %s\n", outfile); + free (cart_image); + } else { + if (radar_verbose_flag) + fprintf(stderr,"No image. cart_image for sweep %d is NULL.\n", i); + } + } +} + +/**********************************************************************/ +/* */ +/* RSL_volume_to_ppm */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_volume_to_ppm(Volume *v, char *basename, int xdim, int ydim, float range) +{ +/* + * Make a xdim by ydim cartesean image. Center of radar is xdim/2,ydim/2. + */ + int i; + char outfile[100]; + unsigned char *cart_image; + + if (v == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } +/* + * Sweep 0 has Reflectivity only. + * Sweep 1 has Velocity and Spectrum width, No Reflectivity. + * Sweep > 1 any. + * + */ + for (i=0; ih.nsweeps; i++) { + cart_image = RSL_sweep_to_cart(v->sweep[i], xdim, ydim, range); + if (radar_verbose_flag) + fprintf(stderr,"==> Sweep %d of %d\n",i, v->h.nsweeps); + (void)sprintf(outfile,"%s.%2.2d.ppm", basename, i); /* File name: sweep.[0-10] */ + if (cart_image != NULL) { + RSL_write_ppm(outfile, cart_image, xdim, ydim, color_table); + if (radar_verbose_flag) + fprintf(stderr,"Wrote: %s\n", outfile); + free (cart_image); + } else { + if (radar_verbose_flag) + fprintf(stderr,"No image. cart_image for sweep %d is NULL.\n", i); + } + } +} +/**********************************************************************/ +/* */ +/* RSL_volume_to_pgm */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +void RSL_volume_to_pgm(Volume *v, char *basename, int xdim, int ydim, float range) +{ +/* + * Make a xdim by ydim cartesean image. Center of radar is xdim/2,ydim/2. + */ + int i; + char outfile[100]; + unsigned char *cart_image; + +/* + * Sweep 0 has Reflectivity only. + * Sweep 1 has Velocity and Spectrum width, No Reflectivity. + * Sweep > 1 any. + * + */ + if (v == NULL) return; + for (i=0; ih.nsweeps; i++) { + cart_image = RSL_sweep_to_cart(v->sweep[i], xdim, ydim, range); + if (radar_verbose_flag) + fprintf(stderr,"==> Sweep %d of %d\n",i, v->h.nsweeps); + (void)sprintf(outfile,"%s.%2.2d.pgm", basename, i); /* File name: sweep.[0-10] */ + if (cart_image != NULL) { + RSL_write_pgm(outfile, cart_image, xdim, ydim); + if (radar_verbose_flag) + fprintf(stderr,"Wrote: %s\n", outfile); + free (cart_image); + } else { + if (radar_verbose_flag) + fprintf(stderr,"No image. cart_image for sweep %d is NULL.\n", i); + } + } +} + + +/***********************************************************************/ +/* */ +/* RSL_rebin_velocity_ray */ +/* RSL_rebin_velocity_sweep */ +/* RSL_rebin_velocity_volume */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 30, 1994 */ +/* */ +/***********************************************************************/ +void RSL_rebin_velocity_ray(Ray *r) +{ + /* Rebin the velocity data to the range -nyquist, +nyquist. + * 14 bins are created centered at 0. It sets the proper color look up + * indexes. This function modifies Ray r. + */ + int i; + float nyquist; + float val /* val1 */; + + int ncbins = 15; /* Number of color bins */ + float (*f)(Range x); + Range (*invf)(float x); + + if (r == NULL) return; + + nyquist = r->h.nyq_vel; + if (nyquist == 0.0) { + fprintf(stderr, "RSL_rebin_velocity_ray: nyquist == 0.0\n"); + fprintf(stderr, "RSL_rebin_velocity_ray: Unable to rebin.\n"); + return; + } + f = r->h.f; + invf = r->h.invf; + for (i=0; ih.nbins; i++) { + val = f(r->range[i]); + if (val == RFVAL) { + val = 16; + } else if (val != BADVAL) { +/* + Okay, we want to shift the data to positive values + then we re-scale them by the number of color bins/nyquist +*/ + val = (int)(val/nyquist*(ncbins/2) + 1.0 + ncbins/2); + + } else { + val = 0; + } + + r->range[i] = invf(val); + } +} + + +void RSL_rebin_velocity_sweep(Sweep *s) +{ + /* Rebin the velocity data to the range -nyquist, +nyquist. + * 14 bins are created centered at 0. It sets the proper color look up + * indexes. This function modifies Sweep s. Use this function prior + * RSL_sweep_to_cart. The binning is done in RSL_rebin_velocity_ray. + */ + + int i; + + if (s == NULL) return; + + for (i=0; ih.nrays; i++) + RSL_rebin_velocity_ray(s->ray[i]); + +} + +void RSL_rebin_velocity_volume(Volume *v) +{ + /* Rebin the velocity data to the range -nyquist, +nyquist. + * 14 bins are created centered at 0. It sets the proper color look up + * indexes. This function modifies Volume v. Use this function prior + * RSL_sweep_to_cart. The binning is done in RSL_rebin_velocity_ray. + */ + + int i; + + if (v == NULL) return; + + for (i=0; ih.nsweeps; i++) + RSL_rebin_velocity_sweep(v->sweep[i]); + +} + + +/**********************************************************************/ +/* */ +/* RSL_carpi_to_cart */ +/* */ +/* Space Applications Corporation */ +/* 17 Mar 1997 */ +/**********************************************************************/ +unsigned char *RSL_carpi_to_cart(Carpi *carpi, int xdim, int ydim, float range) +{ + /* Converts carpi data from the native RSL 1_ or 2_byte format to + unsigned char format for image generation. Also reverses the + row order of the data so that displayed images come out right side up. + */ + int i, j, cart_index; + unsigned char *cart_image = NULL; + float val; + + if (carpi == NULL) return NULL; + cart_image = (unsigned char *) calloc(xdim*ydim, sizeof(unsigned char)); + + for (j=0; jf(carpi->data[j][i]); + if (val == BADVAL || val == NOTFOUND_V || val == NOTFOUND_H) + cart_image[cart_index] = (unsigned char) 0; + else if (val >= 0) + cart_image[cart_index] = (unsigned char) val; + else + cart_image[cart_index] = (unsigned char) (256+val); /*2's complement.*/ + } + return(cart_image); +} + +/**********************************************************************/ +/* */ +/* RSL_carpi_to_gif */ +/* */ +/* Space Applications Corporation */ +/* 17 Mar 1997 */ +/**********************************************************************/ +void RSL_carpi_to_gif(Carpi *carpi, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (carpi == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_carpi_to_cart(carpi, xdim, ydim, range); + RSL_write_gif(outfile, cart_image, xdim, ydim, color_table); + free(cart_image); +} + +/**********************************************************************/ +/* */ +/* RSL_carpi_to_pict */ +/* */ +/* Space Applications Corporation */ +/* 17 Mar 1997 */ +/**********************************************************************/ +void RSL_carpi_to_pict(Carpi *carpi, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (carpi == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_carpi_to_cart(carpi, xdim, ydim, range); + RSL_write_pict(outfile, cart_image, xdim, ydim, color_table); + free(cart_image); +} + +/**********************************************************************/ +/* */ +/* RSL_carpi_to_ppm */ +/* */ +/* Space Applications Corporation */ +/* 17 Mar 1997 */ +/**********************************************************************/ +void RSL_carpi_to_ppm(Carpi *carpi, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (carpi == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_carpi_to_cart(carpi, xdim, ydim, range); + RSL_write_ppm(outfile, cart_image, xdim, ydim, color_table); + free(cart_image); +} + +/**********************************************************************/ +/* */ +/* RSL_carpi_to_pgm */ +/* */ +/* Space Applications Corporation */ +/* 17 Mar 1997 */ +/**********************************************************************/ +void RSL_carpi_to_pgm(Carpi *carpi, char *outfile, int xdim, int ydim, float range) +{ + /* Currently range is not used. */ + unsigned char *cart_image; + + /* Assumes the color table is already loaded. */ + if (carpi == NULL) return; + if (ncolors == 0) { + fprintf(stderr, "No colors in color table. Load color table first.\n"); + return; + } + cart_image = RSL_carpi_to_cart(carpi, xdim, ydim, range); + RSL_write_pgm(outfile, cart_image, xdim, ydim); + free(cart_image); +} + +/**********************************************************************/ +/* RSL_rebin_volume */ +/* More generic version of RSL_rebin_velocity. Allows for centering */ +/* +/- field like zdr or vel around zero. Width is the 1/2 width of */ +/* what is to be centered; e.g., +/- 5, width=5. */ +/* Space Applications Corporation */ +/* July 13, 1997 */ +/**********************************************************************/ +void RSL_rebin_ray(Ray *r, int width) +{ + int i; + float nyquist, val; + int ncbins = 15; /* Number of color bins */ + float (*f)(Range x); + Range (*invf)(float x); + + if (r == NULL) return; + + nyquist = width; + if (nyquist == 0.0) { + fprintf(stderr, "RSL_rebin_ray: nyquist == 0.0\n"); + fprintf(stderr, "RSL_rebin_ray: Unable to rebin.\n"); + return; + } + f = r->h.f; + invf = r->h.invf; + for (i=0; ih.nbins; i++) { + val = f(r->range[i]); + if (val == width+1) { + val = ncbins + 1; + } else if (val != BADVAL) { +/* + Okay, we want to shift the data to positive values + then we re-scale them by the number of color bins/nyquist +*/ + val = (int)(val/nyquist*(ncbins/2) + 1.0 + ncbins/2); + } else { + val = 0; + } + + r->range[i] = invf(val); + } +} + +void RSL_rebin_sweep(Sweep *s, int width) +{ + int i; + if (s == NULL) return; + for (i=0; ih.nrays; i++) + RSL_rebin_ray(s->ray[i], width); +} + +void RSL_rebin_volume(Volume *v, int width) +{ + int i; + if (v == NULL) return; + for (i=0; ih.nsweeps; i++) + RSL_rebin_sweep(v->sweep[i], width); +} + +/**********************************************************************/ +/* */ +/* RSL_rebin_zdr_volume, _sweep, _ray */ +/* */ +/* Space Applications Corporation */ +/**********************************************************************/ +/* + Maps valid zdr values from the real set [-6.0, 10.0] onto the set of + integers {0, 1, 2, ..., 35}, which forms the set of indices into + the zdr color table. Used in conjunction with gif image generation + of zdr sweeps. + + Color coding: + ------------- + -6.0 <= zdr < -4.0 --> black + -4.0 <= zdr < -2.0 --> gray + -2.0 <= zdr < 0.0 --> blue + 0.0 <= zdr < 2.0 --> green + 2.0 <= zdr < 4.0 --> orange + 4.0 <= zdr < 6.0 --> red + 6.0 <= zdr < 8.0 --> pink + 8.0 <= zdr < 10.0 --> white + + Space Applications Corporation + July 13, 1997 +*/ + +void RSL_rebin_zdr_ray(Ray *r) +{ + int i; + float val; + float (*f)(Range x); + Range (*invf)(float x); + + if (r == NULL) return; + f = r->h.f; + invf = r->h.invf; + for (i=0; ih.nbins; i++) + { + val = f(r->range[i]); + if ((val >= -6.0) && (val < 8.4)) val = (floor) ((val + 6.0) * 2.5); + else if (val < 10.0) val = 35.0; /* Make all these white. */ + else val = 0; /* invalid zdr value */ + r->range[i] = invf(val); + } +} + +void RSL_rebin_zdr_sweep(Sweep *s) +{ + int i; + if (s == NULL) return; + for (i=0; ih.nrays; i++) RSL_rebin_zdr_ray(s->ray[i]); +} + +void RSL_rebin_zdr_volume(Volume *v) +{ + int i; + if (v == NULL) return; + for (i=0; ih.nsweeps; i++) RSL_rebin_zdr_sweep(v->sweep[i]); +} diff --git a/interp.c b/interp.c new file mode 100644 index 0000000..45d349a --- /dev/null +++ b/interp.c @@ -0,0 +1,436 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996 Dennis F. Flanigan Jr. of Applied Research Corporation, + Landover, Maryland, a NASA/GSFC on-site contractor. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * Interpolation functions + * + * Dennis Flanigan, Jr. + * + * 7/7/95 + * Finished testing interpolation routine. + * + * 7/6/95 + * Finished up bilinear interpolation routine. + * Routine calculates values using four surrounding + * values with the same slant range. + * + * 6/29/95 + * Added bilinear interpolation value routine. Rewrote + * get_surrounding sweeps so that it returns Sweeps instead of + * Sweep indexes. + * + * 6/28/95 + * Added internal ray searching routine. Replaces + * RSL_get_next_closest_ray. + * + * 6/25/95 + * Added internal sweep searching routine designed for use + * by interpolation routines. Replaced RSL_get_next_closest_sweep. + * + * 6/23/95 + * This file was created. Started adding internal routines + * needed for calculating distences between two points + * in space. + */ + +#include +#include +#include "rsl.h" + + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +extern double hypot(double, double); + +/***************************************************/ +/* */ +/* get_xyz_coord */ +/* */ +/* */ +/***************************************************/ +void get_xyz_coord(double *x,double *y,double *z, + double range,double azim,double elev) + { + /* Return x,y,z coordinates given range, azimuth angle and + * elevation angle. Memory allocation for x,y and z are + * not provided by this routine! + */ + double azim_rad,elev_rad; + +# define M_PI 3.14159265358979323846 + azim_rad = azim * M_PI / 180.0; + elev_rad = elev * M_PI / 180.0; + + *x = cos(elev_rad) * cos(azim_rad) * range; + *y = cos(elev_rad) * sin(azim_rad) * range; + *z = sin(elev_rad) * range; + } + +/***************************************************/ +/* */ +/* get_dist */ +/* */ +/* */ +/***************************************************/ +float get_dist(float r1,float a1,float e1, + float r2,float a2,float e2) + { + /* Give two points described by range, azimuth angle + * and elevation angle, return the distence between + * the two. + */ + double x1,y1,z1,x2,y2,z2; + + get_xyz_coord(&x1,&y1,&z1,(double)r1,(double)a1,(double)e1); + get_xyz_coord(&x2,&y2,&z2,(double)r2,(double)a2,(double)e2); + + return (float) sqrt(pow(x1 - x2,2) + pow(y1 - y2,2) + pow(z1 - z2,2)); + } + +/***************************************************/ +/* */ +/* get_surrounding_sweeps */ +/* */ +/* */ +/***************************************************/ +void get_surrounding_sweep(Sweep **below,Sweep **above, Volume *v, + float elev) + { + /* Return the pointers of the sweeps that are above and + * and below the elevation angle in the parameter list. + * + * Assume at least one non-NULL sweep exist in Volume. + * + * A value of NULL is set to above or below in cases + * where there is no sweep above or below. + */ + int a; + + /* look for above index first */ + a = 0; + while(a < v->h.nsweeps) + { + if(v->sweep[a] != NULL) + { + if(v->sweep[a]->h.elev >= elev) + { + *above = v->sweep[a]; + break; + } + } + a++; + } + + /* Was above ever set ? + * If not, set above to counter. + */ + if(a == v->h.nsweeps) + { + *above = NULL; + } + + /* Look for index just below elev */ + a--; + while(a >= 0) + { + if(v->sweep[a] != NULL) + { + if(v->sweep[a]->h.elev <= elev) + { + *below = v->sweep[a]; + break; + } + } + a--; + } + + /* Was a below found ? */ + if (a == -1) + { + *below = NULL; + } + + /* Bye */ + } + +/****************************************** + * * + * dir_angle_diff * + * * + * Dennis Flanigan,Jr. 4/29/95 * + ******************************************/ +double dir_angle_diff(float x,float y) + { + /* returns difference between angles x and y. Returns + * positive value if y > x, negitive value if + * y < x. + * + */ + double d; + d = (double)(y - x); + + while (d >= 180) d = -1 * (360 - d); + while (d < -180) d = (360 + d); + + return d; + } + +/***************************************************/ +/* */ +/* get_surrounding_rays */ +/* */ +/* */ +/***************************************************/ +void get_surrounding_ray(Ray **ccwise,Ray **cwise,Sweep *s, + float ray_angle) + { + /* Return the pointers to the rays that are counterclockwise + * and clockwise to the ray_angle in the parameter list. + * Memory space for the variables ccwise and cwise + * is not allocated by this routine. + * + * Assume at least two rays exist and that a hash + * table has been created. + * + * Will need to add test for first ray and last + * ray if this routine is going to be used for + * RHI scans. + */ + int hindex; + double close_diff; + Hash_table *hash_table; + + Azimuth_hash *closest; + + /* Find hash index close to hindex we want. This will + * used as a starting point for a search to the closest + * ray. + */ + hash_table = hash_table_for_sweep(s); + if (hash_table == NULL) return; /* Nada. */ + + hindex = hash_bin(hash_table,ray_angle); + + /* Find hash entry with closest Ray */ + closest = the_closest_hash(hash_table->indexes[hindex],ray_angle); + + close_diff = dir_angle_diff(ray_angle,closest->ray->h.azimuth); + + if(close_diff < 0) + { + /* Closest ray is counterclockwise to ray_angle */ + *ccwise = closest->ray; + *cwise = closest->ray_high->ray; + } + else + { + /* Closest ray is clockwise to ray_angle. */ + *cwise = closest->ray; + *ccwise = closest->ray_low->ray; + } + + } + +/***************************************************/ +/* */ +/* from_dB, to_dB */ +/* */ +/***************************************************/ +double from_dB(double db) + { + return pow(10,db/10.0); + } + +double to_dB(double value) + { + return 10.0 * log10(value); + } + +/***************************************************/ +/* */ +/* get_linear_value_from_sweep */ +/* */ +/***************************************************/ +double get_linear_value_from_sweep(Sweep *sweep,float srange,float azim, + float limit) + { + float ccw_db_value,cw_db_value; + double ccw_value,cw_value,value; + double delta_angle; + Ray *ccw_ray,*cw_ray; + + get_surrounding_ray(&ccw_ray,&cw_ray,sweep,azim); + + /* Assume that ccw_ray and cw_ray will be non_NULL */ + + if((azim - ccw_ray->h.azimuth) > limit) + { + ccw_value = -1; + } + else + { + ccw_db_value = RSL_get_value_from_ray(ccw_ray,srange); + + /* Check to make sure this is a valid value */ + if (ccw_db_value == BADVAL) + { + ccw_value = 0; + } + else + { + ccw_value = from_dB(ccw_db_value); + } + } + + if((cw_ray->h.azimuth - azim) > limit) + { + cw_value = -1; + } + else + { + cw_db_value = RSL_get_value_from_ray(cw_ray,srange); + /* Check to make sure this is a valid value */ + if (cw_db_value == BADVAL) + { + cw_value = 0; + } + else + { + cw_value = from_dB(cw_db_value); + } + } + + if((cw_value != -1) && (ccw_value != -1)) + { + /* Both the clockwise ray and the counterclockwise + * ray is valid. + */ + delta_angle = angle_diff(ccw_ray->h.azimuth,cw_ray->h.azimuth); + + value=((angle_diff(azim,cw_ray->h.azimuth)/delta_angle)*ccw_value) + + ((angle_diff(azim,ccw_ray->h.azimuth)/delta_angle) * cw_value); + } + else if((cw_value == -1) && (ccw_value == -1)) + { + /* Neither ray is valid. */ + value = -1; + } + else if(cw_value != -1) + { + /* cw_ray is only ray that is within limit. */ + value = cw_value; + } + else + { + /* ccw_ray is only ray that is within limit. */ + value = ccw_value; + } + + return value; + } + +/***************************************************/ +/* */ +/* RSL_get_linear_value */ +/* */ +/* */ +/***************************************************/ +float RSL_get_linear_value(Volume *v,float srange,float azim, + float elev,float limit) + { + /* Compute bilinear value from four surrounding values + * in Volume v. The four surrounding values + * are at a constant range. + * + * Limit is an angle used only to reject values + * in the azimuth plane. + */ + float db_value; + double value = 0; + double up_value, down_value; + double delta_angle; + Sweep *up_sweep,*down_sweep; + + get_surrounding_sweep(&down_sweep,&up_sweep,v,elev); + + /* Calculate interpolated value in sweep above + * requested point. + */ + if(up_sweep == NULL) + { + up_value = -1; + } + else + { + up_value = get_linear_value_from_sweep(up_sweep,srange,azim,limit); + } + + /* Calculate interpolated value in sweep below requested point. + */ + if(down_sweep == NULL) + { + down_value = -1; + } + else + { + down_value = get_linear_value_from_sweep(down_sweep,srange,azim,limit); + } + /* Using the interpolated values calculated at the elevation + * angles in the above and below sweeps, interpolate a value + * for the elvation angle at the requested point. + */ + if((up_value != -1) && (down_value != -1)) + { + delta_angle = angle_diff(up_sweep->h.elev,down_sweep->h.elev); + + value =((angle_diff(elev,up_sweep->h.elev)/delta_angle) * down_value) + + ((angle_diff(elev,down_sweep->h.elev)/delta_angle) * up_value); + } + else if((up_value == -1) && (down_value == -1)) + { + value = -1; + } + else if(up_value != -1) + { + value = up_value; + } + else + { + value = down_value; + } + + /* Convert back to dB value and return. */ + if(value > 0) + { + db_value = (float)to_dB(value); + return db_value; + } + else + { + return BADVAL; + } + } + diff --git a/lassen.c b/lassen.c new file mode 100644 index 0000000..dc8cd16 --- /dev/null +++ b/lassen.c @@ -0,0 +1,523 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LASSEN +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/*---------------------------------------------------------------------- + * PURPOSE: + * + * Ingest a Lassen file and fill the Lassen_volume data structure. + * It can handle version 1.3 and 1.4 files (MCTEX data). + * + * The algorthm is pretty simple, call an 'xdr' routine each time for + * each and every member of Lassen_volume and all substructures. + * + * The order and type of xdr routine called defines the file organization. + *---------------------------------------------------------------------- + */ +#include +#include +#include +#include +#include +#include "lassen.h" + +/* xdr_destroy is broken on HPUX, SGI, and SUN; Linux, the only working one? */ +/* This broken behavior could be from old xdr versions, too. */ +#undef BROKEN_XDR_DESTROY +#if defined(__hpux) || defined(__sgi) || defined(__sun) +#define BROKEN_XDR_DESTROY +#endif +/*************************************************************/ +/* */ +/* read_lassen_head */ +/* */ +/*************************************************************/ +int read_lassen_head(FILE *f, Lassen_head *head) +{ + int rc=1, i; + char *tmp; + XDR xdrs; + + memset(head->magic, 0, sizeof(head->magic)); + + xdrstdio_create(&xdrs, f, XDR_DECODE); + + /* + * Can I read the first string? If not, then this is probably + * not a valid header. If this happens, then return. + */ + tmp=head->magic; + if((rc &= xdr_string(&xdrs, &tmp, 8))==0) { +#ifndef BROKEN_XDR_DESTROY + xdr_destroy(&xdrs); +#endif + return(0); + } + rc &= xdr_u_char(&xdrs, &head->mdate.year); + rc &= xdr_u_char(&xdrs, &head->mdate.month); + rc &= xdr_u_char(&xdrs, &head->mdate.day); + rc &= xdr_u_char(&xdrs, &head->mdate.hour); + rc &= xdr_u_char(&xdrs, &head->mdate.minute); + rc &= xdr_u_char(&xdrs, &head->mdate.second); + rc &= xdr_u_char(&xdrs, &head->cdate.year); + rc &= xdr_u_char(&xdrs, &head->cdate.month); + rc &= xdr_u_char(&xdrs, &head->cdate.day); + rc &= xdr_u_char(&xdrs, &head->cdate.hour); + rc &= xdr_u_char(&xdrs, &head->cdate.minute); + rc &= xdr_u_char(&xdrs, &head->cdate.second); + rc &= xdr_int(&xdrs, &head->type); + tmp=head->mwho; + rc &= xdr_string(&xdrs, &tmp, 16); + tmp=head->cwho; + rc &= xdr_string(&xdrs, &tmp, 16); + rc &= xdr_int(&xdrs, &head->protection); + rc &= xdr_int(&xdrs, &head->checksum); + tmp=head->description; + rc &= xdr_string(&xdrs, &tmp, 40); + rc &= xdr_int(&xdrs, &head->id); + for(i=0;i<12;i++) + rc &= xdr_int(&xdrs, &head->spare[i]); + +#ifndef BROKEN_XDR_DESTROY + xdr_destroy(&xdrs); +#endif + + return rc; +} + +/*************************************************************/ +/* */ +/* free_lassen_volume */ +/* */ +/*************************************************************/ + +void free_lassen_volume(Lassen_volume *vol) +{ + int i,j; + + if (vol == NULL) return; + for(i=0; inumsweeps; i++ ) { + if(vol->index[i] == NULL) continue; + for(j=0; jindex[i]->numrays; j++ ) + if (vol->index[i]->ray[j] != NULL) + free( vol->index[i]->ray[j] ); + free( vol->index[i] ); + } + free( vol ); + return; +} + +static void short_shift(unsigned short *n) +{ + *n = ntohs(*n); +} + +/*************************************************************/ +/* */ +/* read_lassen_volume */ +/* */ +/*************************************************************/ +int read_lassen_volume( XDR *xdr, Lassen_volume *vol) +{ + int i,j; + int rc = TRUE; + char *tmp; + unsigned short ushort_tmp; + + /* Read the version number. */ + rc &= xdr_u_short(xdr, &vol->version); + + /* + * Currently, Version 1.3 and 1.4 seem to be the same on disk. + * I have no doc's. The only thing that I know of to be different + * is how the ray azimuth angles are calculated. For MCTEX data, + * this is time dependant. The correction will happen in the + * application; after RSL_lassen_to_radar is called, for example. + * + * Version 1.3 is coded as 13 and version 1.4 is coded as 14. + */ + if( (int)vol->version != 13 && (int)vol->version != 14 ) { + (void)fprintf(stderr, "Incompatible version of LASSEN file.\n" ); + (void)fprintf(stderr, "File version: %d.%d\n", + (int)vol->version/10, (int)vol->version%10); + return( 0 ); + } + + /* Read in the Lassen_volume. */ + rc &= xdr_short(xdr, &vol->filled); + rc &= xdr_u_int(xdr, &vol->volume); + rc &= xdr_u_short(xdr, &vol->sweep); + rc &= xdr_u_short(xdr, &vol->sweep_type); + rc &= xdr_u_short(xdr, &vol->max_height); + rc &= xdr_u_short(xdr, &vol->status); + rc &= xdr_u_short(xdr, &vol->min_fangle); + rc &= xdr_u_short(xdr, &vol->max_fangle); + rc &= xdr_u_short(xdr, &vol->min_var); + rc &= xdr_u_short(xdr, &vol->max_var); + rc &= xdr_u_short(xdr, &vol->a_start); + rc &= xdr_u_short(xdr, &vol->a_stop); + rc &= xdr_u_short(xdr, &vol->numsweeps); + for(i=0;ifangles[i]); + rc &= xdr_u_short(xdr, &vol->gatewid); + rc &= xdr_u_short(xdr, &vol->rangeg1); + for(i=0;inumgates[i]); + rc &= xdr_u_short(xdr, &vol->maxgates); + rc &= xdr_u_short(xdr, &ushort_tmp); + rc &= xdr_u_short(xdr, &ushort_tmp); + rc &= xdr_u_short(xdr, &ushort_tmp); + rc &= xdr_u_short(xdr, &ushort_tmp); + rc &= xdr_u_short(xdr, &vol->prf); + rc &= xdr_u_short(xdr, &vol->prflow); + rc &= xdr_u_int(xdr, &vol->freq); + rc &= xdr_u_short(xdr, &vol->n_pulses); + + for(i=0;ioffset[i][j]); + + rc &= xdr_u_char(xdr, &vol->year); + rc &= xdr_u_char(xdr, &vol->month); + rc &= xdr_u_char(xdr, &vol->day); + rc &= xdr_u_char(xdr, &vol->shour); + rc &= xdr_u_char(xdr, &vol->sminute); + rc &= xdr_u_char(xdr, &vol->ssecond); + rc &= xdr_u_char(xdr, &vol->ehour); + rc &= xdr_u_char(xdr, &vol->eminute); + rc &= xdr_u_char(xdr, &vol->esecond); + /* The flags use bits. The data type length is short; I expect. */ + rc &= xdr_u_short(xdr, (unsigned short *)&vol->volflags); + short_shift((unsigned short *)&vol->volflags); + /* This is radar info. */ + tmp=vol->radinfo.radar_name; + rc &= xdr_string(xdr, &tmp, 8); + tmp=vol->radinfo.site_name; + rc &= xdr_string(xdr, &tmp, 8); + rc &= xdr_u_short(xdr, &vol->radinfo.antenna_height); + rc &= xdr_short(xdr, &vol->radinfo.latitude.degree); + rc &= xdr_short(xdr, &vol->radinfo.latitude.minute); + rc &= xdr_short(xdr, &vol->radinfo.latitude.second); + rc &= xdr_short(xdr, &vol->radinfo.longitude.degree); + rc &= xdr_short(xdr, &vol->radinfo.longitude.minute); + rc &= xdr_short(xdr, &vol->radinfo.longitude.second); + + /* + * The return value is the logical and of all the xdr reads. + */ + return( rc ); +} + +/*************************************************************/ +/* */ +/* read_lassen_ray */ +/* */ +/*************************************************************/ +int read_lassen_ray(XDR *xdr, Lassen_ray *ray ) +{ + int i, rc = 1; + + /* Read in Lassen_ray */ + rc &= xdr_u_short( xdr, &ray->vangle); + rc &= xdr_u_short( xdr, &ray->fanglet); + rc &= xdr_u_short( xdr, &ray->fanglea); + rc &= xdr_u_short( xdr, &ray->a_start); + rc &= xdr_u_short( xdr, &ray->a_stop); + rc &= xdr_u_char( xdr, &ray->max_height); + rc &= xdr_u_char( xdr, &ray->volume); + rc &= xdr_u_char( xdr, &ray->sweep); + rc &= xdr_u_char( xdr, &ray->sweep_type); + rc &= xdr_u_short( xdr, &ray->gatewid); + rc &= xdr_u_short( xdr, &ray->rangeg1); + rc &= xdr_u_short( xdr, &ray->numgates); + rc &= xdr_u_short( xdr, &ray->prf); + rc &= xdr_u_short( xdr, &ray->prflow); + rc &= xdr_u_short( xdr, &ray->n_pulses); + rc &= xdr_u_char( xdr, &ray->p_width); + rc &= xdr_u_char( xdr, &ray->cfilter); + rc &= xdr_u_short( xdr, &ray->status); + memset(&ray->flags, 0, 4); + /* I expect the length of the bit field to be a 'short', never 'long' */ + rc &= xdr_u_short( xdr, (unsigned short *)&ray->flags); /* a bit field */ + short_shift((unsigned short *)&ray->flags); + /* + fprintf(stderr, "short_shift: flags = %x\n", ray->flags); + fprintf(stderr, "packed = %d", (int)ray->flags.packed); + fprintf(stderr, "good_data = %d", (int)ray->flags.good_data); + fprintf(stderr, "uz = %d", (int)ray->flags.uz); + fprintf(stderr, "cz = %d", (int)ray->flags.cz); + fprintf(stderr, "vel= %d", (int)ray->flags.vel); + fprintf(stderr, "wid= %d", (int)ray->flags.wid); + fprintf(stderr, "zdr= %d", (int)ray->flags.zdr); + fprintf(stderr, "phi= %d", (int)ray->flags.phi); + fprintf(stderr, "rho= %d", (int)ray->flags.rho); + fprintf(stderr, "ldr= %d", (int)ray->flags.ldr); + fprintf(stderr, "kdp= %d", (int)ray->flags.kdp); + fprintf(stderr, "tim= %d", (int)ray->flags.time); + fprintf(stderr, "spa= %x", (int)ray->flags.spares); + */ + for(i=0;ioffset[i]); + + rc &= xdr_u_char( xdr, &ray->year); + rc &= xdr_u_char( xdr, &ray->month); + rc &= xdr_u_char( xdr, &ray->day); + rc &= xdr_u_char( xdr, &ray->hour); + rc &= xdr_u_char( xdr, &ray->minute); + rc &= xdr_u_char( xdr, &ray->second); + + return rc; +} + + +/*************************************************************/ +/* */ +/* read_entire_lassen_file */ +/* */ +/*************************************************************/ +int read_entire_lassen_file(FILE *f, Lassen_volume *vol) +{ + Lassen_sweep *sweep; + int i; + XDR xdr; + Lassen_ray ray; + Lassen_head head; + int isweep = (-99); + int lastray=0,numrays=0, rc; + unsigned int size; + int tbytes = 0; + unsigned char *p; + + + /* Skip the header. */ + read_lassen_head(f, &head); + + /* Connect to the XDR stream. */ + xdrstdio_create(&xdr, f, XDR_DECODE); + + /* Check the volume header. Is the version is correct? */ + if( read_lassen_volume( &xdr, vol ) == 0) { +#ifndef BROKEN_XDR_DESTROY + xdr_destroy(&xdr); +#endif + return( 0 ); + } + + rc = TRUE; + + /* Read until XDR error. */ + while(rc == TRUE) { + + /* + * Read in the ray header. If there is an error in reading + * in the ray header, then make sure the rc value is + * set to 0. + */ + if( read_lassen_ray( &xdr, &ray ) == 0 ) + break; + + if( (short)ANGLE_CONVERT(ray.vangle) < 0 || + (short)ANGLE_CONVERT(ray.vangle) > 360 ) { + fprintf(stderr, "read_entire_lassen_file: angle out of range (%d)\n", + ANGLE_CONVERT(ray.vangle)); + rc = 0; + break; + } + + if(ray.volume != (vol->volume&0x00ff)) { + fprintf(stderr, "read_entire_lassen_file: Volume serial number out of sync:\n"); + fprintf(stderr, " Ray->volume = %u, Should be %u\n", + ray.volume, (unsigned char)vol->volume&0x00ff ); + fprintf(stderr, " (Ray->volume == Vol->volume(%d) & 0x00ff)\n", + vol->volume ); + if(isweep == -99) rc = 0; + break; + } + + /* + * If we have a new sweep, then create + * the new sweep data structure. The 'isweep' + * contains the offset number in the volume. 'ray.sweep' + * has the sweep number. + */ + if((ray.sweep-1) != isweep) { + if(ray.sweep == 0) { + fprintf(stderr,"Sweep number in a ray is 0!\n"); + fprintf(stderr,"Aborting read_entire_lassen_file()\n"); +#ifndef BROKEN_XDR_DESTROY + xdr_destroy(&xdr); +#endif + rc = 0; + break; + } + + + isweep = ray.sweep-1; + + if(isweep > 0) { + /* Reset the last ray when passing 2 pi. */ + lastray--; + if( lastray < 0 ) lastray = 359; + + sweep = vol->index[isweep-1]; + if (sweep == NULL) { + rc = 0; + fprintf(stderr, "vol->index[%d] is NULL.\n", isweep-1); + break; + } + sweep->ehour = sweep->ray[lastray]->hour; + sweep->eminute = sweep->ray[lastray]->minute; + sweep->esecond = sweep->ray[lastray]->second; + sweep->numrays = numrays; + sweep->max_var = sweep->ray[lastray]->vangle; + + } + + /* We have a new sweep. */ + if((vol->index[isweep] = (Lassen_sweep *)calloc + (1,sizeof(Lassen_sweep))) == 0) { + perror("read_entire_lassen_file"); + rc = 0; + break; + } + + lastray = 0; + + /* Copy to the Sweep. */ + sweep = vol->index[isweep]; + sweep->sweep = isweep; + sweep->shour = ray.hour; + sweep->sminute = ray.minute; + sweep->ssecond = ray.second; + sweep->volume = ray.volume; + sweep->sweep = ray.sweep; + sweep->sweep_type = ray.sweep_type; + sweep->max_height = ray.max_height; + sweep->fangle = ray.fanglet; + sweep->a_start = ray.a_start; + sweep->a_stop = ray.a_stop; + sweep->gatewid = ray.gatewid; + sweep->rangeg1 = ray.rangeg1; + sweep->numgates = ray.numgates; + sweep->prf = ray.prf; + sweep->prflow = ray.prflow; + sweep->n_pulses = ray.n_pulses; + sweep->p_width = ray.p_width; + sweep->cfilter = ray.cfilter; + for(i=0; ioffset[i] = ray.offset[i]; + sweep->year = ray.year; + sweep->month = ray.month; + sweep->day = ray.day; + sweep->min_var = ray.vangle; + + numrays = 0; + } + + /* + * If everything is ok, then add the ray to the + * volume. + */ + numrays++; + vol->index[isweep]->status |= ray.status; + + /* Determine the 'size' of the ray and allocate memory. */ + size = 0; + /* fprintf(stderr,"\nOFFSETS (%d):", NUMOFFSETS); */ + for(i=0; iindex[isweep]->ray[lastray] = + (Lassen_ray *) calloc(1,sizeof(Lassen_ray)+size))==0) { + perror("read_entire_lassen_file"); + rc = 0; +#ifndef BROKEN_XDR_DESTROY + xdr_destroy(&xdr); +#endif + break; + } + + + p = (unsigned char *)vol->index[isweep]->ray[lastray]; + + /* Copy the ray header. */ + memcpy(p, &ray, sizeof(Lassen_ray)); + p = (unsigned char *)p + sizeof(Lassen_ray); + + /* Read the data. */ + /* printf("Previous rc=%d ... ", rc); */ + rc &= xdr_bytes(&xdr, (char **)&p, &size,size); + tbytes += size; + /* printf("after rc=%d. xdr_bytes %d bytes, tbytes %d.\n", rc, size, tbytes); + */ + lastray++; + if(lastray > 359) lastray = 0; + } /* End while. */ + + if(rc == 0) { + /* Clean up and get out. */ + free_lassen_volume(vol); +#ifndef BROKEN_XDR_DESTROY + xdr_destroy(&xdr); +#endif + fprintf(stderr,"\tAborting read_entire_lassen_file.\n\n"); + return(0); + } + + /* + * Check to see if we read a sweep! + */ + if( isweep == -99 ) + vol->filled = -1; + else { + lastray--; + if( lastray < 0 ) lastray = 359; + + /* Update the last sweep. */ + sweep = vol->index[isweep]; + sweep->ehour = sweep->ray[lastray]->hour; + sweep->eminute = sweep->ray[lastray]->minute; + sweep->esecond = sweep->ray[lastray]->second; + sweep->max_var = ray.vangle; + sweep->numrays = numrays; + vol->filled = 1; + } + + /* Check the number of tilts read vs. the number in the file. */ + if(vol->numsweeps != isweep+1) { + fprintf(stderr, "read_entire_lassen_file: Warning, read error. The number of sweeps "); + fprintf(stderr, "detected is different from the number written."); + } + + vol->numsweeps = isweep+1; + +#ifndef BROKEN_XDR_DESTROY + xdr_destroy(&xdr); +#endif + return( 1 ); +} +#endif diff --git a/lassen.h b/lassen.h new file mode 100644 index 0000000..8f3f373 --- /dev/null +++ b/lassen.h @@ -0,0 +1,299 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996 John H. Merritt of Applied Research Corporation, + Landover, Maryland, a NASA/GSFC on-site contractor. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _lassen_h_ +#define _lassen_h_ + +typedef struct { + short degree; /* Geographic position: lat or lon */ + short minute; /* + above equator, - below, */ + short second; /* - Western hemi, + Eastern hemi. */ + short spare; +} Lassen_radar_position; + +typedef struct { + char radar_name[8]; /* Radar name. */ + char site_name[8]; /* Site name. */ + unsigned short antenna_height;/* In meters above sea level. */ + unsigned short spare; + Lassen_radar_position latitude; /* Latitude or radar */ + Lassen_radar_position longitude; /* Longitude of radar.*/ +} Lassen_radar_info; + +/* This is for Lassen files version 1.3 (coded as 13) and + * files version 1.4 (coded 14) + */ + +/* The maximum number of offsets is 10. The LASSEN file will + * have written data (space) for all 10 fields even when there is no field. + */ +#define NUMOFFSETS 10 +#define OFF_UZ 0 +#define OFF_CZ 1 +#define OFF_VEL 2 +#define OFF_WID 3 +#define OFF_ZDR 4 +#define OFF_PHI 5 +#define OFF_RHO 6 +#define OFF_LDR 7 +#define OFF_KDP 8 +#define OFF_TIME 9 + +/* This is absolute and cannot be changed. The LASSEN file is + * written with this number specified. It is used during the + * XDR decode process. + */ +#define LASSEN_MAX_SWEEPS 30 + +/* Sweep types (modes) are: + * POINT = 0 + * PPI = 1 + * RHI = 2 + * SECTOR= 3 + * + * STOP = 7 - Flag the end of the scan mode. + */ + +/* + * The Lassen_ray: + * + * The Lassen_sweep contains 360 pointers to Lassen_rays. + * Each Lassen_ray is dynamically allocated and the pointer inserted + * into the Lassen_sweep. The 'offsets' array contains indexes to + * the field type. When an index value is 0, then there is no data + * available for that field type. The order hard-coded and matches + * the order given by OFF_* variables in the #define above. Checking + * for a non-zero index value seems to be the most reliable method + * to determine the existance of a field type. Using 'flags' is + * problematic when there is no field of that type (ie. you get a + * false positive). + * + * Use the 'offset' array to jump to the field type. + * + */ +typedef struct { + unsigned short vangle; /* Azimuth angle. */ + unsigned short fanglet; /* Target fixed angle. */ + unsigned short fanglea; /* Actual fixed angle. */ + unsigned short a_start; /* Azimuth angle start. */ + unsigned short a_stop; /* Azimuth angle stop. */ + unsigned short status; /* Hardware status word. */ + unsigned char max_height;/* Maximum height, km. */ + unsigned char volume; /* Volume serial number. */ + unsigned char sweep; /* Sweep number 1..LASSEN_MAX_SWEEPS */ + unsigned char sweep_type;/* Sweep type. */ + unsigned short gatewid; /* Gate width, meters. */ + unsigned short rangeg1; /* Range to gate 1, meters. */ + unsigned short numgates; /* Number of gates. */ + unsigned short prf; /* Primary prf, hz. */ + unsigned short prflow; /* Secondary prf, hz. */ + unsigned short n_pulses; /* Sample size in pulses. */ + unsigned char p_width; /* Pulse width, .05 us units.*/ + unsigned char cfilter; /* Clutter filter code. */ + unsigned char spare[2]; + + /* + * Like I said before, don't trust these values. Trust + * the 'offset' instead -- offset in the ray. + */ + + /* flags is 'short' -- I hope it never becomes 'long' */ + struct { + unsigned int packed : 1; /* Is the data packed? */ + unsigned int good_data : 1; /* Is the data good? */ + unsigned int uz : 1; /* UZ present. */ + unsigned int cz : 1; /* CZ present. */ + unsigned int vel : 1; /* VEL present. */ + unsigned int wid : 1; /* WID present. */ + unsigned int zdr : 1; /* ZDR present. */ + unsigned int phi : 1; /* PHI present. */ + unsigned int rho : 1; /* RHO present. */ + unsigned int ldr : 1; /* LDR present. */ + unsigned int kdp : 1; /* KDP present. */ + unsigned int time : 1; /* TIME series present. */ + unsigned int spares : 4; + } flags; + + + /* + * Here is where you get to the data for a field type. + * If offset[OFF_CZ] is non-zero, for instance, then + * CZ exists and is located that many bytes into + * the data array. The data array is in the ray pointer + * which is in the Lassen_sweep. + */ + unsigned short offset[NUMOFFSETS]; + + unsigned char year; /* year-1900 */ + unsigned char month; /* month 1-12 */ + unsigned char day; /* day 1-31 */ + unsigned char hour; /* hour 0-23 */ + unsigned char minute; /* minute 0-59 */ + unsigned char second; /* second 0-59 */ + unsigned char spare2[2]; +} Lassen_ray; + +/* + * The Lassen_sweep: + * + * This structure contains information for an entire sweep for a possible + * 360 rays. These will be pointers to Lassen_ray. + * The Lassen_volume may have up to 30 pointers to Lassen_sweep. + * The '30' is mandatory and not adjustable because of how the LASSEN + * file is written. The LASSEN file writes 30 angles, gates, and + * 300 offset values (30*NUMOFFSETS). LASSEN_MAX_SWEEPS = 30. + * The number of rays in a Lassen_sweep is 'numrays'. + * + * The 'offset' is copied from the one in Lassen_ray. + */ +typedef struct { + unsigned short volume; /* Volume serial number. */ + unsigned short sweep; /* Sweep index. */ + unsigned short sweep_type; /* Sweep type code. */ + unsigned short max_height; /* Maximum height, km. */ + + unsigned short fangle; /* Fixed, azimuth angle. */ + unsigned short min_var; /* 'leftmost' variable angle. */ + unsigned short max_var; /* 'rightmost' variable angle. */ + unsigned short a_start; /* Azimuth angle start. */ + unsigned short a_stop; /* Azimuth angle stop. */ + + unsigned short gatewid; /* Gate width, meters. */ + unsigned short rangeg1; /* Range to gate 1, meters. */ + unsigned short numgates; /* Number of gates. */ + unsigned short numrays; /* Number of rays this sweep. */ + + unsigned short prf; /* Primary prf, hz. */ + unsigned short prflow; /* Secondary prf, hz. */ + unsigned short n_pulses;/* Sample size in pulses. */ + unsigned short p_width; /* Pulse width, .05 us units. */ + unsigned short cfilter; /* Clutter filter code. */ + + unsigned short offset[NUMOFFSETS]; + + unsigned char year; /* Year - 1900. */ + unsigned char month; /* Month 1-12 */ + unsigned char day; /* Day 1-31 */ + unsigned char shour; /* Start hour 0-23 */ + unsigned char sminute; /* Start minute 0-59 */ + unsigned char ssecond; /* Start second 0-59 */ + unsigned char ehour; /* End hour 0-23 */ + unsigned char eminute; /* End minute 0-59 */ + unsigned char esecond; /* End second 0-59 */ + unsigned char spare1[3]; + + unsigned short status; /* Status word. */ + unsigned short spare2; + + Lassen_ray *ray[360]; /* The Lassen_ray pointers. */ +} Lassen_sweep; + +/* + * Lassen_volume: + * + * A volume can contain a maximum of LASSEN_MAX_SWEEPS sweeps. + * The value for LASSEN_MAX_SWEEPS *MUST* be 30. This cannot change, + * otherwise, you'll not be able to read the file. + * The number of sweeps is in the member 'numsweeps'. + * + */ + +typedef struct { + unsigned short version; /* Raw version number. */ + short filled; /* <0=empty 0=filling >0=full. */ + + unsigned int volume; /* Volume serial number. */ + unsigned short sweep; /* Sweep index 1 -> max. */ + unsigned short sweep_type; /* Sweep type code. */ + unsigned short max_height; /* Maximum height, km. */ + unsigned short status; /* Status word. */ + + unsigned short min_fangle; /* Minimum fixed angle. */ + unsigned short max_fangle; /* Maximum fixed angle. */ + unsigned short min_var; /* Minimum variable angle. */ + unsigned short max_var; /* Maximum variable angle. */ + unsigned short a_start; /* Variable angle start. */ + unsigned short a_stop; /* Variable angle stop. */ + unsigned short numsweeps; /* Number of sweeps in volume. */ + unsigned short fangles[LASSEN_MAX_SWEEPS]; /* Fixed angles for each sweep. */ + + unsigned short gatewid; /* Gate width, meters. */ + unsigned short rangeg1; /* Range to gate 1, meters. */ + unsigned short numgates[LASSEN_MAX_SWEEPS]; /* Gates for each sweep. */ + unsigned short maxgates; /* Max # of gates in volume. */ + + unsigned short prf; /* Primary prf, hz. */ + unsigned short prflow; /* Secondary prf, hz. */ + unsigned short n_pulses; /* Sample size in pulses. */ + unsigned short p_width; /* Pulse width, .05 us units. */ + unsigned short cfilter; /* Clutter filter code. */ + unsigned short local; /* Used as volume lock: nonzero. */ + + unsigned int freq; /* Mhz * 10 */ + + unsigned short offset[LASSEN_MAX_SWEEPS][NUMOFFSETS]; + + unsigned char year; /* Year - 1900 */ + unsigned char month; /* Month 1-12 */ + unsigned char day; /* Day 1-31 */ + unsigned char shour; /* Start hour 0-23 */ + unsigned char sminute; /* Start minute 0-59 */ + unsigned char ssecond; /* Start second 0-59 */ + unsigned char ehour; /* End hour 0-23 */ + unsigned char eminute; /* End minute 0-59 */ + unsigned char esecond; /* End second 0-59 */ + unsigned char spare[3]; + + struct { /* Software status flags. Length of volflags is 'short' */ + unsigned int compress : 1; + unsigned int spares : 15; + } volflags; + + Lassen_radar_info radinfo; /* Radar information. */ + + Lassen_sweep *index[LASSEN_MAX_SWEEPS]; /* The Lassen_sweep pointers. */ +} Lassen_volume; + +typedef struct { + unsigned char year; /* year - 1900 */ + unsigned char month; /* 1-12 */ + unsigned char day; /* 1-31 */ + unsigned char hour; /* 0-23 */ + unsigned char minute; /* 0-59 */ + unsigned char second; /* 0-59 */ + unsigned char dummy[2]; +} Lassen_time; + +typedef struct { + char magic[8]; /* Magic number. This must be 'SUNRISE'. */ + Lassen_time mdate; /* Last modification. */ + Lassen_time cdate; /* Creation date. */ + int type; /* See #defines above.*/ + char mwho[16]; /* Last person to modify. */ + char cwho[16]; /* Person who created file. */ + int protection; /* Is file protected? */ + int checksum; /* Data bcc. */ + char description[40]; /* File description. */ + int id; + int spare[12]; +} Lassen_head; + +#define ANGLE_CONVERT(X) ((unsigned short) ((((unsigned int)X+22)*360) >> 14)) +#endif diff --git a/lassen_to_radar.c b/lassen_to_radar.c new file mode 100644 index 0000000..3e5585e --- /dev/null +++ b/lassen_to_radar.c @@ -0,0 +1,460 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +19 Jan 1998 + Michael Whimpey from BMRC, Australia changed code, for the + different callibrations, between, Pre_mctex, mctex, Gunn_Pt + periods. +22 Apr 1999 + Michael Whimpey added more callibration periods over berrimah and scsmex. + please see code where there is m.whimpey + +*/ +#include +#include +#include +#include + +#define USE_RSL_VARS +#include "rsl.h" + +#ifdef HAVE_LASSEN +#include "lassen.h" +extern int radar_verbose_flag; + +/* Some parameter headaches are prevented when vol is declared global. */ +Lassen_volume vol; +extern int read_entire_lassen_file(FILE *f, Lassen_volume *vol); + +/**********************************************************************/ +/* */ +/* lassen_load_sweep */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* May 26, 1994 */ +/**********************************************************************/ +void lassen_load_sweep(Sweep *s, int isweep_num, int ifield, int period, Lassen_sweep *ptr) +{ + float c = RSL_SPEED_OF_LIGHT; + float elev; + Lassen_ray *aray; + unsigned char *ray_data; + int i,j,m,kk=0; + float x[2000]; + double Vu; + Range (*invf)(float x); + float (*f)(Range x); + +/* calibration period flags m.whimpey */ +#define BERRIMAH1 0 +#define MCTEX_EARLY 1 +#define MCTEX 2 +#define BERRIMAH2 3 +#define GUNN_PT 4 +#define GUNN_PT1 5 +#define SCSMEX 6 +#define SCSMEX1 7 + + if (s == NULL) return; + f = (float (*)(Range x))NULL; /* This quiets the pedantic warning. */ + invf = (Range (*)(float x))NULL; + if (ifield == ZT_INDEX) {kk = OFF_UZ; invf = ZT_INVF; f = ZT_F;} + if (ifield == DZ_INDEX) {kk = OFF_CZ; invf = DZ_INVF; f = DZ_F;} + if (ifield == VR_INDEX) {kk = OFF_VEL; invf = VR_INVF; f = VR_F;} + if (ifield == SW_INDEX) {kk = OFF_WID; invf = SW_INVF; f = SW_F;} + if (ifield == ZD_INDEX) {kk = OFF_ZDR; invf = ZD_INVF; f = ZD_F;} + if (ifield == PH_INDEX) {kk = OFF_PHI; invf = PH_INVF; f = PH_F;} + if (ifield == RH_INDEX) {kk = OFF_RHO; invf = RH_INVF; f = RH_F;} + if (ifield == LR_INDEX) {kk = OFF_LDR; invf = LR_INVF; f = LR_F;} + if (ifield == KD_INDEX) {kk = OFF_KDP; invf = KD_INVF; f = KD_F;} + if (ifield == TI_INDEX) {kk = OFF_TIME; invf = TI_INVF; f = TI_F;} + + elev = (float)ptr->fangle*360.0/16384.0; + Vu = c*((float)vol.prf/10.)/(4.*(float)vol.freq*100000.0); + + s->h.sweep_num = ptr->sweep; + s->h.elev = elev; + s->h.nrays = ptr->numrays; + s->h.beam_width = 1.0; /* What is it really? */ + s->h.horz_half_bw = .5; + s->h.vert_half_bw = .5; + s->h.f = f; + s->h.invf = invf; + + for(i=0;i<(int)ptr->numrays;i++) { + aray = ptr->ray[i]; + if (aray == NULL) continue; + s->ray[i] = RSL_new_ray((int)aray->numgates); + s->ray[i]->h.month = aray->month; + s->ray[i]->h.day = aray->day; + s->ray[i]->h.year = (int)aray->year + 1900; + if (s->ray[i]->h.year < 1980) s->ray[i]->h.year += 100; /* Year > 2000. */ + s->ray[i]->h.hour = aray->hour; + s->ray[i]->h.minute = aray->minute; + s->ray[i]->h.sec = aray->second; + s->ray[i]->h.azimuth = (float)aray->vangle*360.0/16384.0; + + s->ray[i]->h.ray_num = i; + s->ray[i]->h.elev = elev; + s->ray[i]->h.elev_num = s->h.sweep_num; + s->ray[i]->h.range_bin1 = aray->rangeg1; + s->ray[i]->h.gate_size = aray->gatewid; + s->ray[i]->h.vel_res = 0.5; /* What is this really? */ + + s->ray[i]->h.fix_angle = s->h.elev; + s->ray[i]->h.frequency = (float)vol.freq*1.0e-4; /* GHz */ + s->ray[i]->h.wavelength = c / s->ray[i]->h.frequency * 1.0e-9; + s->ray[i]->h.prf = (int)aray->prf/10; + s->ray[i]->h.nyq_vel = s->ray[i]->h.prf * s->ray[i]->h.wavelength / 4.0; + if (s->ray[i]->h.prf != 0) + s->ray[i]->h.unam_rng = c / (2.0 * s->ray[i]->h.prf * 1000.0); /* km */ + else + s->ray[i]->h.unam_rng = 0.0; + s->ray[i]->h.pulse_width = (float)(aray->p_width * 0.05); + s->ray[i]->h.pulse_count = aray->n_pulses; + + s->ray[i]->h.beam_width = 1.0; /* What is it really? */ + s->ray[i]->h.f = f; + s->ray[i]->h.invf = invf; + + ray_data = (unsigned char *)aray; + + m = aray->offset[kk]; + if(m==0) continue; + +/* conversion changes by m.whimpey */ + for(j=0; jray[i]->h.nbins; j++) { + switch (kk) { + case OFF_UZ: /* UZ field. */ + case OFF_CZ: /* CZ field. */ + /* Apply a 1.4 dB correction. Ken Glasson did this. */ + /* Removed 1.4 dB correction 09/27/2006--BMRC doesn't use it. */ + if (period == BERRIMAH1) + x[j] = ((float)ray_data[m+j] - 56.0)/2.0; /* Removed +1.4 */ + else + x[j] = ((float)ray_data[m+j] - 64.0)/2.0; /* Removed +1.4 */ + break; + case OFF_VEL: /* VR field */ + if (period == BERRIMAH1) + x[j] = (float)(Vu*((double)ray_data[m+j]-128.0)/128.); + else if (period == SCSMEX) + x[j] = (float)(Vu*((double)(ray_data[m+j]^0x80)-128.0)/127.); + else + x[j] = (float)(Vu*((double)ray_data[m+j]-128.0)/127.); +/* fprintf(stderr,"Velocity for ray[%d] at x[%d] = %f, nyquist = %f\n",i,j,x[j],s->ray[i]->h.nyq_vel); */ + break; + case OFF_WID: /* SW field */ + if (period == BERRIMAH1) + x[j] = (float)(Vu*(double)ray_data[m+j]/100.); + else + x[j] = (float)(Vu*(double)ray_data[m+j]/256.); + break; + case OFF_ZDR: /* ZD field */ + if (period < MCTEX_EARLY) break; + if (period <= BERRIMAH2) + x[j] = ((float)ray_data[m+j] - 64.0)/21.25; + else + x[j] = ((float)ray_data[m+j] - 128.)*18./254.; + break; + case OFF_PHI: /* PH field */ + if (period < MCTEX_EARLY) break; + if (period <= BERRIMAH2) + x[j] = ((float)ray_data[m+j] - 128.0)*32.0/127.0; + else if (period == GUNN_PT) + x[j] = ((float)ray_data[m+j] - 64.5)*360.0/254.0; + else if (period > GUNN_PT) + x[j] = 90.0+((float)ray_data[m+j] - 128.0)*180.0/254.0; + /*Extra 90 degrees added by Scott Collis, CAWCR/BMRC 2008*/ + break; + case OFF_RHO: /* RH field */ + if (period < MCTEX_EARLY) break; + if (period <= BERRIMAH2) + x[j] = sqrt((float)ray_data[m+j]/256.822 + 0.3108); + else + x[j] = (((float)ray_data[m+j]-1.)*1.14/254.) + 0.01; + break; + case OFF_LDR: /* LR field -- no 'period' here. */ + x[j] = ((float)ray_data[m+j] - 250.0)/6; + break; + case OFF_KDP: /* KP field -- no 'period' here. */ + x[j] = ((float)ray_data[m+j]); /* This conversion is taken + from SIGMET. Is this right? */ + break; + case OFF_TIME: /* TIME field -- no 'period' here. */ + x[j] = ((float)ray_data[m+j]); /* This conversion is taken + from SIGMET. Is this right? */ + break; + } + if (ray_data[m+j] == 0) x[j] = BADVAL; + } + for (j=0; jray[i]->h.nbins; j++) + s->ray[i]->range[j] = invf(x[j]); + } +} + + + +/**********************************************************************/ +/* */ +/* RSL_lassen_to_radar */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* May 26, 1994 */ +/**********************************************************************/ +Radar *RSL_lassen_to_radar(char *infile) +{ +/* Lassen specific. */ + Lassen_sweep *ptr; + Lassen_ray *aray; + int period; /* m.whimpey changed early variable to period */ + FILE *f; + int q[MAX_RADAR_VOLUMES]; + extern int rsl_qfield[]; + extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */ + extern int rsl_qsweep_max; + +/* Radar specific */ + Radar *radar; + int i, j, k; + /* Listing of the RSL field type indexes, in the order that + * LASSEN stores them. + */ + int rsl_index[] = {ZT_INDEX, DZ_INDEX, VR_INDEX, SW_INDEX, ZD_INDEX, + PH_INDEX, RH_INDEX, LR_INDEX, KD_INDEX, TI_INDEX}; + + char *ltype[] = {"UZ", "CZ", "Vel", "Wid", "Zdr", "Phi", + "Rho", "Ldr", "Kdp", "Time"}; + + + struct compare_date { /* introduced by m.whimpey */ + int year; + int month; + int day; + int hour; + int minute; + int second; + }; +/* M.Whimpey changes made 19990422 for extra periods */ +#define NUM_DATES 8 + struct compare_date cvrt_date[NUM_DATES] = + { {1992, 1, 1, 0, 0, 0}, + {1995, 11, 1, 0, 0, 0}, + {1995, 11, 25, 20, 5, 0}, + {1996, 1, 1, 0, 0, 0}, + {1997, 10, 1, 0, 0, 0}, + {1997, 11, 20, 3, 40, 0}, + {1998, 05, 04, 0, 0, 0}, + {1998, 05, 17, 03, 47, 0} }; + + int d; /* date counter */ + + unsigned long vt; /* vol time */ + unsigned long dt; /* date time */ + + + /* open Lassen file */ + if (infile == NULL) { + int save_fd; + save_fd = dup(0); + f = fdopen(save_fd, "r"); + } else + if((f=fopen(infile, "r"))==(FILE *)NULL) { + perror(infile); + return NULL; + } + f = uncompress_pipe(f); /* Transparently, use gunzip. */ +#define NEW_BUFSIZ 16384 + setvbuf(f,NULL,_IOFBF,(size_t)NEW_BUFSIZ); /* Faster i/o? */ + + if((read_entire_lassen_file(f, &vol)) == 0) + { + perror("RSL_lassen_to_radar ... read_entire_lassen_file"); + exit(1); + } + + rsl_pclose(f); + + if (radar_verbose_flag) { + fprintf(stderr,"\n Version = %d",vol.version); + fprintf(stderr,"\n Volume = %d",vol.volume); + fprintf(stderr,"\n Numsweeps = %d",vol.numsweeps); + fprintf(stderr,"\n Time = %2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d - %2.2d:%2.2d:%2.2d", + (int)vol.month, (int)vol.day, (int)vol.year, + (int)vol.shour, (int)vol.sminute, (int)vol.ssecond, + (int)vol.ehour, (int)vol.eminute, (int)vol.esecond); + fprintf(stderr,"\n Angle: start %d, stop %d", (int)vol.a_start, (int)vol.a_stop); + fprintf(stderr,"\n"); + } + +/* determine which period the lassen volume belongs m.whimpey */ + vt = (vol.year-90) * 32140800; + vt += vol.month * 2678400; + vt += vol.day * 86400; + vt += vol.shour * 3600; + vt += vol.sminute * 60; + vt += vol.ssecond; + + for(d=0; dh.month = vol.month; + radar->h.day = vol.day; + radar->h.year = vol.year + 1900; + radar->h.hour = vol.shour; + radar->h.minute = vol.sminute; + radar->h.sec = vol.ssecond; + strcpy(radar->h.radar_type, "lassen"); + radar->h.nvolumes = MAX_RADAR_VOLUMES; + memcpy(&radar->h.radar_name, vol.radinfo.radar_name, 8); + memcpy(&radar->h.name, vol.radinfo.site_name, 8); + memcpy(&radar->h.city, "????", 4); + memcpy(&radar->h.state,"AU", 2); + radar->h.latd = vol.radinfo.latitude.degree; + radar->h.latm = vol.radinfo.latitude.minute; + radar->h.lats = vol.radinfo.latitude.second; + /* Is there a problem with the minutes/seconds when negative? + * The degree/minute/sec all should have the same sign. + */ + if (radar->h.latd < 0) { + if (radar->h.latm > 0) radar->h.latm *= -1; + if (radar->h.lats > 0) radar->h.lats *= -1; + } + radar->h.lond = vol.radinfo.longitude.degree; + radar->h.lonm = vol.radinfo.longitude.minute; + radar->h.lons = vol.radinfo.longitude.second; + if (radar->h.lond < 0) { + if (radar->h.lonm > 0) radar->h.lonm *= -1; + if (radar->h.lons > 0) radar->h.lons *= -1; + } + radar->h.height = vol.radinfo.antenna_height; + radar->h.spulse = 0; + radar->h.lpulse = 0; + + + /* iterate for each sweep in radar volume */ + +/* Determine which field types exist. The array 'q' is a boolean to + * force one print messages, if requested. + * + * Well, I tried looping through all the rays and examining aray->flags., + * but, it turns out that these flags bounce around, ie. toggle, for + * fields that don't really exist. Therefore, I cannot just logically OR + * the field flags together to determine which fields exist -- is this + * a bug when the file was created? + * + * What I've seen in lass2uf is to examine the first ray of the first sweep, + * but, I think that is unreliable too, due to the above finding. + * + * The solution, now, is to examine the existance of OFFSET values. + * This seems to be consistant, throughout the volume. + * The OFFSET is really what is used, anyway, to extract the data. + */ + memset(q, 0, sizeof(q)); + for (i=0; inumrays; j++) { + aray = ptr->ray[j]; + for (k=0; koffset[k] != 0 && !q[rsl_index[k]]) { + /* From RSL_select_fields */ + if (rsl_qfield[rsl_index[k]] == 1) + q[rsl_index[k]]=1; + } + } + } + } + if (radar_verbose_flag) + fprintf(stderr,"\n Fields are (Lassen nomenclature):"); + for (k=0; kv[i] = RSL_new_volume(vol.numsweeps); + radar->v[i]->h.f = RSL_f_list[i]; + radar->v[i]->h.invf = RSL_invf_list[i]; + if (radar_verbose_flag) fprintf(stderr," %s", RSL_ftype[i]); + if (k >= 2 && radar_verbose_flag) fprintf(stderr," "); /* Alignment. */ + } + } + if (radar_verbose_flag) fprintf(stderr,"\n"); + + for(j=0;jh.nvolumes; j++) { + for(i=0;i<(int)vol.numsweeps;i++) { + if (rsl_qsweep != NULL) { + if (i > rsl_qsweep_max) break; + if (rsl_qsweep[i] == 0) continue; + } + ptr = vol.index[i]; + if (radar->v[j]) { + radar->v[j]->sweep[i] = RSL_new_sweep(ptr->numrays); + + /* 'period' is a flag for different calibrations */ + lassen_load_sweep(radar->v[j]->sweep[i], i, j, period, ptr); + } + } + } + radar = RSL_prune_radar(radar); + return radar; +} +#else +Radar *RSL_lassen_to_radar(char *infile) +{ + fprintf(stderr, "LASSEN is not installed in this version of RSL.\n"); + fprintf(stderr, "Reinstall RSL w/ -DHAVE_LASSEN in the Makefile.\n"); + return NULL; +} +#endif diff --git a/mcgill.c b/mcgill.c new file mode 100644 index 0000000..f4805ca --- /dev/null +++ b/mcgill.c @@ -0,0 +1,430 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/****************************************************************** + * Opens a Mcgill format radar data file, and reads and + * decompresses the contents. + * + * All Mcgill data structures referenced herein are + * defined in the file "mcgill.h". + * + * There exist 3 functions in this file which are + * accessible to application routines: + * ----------------------------------------------------- + * mcgFile_t *mcgFileOpen(int *code, char *filename); + * Opens and verifies the content of a Mcgill format + * data file, reads in the file header record, and + * initializes the mcgFile_t structure. + * ------------------------------------------------------- + * int mcgFileClose(mcgFile_t *file); + * Closes the Mcgill data file. + * ------------------------------------------------------- + * int mcgRayBuild(mcgRay_t *ray, mcgFile_t *file); + * Returns in the mcgRay_t structure the reflectivity values from + * one ray of data from a Mcgill format radar data file. + * Successive calls return data from successive rays found + * in the file. + * + * Kolander + * + *******************************************************************/ + +#include +#include +#include +#include "mcgill.h" + +#define TRUE 1 +#define FALSE 0 +#define EMPTY -1.0 + + +/* Fixed elevation angles for Mcgill sweeps. */ +static float elev_angle[3][24] = + { + /* PAFB volume scan format types 3 and 4 (12 sweeps) */ + { + 0.6, 1.0, 1.6, 2.5, 3.6, 5.2, 7.5, 10.5, 14.7, 20.2, + 27.2, 35.6 + }, + /* PAFB volume scan format types 1 and 2 (24 sweeps) */ + { + 0.6, 0.79, 1.01, 1.27, 1.57, 1.93, 2.35, 2.84, + 3.41, 4.08, 4.86, 5.78, 6.85, 8.09, 9.55, 11.23, + 13.18, 15.42, 17.98, 20.89, 24.16, 27.78, 31.73, 35.97 + }, + /* Sao Paulo radar?? (20 sweeps) */ + { + 1.0, 1.3, 1.6, 2.0, 2.4, 2.9, 3.6, 4.2, 5.1, + 6.1, 7.3, 8.7, 10.3, 12.2, 14.4, 16.9, 19.8, + 23.1, 26.7, 30.8 + } + }; + +/* Fixed number_of_bins for Mcgill sweeps. */ +static int num_bins_normal[24] = + { + /* PAFB volume scan formats 1 and 3 (normal mode) */ + 240, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180 + }; +static int num_bins_compressed[24] = + { + /* PAFB volume scan formats 2 and 4 (compressed mode) */ + 180, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120 + }; + +FILE *uncompress_pipe (FILE *fp); + +/**********************************************************************/ +mcgFile_t *mcgFileOpen(int *code, char *filename) +/**********************************************************************/ + { + /* Open a Mcgill format radar data file, and read and verify + the content of the first (header) record from the file. + This function returns one of the following coded integer values: + MCG_OK: Normal return. + MCG_OPEN_FILE_ERR: Error occurred while attempting to open + the data file. + MCG_EOF: Unexpected End_of_File occurred reading from file. + MCG_READ_ERR: Error occurred while reading from file. + MCG_FORMAT_ERR: Format error encountered reading from file. + SYS_NO_SPACE: Error attempting to allocate memory space. + */ + mcgFile_t *file; + char buffer[MCG_RECORD]; + char *csp_buffer; + + /* Allocate space for the mcgFile structure. */ + if ((file = (mcgFile_t *)malloc(sizeof(mcgFile_t))) == NULL) + { + *code = SYS_NO_SPACE; + return(NULL); + } + + /* Open Mcgill data file for reading */ + if ((file->fp = fopen(filename, "r")) == NULL) + { + *code = MCG_OPEN_FILE_ERR; + return(NULL); + } + file->fp = uncompress_pipe(file->fp); /* Transparently, use gunzip. */ + /* Read first (header) record from data file into buffer */ + if (fread(buffer, sizeof(char), MCG_RECORD, file->fp) < MCG_RECORD) + { + *code = MCG_FORMAT_ERR; + return(NULL); + } + + /* Move header values from buffer to the mcgHeader structure.*/ + memcpy(&file->head, buffer, sizeof(mcgHeader_t)); + + /* Check the leading header characters for the site ID string. */ + if ((strncmp((char *)&file->head, "PAFB RADAR VOLUME SCAN AT", 25) == 0) || + (strncmp((char *)&file->head, "P A B RADAR VOLUME SCAN AT", 27) == 0)) + { + file->site = MCG_PAFB_1_2; + } + /* Check if file from Sao Paulo. + else if (strncmp((char *)&file->head, SAOP_ID_STRING) == 0) + { + file->site = MCG_SAOP; + } + */ + else /* Can't identify site/format. */ + { + *code = MCG_FORMAT_ERR; + return(NULL); + } + + /* Check validity of some file header values. If + not valid, we assume the file is garbled beyond legibility. */ + if ((file->head.vol_scan_format < 1) || (file->head.vol_scan_format > 4) + || (file->head.day < 1) || (file->head.day > 31) + || (file->head.month < 1) || (file->head.month > 12)) + { + /* Invalid/unexpected file format */ + *code = MCG_FORMAT_ERR; + return(NULL); + } + + /* Set the proper number_of_bins, depending on scan format. */ + switch (file->head.vol_scan_format) + { + case 1: + case 3: + file->num_bins = num_bins_normal; + break; + case 2: + case 4: + file->num_bins = num_bins_compressed; + break; + default: + break; + } /* end switch */ + + /* I've never seen scan_formats 3 or 4 from PAFB, but I make + allowance for them here. */ + if (file->site == MCG_PAFB_1_2) + { + if ((file->head.vol_scan_format == 3) || + (file->head.vol_scan_format == 4)) + { + file->site = MCG_PAFB_3_4; + } + } + + /* If a Mcgill Csp block is contained in this file, it's next. + Skip past it. It's useless for our purposes. */ + if (file->head.csp_rec == 1) + { + /* if (fseek(file->fp, MCG_CSP, SEEK_CUR) != 0) + { + *code = MCG_READ_ERR; + return(NULL); + } + */ + /* Allocate buffer space for the csp block, read the block + from the disk file into the buffer, then free the buffer. + An ugly way to discard the block, but the fseek solution + above won't work with stdin capabilities. + */ + if ((csp_buffer=(char *)malloc(MCG_CSP)) == NULL) + { + *code = SYS_NO_SPACE; + return(NULL); + } + if (fread(csp_buffer, sizeof(char), MCG_CSP, file->fp) < MCG_CSP) + { + *code = MCG_READ_ERR; + return(NULL); + } + free(csp_buffer); + } + + /* File is open and properly initialized. */ + *code = MCG_OK; + return(file); + } + + +int rsl_pclose( FILE *stream); +/**********************************************************************/ +int mcgFileClose(mcgFile_t *file) +/**********************************************************************/ + { + /* Close a Mcgill format radar data file. Returns one of the + following coded integer values: + MCG_OK: File closed successfully. + MCG_CLOSE_FILE_ERR: System error occurred during file close + operation. + */ + + + if (rsl_pclose(file->fp) == 0) + { + file->fp = NULL; + return(MCG_OK); + } + else + return(MCG_CLOSE_FILE_ERR); + } + + + +/************************************************************************/ +int mcgRecordRead(mcgRecord_t *record, mcgFile_t *file) +/************************************************************************/ + { + /* Reads a Mcgill logical record (2048 bytes) from the data file + into the mcgRecord_t structure. Returns one of the following coded + integer values: + MCG_OK: Successfully read a record. + MCG_EOF: End_of_File condition occurred while reading a record. + MCG_READ_ERR: Read error occurred. + */ + + /* Read data from file directly into the record structure. */ + if (fread(record, sizeof(char), MCG_RECORD, file->fp) < MCG_RECORD) + { + if (feof(file->fp)) + return(MCG_EOF); + else + return(MCG_READ_ERR); + } + + return(MCG_OK); + } + + + +/************************************************************************/ +mcgSegmentID mcgSegmentKeyIdentify(int key) +/************************************************************************/ + { + /* Decodes the first byte from a Mcgill file segment. + The first byte of the segment identifies the type of the segment. + Mcgill segment types are data, elevation, and end_of_data. + */ + if ((key > 0) && (key < 16)) + return(MCG_DATA_SEG); + else if ((key > 31) && (key < 63)) + return(MCG_ELEV_SEG); + else if (key == 63) + return(MCG_EOD_SEG); + else + return(MCG_UNDEFINED_SEG); + } + + + +/*************************************************************************/ +int mcgRayBuild(mcgRay_t *ray, mcgFile_t *file) +/*************************************************************************/ + { + /* Returns in the ray structure the reflectivity values from one + ray of data from a Mcgill format radar data file. Successive calls + to this routine return data from successive rays found in the file. + This function returns the following coded integer values: + MCG_OK : Ray structure successfully filled with data values. + MCG_EOD: Empty ray structure, No more data in file. + MCG_EOF: Premature End_of_File condition encountered. + MCG_READ_ERR: System error occurred while reading from file. + MCG_FORMAT_ERR: Format error encountered while reading from file. + */ + + /* This function is typically called about 9000 times while reading a + Mcgill data file. The following static variables must retain their + values between successive calls. */ + static int seg_num=MCG_MAX_SEG_NUM; + static int eod_found = FALSE; + static int sweep_num=0; + static float elev=0.0; + static float azm; + int base, j, n; + mcgSegmentID seg_type; + static mcgRecord_t record; + + + /* If we've previously found the end_of_data (eod) data segment in + the last Mcgill record, we're done. Do this for robustness, in case + the calling application routine screws up. */ + if (eod_found) + { + return(MCG_EOD); + } + + /* Initialize the ray data values. */ + ray->elev = elev; + ray->azm = EMPTY; + ray->sweep_num = sweep_num; + memset(ray->data, 0, 240); + ray->num_bins = file->num_bins[sweep_num]; + + /* Loop to fill the ray bins with data values from consecutive + Mcgill data segments. */ + while (1) + { + /* Read in from the Mcgill file a new record, if necessary. */ + if (seg_num == MCG_MAX_SEG_NUM) + { + if ((n=mcgRecordRead(&record, file)) < MCG_OK) + return(n); + else + { + /* record_empty = FALSE; */ + seg_num = 0; + } + } + + /* The first byte of segment is used to identify segment type. */ + seg_type = mcgSegmentKeyIdentify(record.segment[seg_num][0]); + switch (seg_type) + { + case MCG_DATA_SEG: + /* Determine the azimuth angle for this data segment */ + azm = record.segment[seg_num][1] * 64.0 + + record.segment[seg_num][2] - 1.0; + /* Check if this data segment contains data belonging to + the current ray. If so, add the segment bin values to + the ray structure. */ + if ((azm == ray->azm) || (ray->azm == EMPTY)) + { + ray->azm = azm; + /* Compute the ray bin base_address for the 16 bin values + from this data segment. */ + base = (record.segment[seg_num][0] - 1)*16; + /* Move the 16 bin values from segment to ray structure */ + for (j=0; j<16; j++) + { + ray->data[base + j] = record.segment[seg_num][3+j]; + } + } + else /* This data segment belongs to the next ray. Return the + current ray. We'll start with this segment the next + time mcgRayBuild() is called. */ + { + return(MCG_OK); + } + break; + + case MCG_ELEV_SEG: + sweep_num = record.segment[seg_num][0] - 31 - 1; + elev = elev_angle[file->site][sweep_num]; + /* If ray structure is not empty, return it, since + we've found a Mcgill elevation segment, which initiates + a new sweep. */ + if (ray->azm != EMPTY) + { + seg_num += 1; + if (seg_num == MCG_MAX_SEG_NUM) + /* record_empty = TRUE; */ + return(MCG_OK); + } + else /* Ray structure is empty. Continue on to read the + next Mcgill segment.*/ + { + ray->elev = elev; + ray->sweep_num = sweep_num; + } + break; + + case MCG_EOD_SEG: + eod_found = TRUE; + if (ray->azm == EMPTY) + return(MCG_EOD); + else /* Return the ray structure we've filled. */ + return(MCG_OK); + break; + + default: + return(MCG_FORMAT_ERR); + break; + } /* end switch */ + + seg_num += 1; + } /* end while (1) */ + } diff --git a/mcgill.h b/mcgill.h new file mode 100644 index 0000000..5b6ae69 --- /dev/null +++ b/mcgill.h @@ -0,0 +1,109 @@ +/********************************************************************** + * Structure and parameter definitions for Mcgill format + * radar data processing. + * + * Kolander + * + **********************************************************************/ + +#include + +#define MCG_RECORD 2048 /* Mcgill record size (bytes) */ +#define MCG_CSP 12288 /* Mcgill CSP block size (bytes) */ +#define MCG_MAX_SEG_NUM 107 /* 107 segments per Mcgill logical record */ + +/* Mcgill method return codes */ +#define MCG_EOD 1 /* End_Of_Data flag */ +#define MCG_OK 0 /* Successful return */ +#define MCG_OPEN_FILE_ERR -1 /* Couldn't open Mcgill data file */ +#define MCG_CLOSE_FILE_ERR -2 /* Couldn't close Mcgill data file */ +#define MCG_EOF -3 /* Reached end of Mcgill data file */ +#define MCG_READ_ERR -4 /* Error occurred reading data file */ +#define MCG_FORMAT_ERR -5 /* Unidentified radar site or format error*/ +#define SYS_NO_SPACE -6 /* Memory allocation problem */ + +/* Mcgill segment identifiers */ +#define MCG_UNDEFINED_SEG 0 +#define MCG_DATA_SEG 1 +#define MCG_ELEV_SEG 2 +#define MCG_EOD_SEG 3 + +/* Radar site/format codes */ +#define MCG_PAFB_3_4 0 /* Patrick Air Force Base, format 3 or 4 */ +#define MCG_PAFB_1_2 1 /* Patrick Air Force Base, format 1 or 2 */ +#define MCG_SAOP 2 /* Sao Paulo */ + +typedef unsigned short word; +typedef unsigned char byte; +typedef int mcgSegmentID; + +typedef struct + { + word unused[40]; + /* Word 41 of Mcgill header record. A word is 2 (unsigned) bytes. */ + word hour; /* 0 to 23 */ + word min; /* 0 to 59 */ + word sec; /* 0 to 59 */ + word day; /* 1 to 31 */ + word month; /* 1 to 12 */ + word year; /* 0 to 99 */ + word num_records; /* No. logical records in volume scan */ + word unused1[3]; + /* Word 51 */ + word vol_scan_format; /* 1: 24 sweeps, normal + 2: 24 sweeps, compressed + 3: 12 sweeps, normal + 4: 12 sweeps, compressed */ + word unused2[4]; + /* Word 56 */ + word csp_rec; /* 0: No CSP block 1: CSP block */ + } +mcgHeader_t; + +typedef struct + { + FILE *fp; /* Pointer to Mcgill file */ + int site; + int *num_bins; /* Points to array of 24 bin_counts, + one bin_count per sweep. */ + mcgHeader_t head; + } +mcgFile_t; + +/* Structure to contain a Mcgill logical record (2048 bytes) */ +typedef struct + { + word record_num; /* No. of this logical record in volume scan */ + byte last_record_flag; /* 1 if last record in vol_scan, 0 otherwise */ + byte start_elev_num; /* Starting elev no. of data in this record */ + byte end_elev_num; /* End elev no. of data in this record */ + byte unused[9]; + byte segment[107][19]; /* 107 elevation and data segments, + 19 bytes each. */ + byte unused1; + } +mcgRecord_t; + +/* Structure to contain Mcgill reflectivity data from 1 ray */ +typedef struct + { + float elev; + float azm; + int sweep_num; + int num_bins; /* no. of bins for this ray */ + char data[240]; /* reflectivity data value for each bin */ + } +mcgRay_t; + + +/*************** Function Prototypes **********************/ +/* Grouped by object operated on and/or returned. */ +mcgFile_t *mcgFileOpen(int *code, char *filename); +int mcgFileClose(mcgFile_t *file); + +int mcgRecordRead(mcgRecord_t *record, mcgFile_t *file); + +mcgSegmentID mcgSegmentKeyIdentify(int key); + +int mcgRayBuild(mcgRay_t *ray, mcgFile_t *file); + diff --git a/mcgill_to_radar.c b/mcgill_to_radar.c new file mode 100644 index 0000000..bc5e53f --- /dev/null +++ b/mcgill_to_radar.c @@ -0,0 +1,503 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/******************************************************************* + * Ingest a Mcgill format file and fill a RSL Radar structure + * with the data. + * + * Object code from this file must be linked with the following libraries: + * librsl libmcg + * + *----------------------------------------------------------------- + * NOTE: Adjust Mcgill dbz bias in function RayFill() . + * Presently, if (Mcgill_dbz_value != 0) + * then Mcgill_dbz_value + 16.5 is stored in RSL Ray. + * if (Mcgill dbz value == 0) + * then 0 is stored in RSL Ray. + * I don't find the Mcgill documentation very clear in this matter. + *----------------------------------------------------------------- + * Presently sets radar_head->radar_type = DARWIN_TOGA_SIGMET + * (Need a radar_type defined in rsl.h for PAFB or MCGILL) + *---------------------------------------------------------------- + * Minor changes will be required in the associated Mcgill library to + * accomodate Mcgill data from Sao Paulo. Since I don't have any files + * from Sao Paulo to test, I haven't incorporated any such changes. + *------------------------------------------------------------------- + * Functions defined in this file: + * + * void RayFill(Ray *rsl_ray, mcgRay_t *mcg_ray); + * void Ray_headerInit(Ray *ray, mcgHeader_t *head, + * mcgRay_t *mcg_ray, int ray_num, int num_bins_rsl); + * void Sweep_headerInit(Sweep *sweep, mcgRay_t *mcg_ray, + * int nrays); + * void Volume_headerInit(Volume *volume, short vol_scan_format); + * void Radar_headerInit(Radar *radar, mcgHeader_t *mcg_head); + * Radar *RSL_mcgill_to_radar(char *infile); + * + * Kolander + * 09 May 95 + * + *******************************************************************/ + +#include +#include +#include "mcgill.h" +#include "rsl.h" + +#define MAX_RAYS 512 +#define MAX_SWEEPS 32 +#define MISSING_VAL 0 +#define MCG_DBZ_BIAS 16.5 +#define MCG_NOISE_BIAS 0.0 + +extern int radar_verbose_flag; + +/*********************** Function Prototypes ***************************/ +static void RayFill(Ray *rsl_ray, mcgRay_t *mcg_ray); +static void Ray_headerInit(Ray *ray, mcgHeader_t *head, + mcgRay_t *mcg_ray, int ray_num, int num_bins_rsl); +static void Sweep_headerInit(Sweep *sweep, mcgRay_t *mcg_ray, int nrays); +static void Volume_headerInit(Volume *volume, short vol_scan_format); +static void Radar_headerInit(Radar *radar, mcgHeader_t *mcg_head); +Radar *RSL_mcgill_to_radar(char *infile); + +static float (*f)(Range x); +static Range (*invf)(float x); + +/* Fixed number_of_RSL_bins for Mcgill sweeps. Note that + the number of bins in the RSL structure differs from + the number of bins in the Mcgill ray stucture, since + the km/bin spacing differs. SEE MCGILL DOCUMENTATION */ +static int num_bins_normal[24] = + { + /* PAFB volume scan formats 1 and 3 (normal mode) */ + 480, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240 + }; +static int num_bins_compressed[24] = + { + /* PAFB volume scan formats 2 and 4 (compressed mode) */ + 240, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120 + }; + + +/********************************************************************/ +void RayFill(Ray *rsl_ray, mcgRay_t *mcg_ray) +/********************************************************************/ + /* transfer ray data values from the mcgRay structure + to the radar->v[]->sweep[]->ray[] structure */ + { + int j, mcg_bin; + int rsl_bin=0; + int index=1; /* Used to accomodate varying Mcgill bin spacing */ + + if (rsl_ray == NULL) return; + + /* Note that the number of bins in the Mcgill ray structure + is different from the number of bins in the RSL ray structure, + since the Mcgill bin spacing changes with range. RSL ray bin + spacing is constant. + --------------------------------------------------------- + MCGILL NORMAL FORMAT: + The first 120 mcg_bins have a length of 1 km, and span the + the range [0, 120] km. + Mcg_bins 120 to 180 have a length of 2 km, and span the + range [120, 240] km. + Mcg_bins 180 to 240 have a length of 4 km, and span the + range [240, 480] km. + --------------------------------------------------------- + MCGILL COMPRESSED FORMAT: + The first 120 mcg_bins have a length of 2 km, and span the + range [0, 240] km. + Mcg_bins 120 to 180 have a length of 4 km, and span the + range [240, 480] km. + */ + for (mcg_bin=0; mcg_binnum_bins; mcg_bin++) + { + /* I do the case dbz_value of zero separately, so produced + color images have a black background. Otherwise, if >>all<< + dbz values are biased by 16.5, we get a colored background + where there is no precipitation. Looks peculiar. Somebody + knowledgable should look into this matter. */ + if (mcg_ray->data[mcg_bin] == 0) + { + for (j=0; jrange[rsl_bin] = invf(MCG_NOISE_BIAS); + rsl_bin += 1; + } + } + else + { + for (j=0; jrange[rsl_bin] = invf(mcg_ray->data[mcg_bin] + + MCG_DBZ_BIAS); + rsl_bin += 1; + } + } /* end else */ + /* Mcgill bin spacing changes at bins 120 and 180 */ + if ((mcg_bin == 119) || (mcg_bin == 179)) + { + /* In normal format, put range rings at 120km and 240km. + In compressed format, put range rings at 240km and 480km */ +/* rsl_ray->range[rsl_bin-1] = RSL_INVF(60.0); */ + index = index*2; /* Set up new bin spacing index */ + } + } /* end for (mcg_bin=0...*/ + } + + +/*************************************************************************/ +void Ray_headerInit(Ray *ray, mcgHeader_t *head, mcgRay_t *mcg_ray, + int ray_num, int num_bins_rsl) +/*************************************************************************/ + { + if (ray == NULL) return; + ray->h.month = (int)head->month; + ray->h.day = (int)head->day; + ray->h.year = 1900 + (int)head->year; + if (ray->h.year < 1980) ray->h.year += 100; /* Year > 2000 */ + ray->h.hour = (int)head->hour; + ray->h.minute = (int)head->min; + ray->h.sec = (float)head->sec; + ray->h.unam_rng = MISSING_VAL; /***** ?? ******/ + ray->h.azimuth = mcg_ray->azm; + ray->h.ray_num = ray_num; + ray->h.elev = mcg_ray->elev; + ray->h.elev_num = mcg_ray->sweep_num; + ray->h.range_bin1 = 0; + switch (head->vol_scan_format) + { + case 1: + ray->h.gate_size = 1000; /* 1 km/bin */ + ray->h.fix_angle = 24; /* 24 sweeps */ + break; + case 2: + ray->h.gate_size = 2000; /* 2 km/bin */ + ray->h.fix_angle = 24; /* 24 sweeps */ + break; + case 3: + ray->h.gate_size = 1000; /* 1 km/bin */ + ray->h.fix_angle = 12; /* 12 sweeps */ + break; + case 4: + ray->h.gate_size = 2000; /* 2 km/bin */ + ray->h.fix_angle = 12; /* 12 sweeps */ + break; + default: + break; + } /* end switch */ + ray->h.vel_res = MISSING_VAL; /* ?? */ + ray->h.sweep_rate = MISSING_VAL; /* ?? */ + ray->h.prf = MISSING_VAL; + ray->h.azim_rate = MISSING_VAL; /* ?? */ + ray->h.pulse_count = MISSING_VAL; /* ?? */ + ray->h.pulse_width = MISSING_VAL; /* ?? */ + ray->h.frequency = MISSING_VAL; /* ?? */ + ray->h.wavelength = MISSING_VAL; /* ?? */ + ray->h.nyq_vel = MISSING_VAL; /* ?? */ + ray->h.nbins = num_bins_rsl; + ray->h.f = f; + ray->h.invf = invf; + + } + + + +/*********************************************************************/ +void Sweep_headerInit(Sweep *sweep, mcgRay_t *mcg_ray, int nrays) +/*********************************************************************/ + /* Arrive here _after_ sweep ray data has been filled in. */ + { + if (radar_verbose_flag) + fprintf(stderr,"sweep_num:%02d num_rays:%d\n",mcg_ray->sweep_num, nrays); + if (sweep == NULL) return; + sweep->h.sweep_num = mcg_ray->sweep_num; + sweep->h.elev = mcg_ray->elev; + sweep->h.beam_width = 2.0; /* From Dennis' function mcg2uf(). + I don't know where he got it. */ + sweep->h.horz_half_bw = 1.0; + sweep->h.vert_half_bw = 1.0; + sweep->h.nrays = nrays; + sweep->h.f = f; + sweep->h.invf = invf; + } + + + +/************************************************************************/ +void Volume_headerInit(Volume *volume, short vol_scan_format) +/************************************************************************/ + { + if (volume == NULL) return; + volume->h.type_str = strdup("Reflectivity"); + volume->h.f = f; + volume->h.invf = invf; + + switch (vol_scan_format) + { + case 1: case 2: + volume->h.nsweeps = 24; + break; + case 3: case 4: + volume->h.nsweeps = 12; + break; + default: + break; + } + } + + +/***********************************************************************/ +void Radar_headerInit(Radar *radar, mcgHeader_t *mcg_head) +/***********************************************************************/ + { + radar->h.month = (int)mcg_head->month; + radar->h.day = (int)mcg_head->day; + radar->h.year = 1900 + (int)mcg_head->year; + radar->h.hour = (int)mcg_head->hour; + radar->h.minute = (int)mcg_head->min; + radar->h.sec = (float)mcg_head->sec; + strcpy(radar->h.radar_type, "mcgill"); + radar->h.nvolumes = 1; /* Mcgill contains only refl data */ + radar->h.number = MISSING_VAL; /****************/ + strcpy(radar->h.name, "PAFB"); + strcpy(radar->h.radar_name, "MCGILL"); + strcpy(radar->h.city, "MELB"); + strcpy(radar->h.state, "FL"); + radar->h.latd = 28; + radar->h.latm = 15; + radar->h.lats = 19; + radar->h.lond = -80; + radar->h.lonm = -36; + radar->h.lons = -21; + radar->h.height = 0; + radar->h.spulse = MISSING_VAL; /* ns */ /*************/ + radar->h.lpulse = MISSING_VAL; /* ns */ /*************/ + } + + + +/*********************************************************************/ +Radar *RSL_mcgill_to_radar(char *infile) +/*********************************************************************/ + { + /* Ingest a Mcgill format radar data file and fill a Radar RSL + structure with the data. + */ + int ray_num, code; + int *num_bins_rsl; + mcgFile_t *file; + Radar *radar; + mcgRay_t *mcg_ray, *mcg_ray_last, *swap; + extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */ + extern int rsl_qsweep_max; + + /* If no filename has been passed, there's nothing to do. */ + if (infile == NULL) + return NULL; + + /* Default conversion functions. */ + f = DZ_F; + invf = DZ_INVF; + + /* Create a structure of type Radar */ + radar = (Radar *)RSL_new_radar(MAX_RADAR_VOLUMES); + if (radar == NULL) { + perror("RSL_mcgill_to_radar: RSL_new_radar:"); + return NULL; + } + + + /* Open the Mcgill data file and read Mcgill file header into the + mcgFile.head structure */ + file = (mcgFile_t *)mcgFileOpen(&code, infile); + if (file == NULL) + goto quit; + + if (radar_verbose_flag) + { + fprintf(stderr,"Input file: %s\n", infile); + fprintf(stderr,"Scan_date: %d/%d/%d\n", file->head.month, file->head.day, + file->head.year); + fprintf(stderr,"Scan_time: %d:%d:%d\n", file->head.hour, file->head.min, + file->head.sec); + fprintf(stderr,"num_recs:%d format:%d\n\n", + file->head.num_records, file->head.vol_scan_format); + } + + /* Initialize num_bins_rsl to point to the proper bin count array for + the scan format. */ + if ((file->head.vol_scan_format == 1) || + (file->head.vol_scan_format == 3)) /* Normal mode */ + { + num_bins_rsl = num_bins_normal; + } + else /* Compressed mode */ + num_bins_rsl = num_bins_compressed; + + /* Allocate space for two mcg_rays. mcg_ray will contain the current + ray, and mcg_ray_last will contain the previous ray. The previous ray + is needed only at sweep increments. */ + mcg_ray = (mcgRay_t *)malloc(sizeof(mcgRay_t)); + mcg_ray_last = (mcgRay_t *)malloc(sizeof(mcgRay_t)); + + /* Initialize the values of the Radar_header structure */ + Radar_headerInit(radar, &file->head); + /* Create a structure of type Volume */ + radar->v[DZ_INDEX] = RSL_new_volume(MAX_SWEEPS); + if (radar->v[DZ_INDEX] == NULL) { + perror("mcgill_to_radar: RSL_new_volume"); + return radar; + } + /* Initialize the values of the Volume_header structure. */ + Volume_headerInit(radar->v[DZ_INDEX], file->head.vol_scan_format); + + /* initialize counters */ + ray_num = -1; + mcg_ray_last->sweep_num = -1; + + /* Main loop to read in a ray from the Mcgill data file and store + into RSL radar structure */ + while ((code = mcgRayBuild(mcg_ray, file)) == MCG_OK) + { + /* Discard rays with bogus azimuth values. */ + if (mcg_ray->azm > 360.0) + { + if (radar_verbose_flag) + fprintf(stderr,"**** Bogus azm:%.1f, discarding ray.\n", mcg_ray->azm); + continue; + } + /* Check for end_of_sweep. Fill the sweep header _after_ we've + read in the sweep, since we don't know the number of + rays in the sweep until we find the start of the next sweep*/ + if (mcg_ray_last->sweep_num < mcg_ray->sweep_num) /* new sweep? */ + { + if (mcg_ray_last->sweep_num >= 0) + { + /* fill the sweep header for the previous sweep */ + Sweep_headerInit(radar->v[DZ_INDEX]->sweep[mcg_ray_last->sweep_num], + mcg_ray_last, ray_num+1); + } + ray_num = -1; /* Reset ray counter at start of each sweep */ + + /* Check for too many sweeps. If we've exceeded MAX_SWEEPS, + we're lost. */ + if (MAX_SWEEPS < mcg_ray->sweep_num + 1) + { + perror("RSL_mcgill_to_radar: Exceeded expected no. of sweeps"); + mcgFileClose(file); + RSL_free_radar(radar); + return NULL; + } + if (rsl_qsweep != NULL) { + if (mcg_ray->sweep_num > rsl_qsweep_max) break; + if (rsl_qsweep[mcg_ray->sweep_num] == 0) continue; + } + + /* Create new sweep structure. */ + radar->v[DZ_INDEX]->sweep[mcg_ray->sweep_num] = RSL_new_sweep(MAX_RAYS); + if (radar->v[DZ_INDEX]->sweep[mcg_ray->sweep_num] == NULL) { + perror("mcgill_to_radar: RSL_new_sweep"); + return radar; + } + } /* end if new sweep */ + + ray_num += 1; /* Increment ray counter */ + /* Check for too many rays. */ + if (ray_num > MAX_RAYS) + { + perror("mcgill_to_radar: Exceeded maximal no. of rays"); + mcgFileClose(file); + RSL_free_radar(radar); + return NULL; + } + + /* Create a new RSL ray containing correct # of bins, and fill it. */ + radar->v[DZ_INDEX]->sweep[mcg_ray->sweep_num]->ray[ray_num] = + RSL_new_ray(num_bins_rsl[mcg_ray->sweep_num] + 8); + if (radar->v[DZ_INDEX]->sweep[mcg_ray->sweep_num]->ray[ray_num] == NULL ) { + perror("mcgill_to_radar: RSL_new_ray"); + return radar; + } + + Ray_headerInit(radar->v[DZ_INDEX]->sweep[mcg_ray->sweep_num]->ray[ray_num], + &file->head, mcg_ray, ray_num, num_bins_rsl[mcg_ray->sweep_num]); + RayFill(radar->v[DZ_INDEX]->sweep[mcg_ray->sweep_num]->ray[ray_num], + mcg_ray); + + /* Swap mcg_ray pointers so that the current mcg_ray, which we've + finished loading into an RSL_ray, becomes mcg_ray_last . */ + swap = (mcgRay_t *)mcg_ray_last; + mcg_ray_last = (mcgRay_t *)mcg_ray; + mcg_ray = (mcgRay_t *)swap; + } /* end while */ + + /* At this point, we're finished reading file records. + Fill in the last sweep header. */ + Sweep_headerInit(radar->v[DZ_INDEX]->sweep[mcg_ray_last->sweep_num], + mcg_ray_last, ray_num+1); + + /* Check which flag the mcgill routines returned, and + print appropriate terminating message */ +quit: if (radar_verbose_flag) + { + switch (code) + { + case MCG_EOD: + fprintf(stderr,"MCG_EOD: Reached end of data file\n"); + break; + case MCG_OPEN_FILE_ERR: + fprintf(stderr,"MCG_OPEN_FILE_ERR: Error opening Mcgill data file\n"); + break; + case MCG_EOF: + fprintf(stderr,"MCG_EOF: End of data file reached prematurely\n"); + break; + case MCG_READ_ERR: + fprintf(stderr,"MCG_READ_ERR: Error occurred while reading from data file\n"); + break; + case MCG_FORMAT_ERR: + fprintf(stderr,"MCG_FORMAT_ERR: Format error encountered in data file\n"); + break; + default: + fprintf(stderr,"Error reading data file \n"); + break; + } + } /* end if (radar_verbose_flag) */ + + if (code == MCG_EOD) /* Successfully read in Mcgill file? */ + { + mcgFileClose(file); + radar = RSL_prune_radar(radar); + return(radar); + } + else /* Fatal error occurred */ + { + RSL_free_radar(radar); + return(NULL); + } + } + diff --git a/nsig.c b/nsig.c new file mode 100644 index 0000000..038b7de --- /dev/null +++ b/nsig.c @@ -0,0 +1,644 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * Read SIGMET version 1 and version 2 formatted files. + * + * Data is written in little-endian format for version 1 files. + * This means that on big endian machines, bytes must be swapped. + * This is auto-detected and all swapping is automatic. + * + * Note that this is different in SIGMET version 2 data files. There + * the data is written in big-endian format (written w/ an IRIS computer). + * For that case, the byte swapping logic is reversed. + * + * The highest level functions provided is: + * nsig_read_sweep -- Read an entire sweep including all fields. + * Call it until NULL is returned. That indicates + * end-of-file. + *---------------------------------------------------------------------- + * 8/13/96 + * + * John H. Merritt + * Space Applications Corp. + * NASA/GSFC Code 910.1 + * + * Copyright 1996 + */ + +#include +#include +#include +#include + +#include "nsig.h" + +FILE *uncompress_pipe(FILE *fp); +int big_endian(void); +int little_endian(void); +void swap_4_bytes(void *word); +void swap_2_bytes(void *word); +int rsl_pclose(FILE *fp); + +/********************************************************************* + * Open a file and possibly setup a gunzip pipe * + *********************************************************************/ +FILE *nsig_open(char *file_name) +{ + FILE *fp; + int save_fd; + + /* Open input file */ + if (file_name == NULL) { /* Use stdin */ + save_fd = dup(0); + fp = fdopen(save_fd, "r"); + } else if((fp = fopen(file_name,"r")) == NULL) { + perror(file_name); + return fp; + } + + fp = uncompress_pipe(fp); /* Transparently gunzip. */ + return fp; +} + +/********************************************************************** + * Given an opened file stream read in the headers and fill in * + * the nsig_file data structure. * + **********************************************************************/ +int nsig_read_record(FILE *fp, char *nsig_rec) +{ + int n; + int nbytes; + char *buf; + /* Input could be a chain of pipes. So read until no more data. + * For instance, a gzip pipe will write chunks of 4096 bytes, + * even when there is really more that we want to read. + */ + /* Return the number of bytes read. */ + buf = (char *)nsig_rec; + + if (feof(fp)) return -1; + nbytes = 0; + while((n = fread(&buf[nbytes], sizeof(char),NSIG_BLOCK-nbytes, fp)) > 0) { + nbytes += n; + } + return nbytes; +} + + +/********************************************************* + * Close nsig file * + *********************************************************/ +void nsig_close(FILE *fp) + { + rsl_pclose(fp); + } + +static int do_swap; + +int nsig_endianess(NSIG_Record1 *rec1) +{ + /* + * If NSIG is version1 and on big-endian, then swap. + * If NSIG is version2 and on little-endian, then swap. + */ + /* + printf("id = %d %d\n", (int)rec1->struct_head.id[0], (int)rec1->struct_head.id[1]); + */ + if (rec1->struct_head.id[0] == 0) { /* Possible little-endian */ + if (rec1->struct_head.id[1] >= 20) + /* This is a big-endian file. Typically, version 2. */ + do_swap = little_endian(); + else + do_swap = big_endian(); + } else if ((rec1->struct_head.id[1] == 0)) { /* Possible big-endian */ + if (rec1->struct_head.id[0] <= 7) + /* This is a little-endian file. Version 1. */ + do_swap = big_endian(); + } + /* + printf("DO SWAP = %d\n", do_swap); + */ + return do_swap; +} + +short NSIG_I2 (twob x) +{/* x is already a pointer. */ + short s; + memmove(&s, x, sizeof(twob)); + if (do_swap) swap_2_bytes(&s); + return s; +} + +int NSIG_I4 (fourb x) +{ /* x is already a pointer. */ + int i; + memmove(&i, x, sizeof(fourb)); + if (do_swap) swap_4_bytes(&i); + return i; +} + + +void nsig_free_ray(NSIG_Ray *r) +{ + if (r == NULL) return; + free(r->range); + free(r); +} + +void nsig_free_sweep(NSIG_Sweep **s) +{ + int i=0,itype; + if (s == NULL) return; + for (itype=0; itypenparams; itype++) { + if (s[itype] == NULL) continue; + + if (s[itype]->idh.data_type == NSIG_DTB_EXH) + free(s[itype]->ray[i]); + else { + for (i=0; iidh.num_rays_act); i++) + nsig_free_ray(s[itype]->ray[i]); + } + free(s[itype]->ray); + free(s[itype]); + } + free(s); +} + +static int ipos = 0; /* Current position in the data buffer. */ +static NSIG_Data_record data; + +int nsig_read_chunk(FILE *fp, char *chunk) +{ + int i, n; + int the_code; + int nwords, end_nwords; + + /* The information saved from call to call is 'data' and represents + * the data that has been buffered. When new data is needed + * it will be read from the file. 'ipos' is global and initially + * set in 'nsig_read_sweep'. Assumptions: chunk is big enough. + * + * Return number of bytes in 'chunk' -- this variable is 'i'. + */ + + i = n = 0; + the_code = 0; + +#define Vprint +#undef Vprint + while(the_code != 1) { + if (feof(fp)) return -1; + if (ipos == sizeof(data)) { /* the_code is in the next chunk */ +#ifdef Vprint + printf("Exceeded block size looking for the_code. Get it from next buffer.\n"); +#endif + n = nsig_read_record(fp, (char *)data); + if (n <= 0) return n; /* Problem. */ + +#ifdef Vprint + printf("Read %d bytes.\n", n); + printf("Resetting ipos\n"); +#endif + ipos = sizeof(NSIG_Raw_prod_bhdr); + } + +#ifdef Vprint + printf("ipos = %d -- ", ipos); +#endif + the_code = NSIG_I2(&data[ipos]); +#ifdef Vprint + printf("the_code = %d (%d) -- ", the_code, (unsigned short)the_code); +#endif + ipos += sizeof(twob); + + if (the_code < 0) { /* THIS IS DATA */ + nwords = the_code & 0x7fff; +#ifdef Vprint + printf("#data words (2-bytes) is %d\n", nwords); +#endif + if (ipos + sizeof(twob)*nwords > sizeof(data)) { +#ifdef Vprint + printf("Exceeded block size... transferring and reading new (i=%d).\n", i); +#endif + /* Need another phyical block. */ + + /* But, first transfer the remainder to the output chunk. */ + /* And, transfer begining of next block */ + /* Transfer end of current buffer. */ + end_nwords = (NSIG_BLOCK - ipos)/sizeof(twob); + memmove(&chunk[i], &data[ipos], sizeof(twob)*end_nwords); + i += end_nwords * sizeof(twob); + + n = nsig_read_record(fp, (char *)data); + if (n <= 0) return n; /* Problem. */ + /* New ipos */ + nwords -= end_nwords; + ipos = sizeof(NSIG_Raw_prod_bhdr); + + /* Transfer beginning of new buffer */ + if (i+nwords * sizeof(twob) > NSIG_BLOCK) return -1; + memmove(&chunk[i], &data[ipos], sizeof(twob) * nwords); + i += nwords * sizeof(twob); + ipos += nwords * sizeof(twob); + +#ifdef Vprint + printf("Words to transfer (at end of block) is %d\n", end_nwords); + printf("Transfer %d words from beginning of next buffer.\n", nwords); + printf("ipos in new buffer is %d\n", ipos); +#endif + } else { /* Normal situation. Position to end of data. + * But, first transfer it to the chunk. + */ + if (i+nwords * sizeof(twob) > NSIG_BLOCK) return -1; + memmove(&chunk[i], &data[ipos], sizeof(twob) * nwords); + i += nwords * sizeof(twob); + ipos += sizeof(twob) * nwords; + } + + } else if (the_code == 1) { /* END OF THE RAY. */ +#ifdef Vprint + printf("------------------------------> Reached end of ray.\n"); +#endif + break; /* or continue; */ + + } else if (the_code == 0) { /* UNKNOWN */ + break; + } else { /* NUMBER OF ZERO's */ +#ifdef Vprint + printf("#000000000000 to skip is %d (i=%d)\n", the_code, i); +#endif + if (i+the_code * sizeof(twob) > NSIG_BLOCK) return -1; + memset(&chunk[i], 0, the_code*sizeof(twob)); + i += the_code * sizeof(twob); + } + + if (ipos >= sizeof(data)) { +#ifdef Vprint + printf("Exceeded block size ... ipos = %d\n", ipos); + printf("This should be right at the end of the block.\n"); +#endif + n = nsig_read_record(fp, (char *)data); + if (n <= 0) return n; /* Problem. */ + ipos = sizeof(NSIG_Raw_prod_bhdr); + } + + } /* End while. */ + return i; +} + +NSIG_Ext_header_ver0 *nsig_read_ext_header_ver0(FILE *fp) +{ + NSIG_Data_record chunk; + int n; + NSIG_Ext_header_ver0 *xh0; + xh0 = NULL; + n = nsig_read_chunk(fp, (char *)chunk); + if (n <= 0) return xh0; +#ifdef Vprint + printf("Ver0 x-header. %d bytes found.\n", n); +#endif + n -= sizeof(NSIG_Ray_header); + xh0 = (NSIG_Ext_header_ver0 *)calloc(1, n); + if (xh0) memmove(xh0, &chunk[sizeof(NSIG_Ray_header)], n); + return xh0; +} + + +NSIG_Ext_header_ver1 *nsig_read_ext_header_ver1(FILE *fp) +{ + NSIG_Data_record chunk; + int n; + NSIG_Ext_header_ver1 *xh1; + xh1 = NULL; + n = nsig_read_chunk(fp, (char *)chunk); + if (n <= 0) return xh1; +#ifdef Vprint + printf("Ver1 x-header. %d bytes found.\n", n); +#endif + n -= sizeof(NSIG_Ray_header); + xh1 = (NSIG_Ext_header_ver1 *)calloc(1, n); + if (xh1) memmove(xh1, &chunk[sizeof(NSIG_Ray_header)], n); + return xh1; +} + +NSIG_Ray *nsig_read_ray(FILE *fp) +{ + int n, nbins; + NSIG_Ray_header rayh; + static NSIG_Data_record chunk; + NSIG_Ray *ray; + + n = nsig_read_chunk(fp, (char *)chunk); + /* Size of chunk is n */ + + if (n == 0) return NULL; /* Silent error. */ + + if (n < 0) { + fprintf(stderr, "nsig_read_ray: chunk return code = %d.\n", n); + return NULL; + } + + if (n > NSIG_BLOCK) { /* Whoa! */ + fprintf(stderr, "nsig_read_ray: chunk bigger than buffer. n = %d,\ + maximum block size allowed is %d\n", n, NSIG_BLOCK); + return NULL; + } + + ray = (NSIG_Ray *) calloc(1, sizeof(NSIG_Ray)); + memcpy(&ray->h, chunk, sizeof(NSIG_Ray_header)); + n -= sizeof(NSIG_Ray_header); +#ifdef Vprint + printf("nsig_read_ray: allocating %d bytes for range\n", n); +#endif + memcpy(&rayh, chunk, sizeof(NSIG_Ray_header)); + nbins = NSIG_I2(rayh.num_bins); + if (nbins <= 0) return NULL; +#ifdef Vprint + printf(" rayh.num_bins = %d (nbins %d, n %d)\n", NSIG_I2(rayh.num_bins), nbins, n); +#endif + ray->range = (unsigned char *)calloc(nbins, sizeof(unsigned char)); + memmove(ray->range, &chunk[sizeof(NSIG_Ray_header)], nbins); + + return ray; +} + + +NSIG_Sweep **nsig_read_sweep(FILE *fp, NSIG_Product_file *prod_file) +{ + NSIG_Sweep **s; + int i, n; + static NSIG_Ingest_data_header **idh = NULL; + static NSIG_Raw_prod_bhdr *bhdr = NULL; + NSIG_Ray *nsig_ray; + int data_mask, iray, nrays[12], max_rays; + int nparams; + int is_new_ray; + int idtype[12]; + int is_new_sweep; + int xh_size; + NSIG_Ext_header_ver0 *exh0; + NSIG_Ext_header_ver1 *exh1; + + /* + * The organization of a RAW PRODUCT FILE: (page III-38) + * + * Record #1 { 0, 0, 0... } + * Record #2 { 0, 0, 0... } + * Record #3 { Data...} \ + * Record #4 { Data...} \ + * . . . | Data for + * . . . / Sweep + * Record #N { Data 0...} / #1 + * Record #N+1 { Data...} \ + * Record #N+2 { Data...} \ + * . . . | Data for + * . . . / Sweep + * Record #M { Data 0...} / #2 + * + * What about the order of info in 'Data'? + * Data, when it begins a sweep: + * a. Raw Product Bhdr + * b. Ingest data header for param 1 + * . + * . + * Ingest data header for param n+1 + * c. Ray header + * d. Ray data + * + * Ray header and Ray data are encoded with the compression algorithm. + * If Ray data spans more than one physical NSIG BLOCK (6144 bytes), + * then the 'Data' consists of: + * a. Raw Product Bhdr + * b. Ray header + * c. Ray data + * + * It is just missing all the Ingest data header fields. + */ + +#define Vprint +#undef Vprint + /* Determine if we need to byte-swap values. */ + (void)nsig_endianess(&prod_file->rec1); + + /* Setup the array of ingest data headers [0..nparams-1] */ + memmove(&data_mask, prod_file->rec2.task_config.dsp_info.data_mask, sizeof(fourb)); +#ifdef Vprint + printf("data_mask %x\n", data_mask); +#endif + for (nparams=i=0; i<32; i++) + nparams += (data_mask >> i) & 0x1; + /* Number of sweeps */ +#ifdef Vprint + {int nsweeps; + nsweeps = NSIG_I2(prod_file->rec2.task_config.scan_info.num_swp); + printf("nsig2.c:::nparams = %d, nsweeps = %d\n", nparams, nsweeps); + } +#endif + + + if (idh == NULL) { + + idh = (NSIG_Ingest_data_header **)calloc(nparams, sizeof(NSIG_Ingest_data_header *)); + ipos = 0; + for (i=0; idata; + } + + xh_size = NSIG_I2(prod_file->rec2.ingest_head.size_ext_ray_headers); +#ifdef Vprint + {int rh_size; + rh_size = NSIG_I2(prod_file->rec2.ingest_head.size_ray_headers); + printf("Extended header is %d bytes long.\n", xh_size); + printf(" Ray header is %d bytes long.\n", rh_size); + } +#endif + is_new_ray = 1; + is_new_sweep = 1; + max_rays = NSIG_I2(prod_file->rec2.ingest_head.num_rays); + + /* Ingest initial block for the sweep. All remaining I/O will + * be performed in the de-compression loop. + */ + if (feof(fp)) return NULL; + n = nsig_read_record(fp, (char *)data); + if (n <= 0) return NULL; +#ifdef Vprint + printf("Read %d bytes for data.\n", n); +#endif + + + /* This is a NEW sweep. */ + iray = 0; +#ifdef Vprint + {int isweep; + isweep = NSIG_I2(idh[0]->sweep_num); + printf("Number of rays in sweep %d is %d\n", isweep, max_rays); + } +#endif + /* Allocate memory for sweep. */ + s = (NSIG_Sweep **) calloc (nparams, sizeof(NSIG_Sweep*)); + + /* Now pointers to all possible rays. */ + for (i=0; inparams = nparams; + memmove(&s[i]->bhdr, &bhdr, sizeof(NSIG_Raw_prod_bhdr)); + memmove(&s[i]->idh, idh[i], sizeof(NSIG_Ingest_data_header)); + s[i]->ray = (NSIG_Ray **) calloc (max_rays, sizeof(NSIG_Ray *)); + } + + /* Process this sweep. Keep track of the end of the ray. */ + ipos = sizeof(NSIG_Raw_prod_bhdr); /* Position in the 'data' array */ + + max_rays = 0; + for (i=0; idata_type); + nrays[i] = (int)NSIG_I2(idh[i]->num_rays_act); + if (nrays[i] > max_rays) max_rays = nrays[i]; +#ifdef Vprint + printf("New ray: parameter %d has idtype=%d\n", i, idtype[i]); + printf("Number of expected rays in sweep %d is %d\n", isweep, (int)NSIG_I2(idh[i]->num_rays_exp)); + printf("Number of actual rays in sweep %d is %d\n", isweep, (int)NSIG_I2(idh[i]->num_rays_act)); +#endif + + } + if (is_new_sweep) + ipos += nparams * sizeof(NSIG_Ingest_data_header); + + /* ipos = sizeof(NSIG_Raw_prod_bhdr) + nparams*sizeof(NSIG_Ingest_data_header); */ + /* 'iray' is the true ray index into 's', whereas, 'nsig_iray' is what + * the NSIG file says it is. I'll trust 'iray' + * + * I have a cursor into the 'data' buffer representing my current + * position for processing rays. This cursor will dictate if I read + * a new NSIG block. The cursor is call 'ipos'. It is initialized + * each time a new ray is encountered. + */ + +#ifdef Vprint + { int ioff, nsig_iray; + /* Check that all idh pointers 'id' is Ingest data header. */ + ioff = NSIG_I2(bhdr->ray_loc); + nsig_iray = NSIG_I2(bhdr->ray_num); + printf("Offset to begining of ray %d is %d, iray=%d\n", nsig_iray, ioff,iray); + } +#endif + + /* DECODE THE DATA HERE */ + /* From III-39 */ + /* + * Table 3.5-5 + * Compression Code Meanings + * + * MSB LOW-bits Meaning + * 0 0 + * 0 1 End of ray. + * 0 2 + * 0 3-32767 3 to 32767 zeros skipped. + * 1 0 + * 1 1-32767 1 to 32767 data words follow. + */ + + do { +#ifdef Vprint + printf("---------------------- New Ray <%d> --------------------\n", iray); +#endif + if (feof(fp)) { /* Premature eof */ + return NULL; /* This will have to do. */ + } + /* For all parameters present. */ + is_new_ray = 0; + for (i=0; irange = (unsigned char *)exh0; + } + } else { + exh1 = nsig_read_ext_header_ver1(fp); + if (exh1) { + nsig_ray = (NSIG_Ray *)calloc(1, sizeof(NSIG_Ray)); + nsig_ray->range = (unsigned char *)exh1; + } + } + } + if (nsig_ray) is_new_ray = 1; + if (iray > nrays[i]) break; + s[i]->ray[iray] = nsig_ray; + + } /* End for */ + if (is_new_ray) iray++; + + } while (iray < max_rays); +#ifdef Vprint + printf("iray = %d\n", iray); +#endif + return s; + +} + +/************************************************** + * Convert 2 byte binary angle to floating point * + **************************************************/ +float nsig_from_bang(bang in) + { + float result,maxval = 65536.0; + unsigned short bi_ang; + + memmove(&bi_ang, in, sizeof(bang)); + if (do_swap) swap_2_bytes(&bi_ang); + result = ((float)(bi_ang)/maxval) * 360.0; + + return (result); + } + +/************************************************* + * convert 4 byte binary angle to floating point * + *************************************************/ +float nsig_from_fourb_ang(fourb ang) + { + double result,maxval; + unsigned int bi_ang; + + maxval = 4294967296.0; + + memmove(&bi_ang, ang, sizeof(fourb)); + if (do_swap) swap_4_bytes(&bi_ang); + + result = ((double)(bi_ang)/maxval) * 360.0; + + return ((float)result); + } diff --git a/nsig.h b/nsig.h new file mode 100644 index 0000000..63e44a5 --- /dev/null +++ b/nsig.h @@ -0,0 +1,921 @@ +/* For SIGMET version 1 and version 2 files. + * + * John H. Merritt + * Applied Research Corp. + * NASA GSFC Code 910.1 + * + * + * The structures exactly match the SIGMET documentation. + */ + +#ifndef NSIG2_H +#define NSIG2_H + +/*Structure identifier, byte 0 of structure_header, III-18 */ +#define NSIG_INGEST_SUM 3 +#define NSIG_PROD 7 + +/* Data type, value for byte 22 in ingest data header, III-29 */ +#define NSIG_DTB_EXH 0 +#define NSIG_DTB_UCR 1 +#define NSIG_DTB_CR 2 +#define NSIG_DTB_VEL 3 +#define NSIG_DTB_WID 4 +#define NSIG_DTB_ZDR 5 +#define NSIG_DTB_KDP 14 +#define NSIG_DTB_PHIDP 16 +#define NSIG_DTB_SQI 18 +#define NSIG_DTB_RHOHV 19 + +/* Product type code ,value for byte 12 in product configuration + * struct, III-35 + */ +#define NSIG_PROD_PPI 1 /* PPI */ +#define NSIG_PROD_RHI 2 /* RHI */ +#define NSIG_PROD_CAPPI 3 /* CAPPI */ +#define NSIG_PROD_CROSS 4 /* Cross section */ +#define NSIG_PROD_TOPS 5 /* Echo tops */ +#define NSIG_PROD_RAIN1 7 /* Precipitation 1 hour */ +#define NSIG_PROD_TRACK 6 /* Storm track */ +#define NSIG_PROD_RAINN 8 /* Precipitation n hour */ +#define NSIG_PROD_VVP 9 /* Velocity Volume processing */ +#define NSIG_PROD_VIL 10 /* Vertically Integrated Liquid */ +#define NSIG_PROD_SHEAR 11 /* Wind shear */ +#define NSIG_PROD_WARN 12 /* Warning (overlay) */ +#define NSIG_PROD_RTPPI 13 /* Real time PPI */ +#define NSIG_PROD_RTRHI 14 /* Real time RHI */ +#define NSIG_PROD_RAW 15 /* Raw data set (no display)*/ +#define NSIG_PROD_MAX 16 /* Maximum with side panels */ +#define NSIG_PROD_USER 17 /* Earth projection user product */ +#define NSIG_PROD_USERV 18 /* Section projection user product */ +#define NSIG_PROD_OTHER 19 /* Other user product (no display) */ +#define NSIG_PROD_STATUS 20 /* Status product (no display) */ +#define NSIG_PROD_SLINE 21 /* Shear Line Product */ +#define NSIG_PROD_WIND 22 /* Horizontal wind field */ + +#define NSIG_SCAN_PPI 1 +#define NSIG_SCAN_RHI 2 +#define NSIG_SCAN_MAN 3 +#define NSIG_SCAN_CON 4 +#define NSIG_SCAN_FIL 5 + +#define NSIG_BLOCK 6144 +#define NSIG_MAX_BIN 1536 + +/* Two byte binary angle is unsigned short */ +/* Using these typedefs forces non-word alignment. This is because + * we don't want any space between members of a structure. + * -- A coding trick -- + */ +typedef unsigned char bang[2]; +typedef unsigned char twob[2]; +typedef unsigned char fourb[4]; + +/* Ray header 3.4.2, page III-29 */ +/* No change for NSIG_VER2 */ +typedef struct { + bang beg_azm; /* Azimuth at beginning of ray (binary angle). */ + bang beg_elev; /* Elevation at beginning of ray (binary angle). */ + bang end_azm; /* Azimuth at end of ray (binary angle). */ + bang end_elev; /* Elevation at end of ray (binary angle). */ + twob num_bins; /* Actual number of bins in the ray. */ + twob sec; /* Time in seconds from start of sweep (unsigned). */ +} NSIG_Ray_header; +/*============================================================*/ +/*============================================================*/ + +/* Extended Header version 0, section 3.4.3, page III-29 */ +/* No change for NSIG_VER2 */ +typedef struct { + fourb msec; + twob cal_sig; + twob spare[7]; +} NSIG_Ext_header_ver0; +/*============================================================*/ +/*============================================================*/ + +/* Extended Header version 1, section 3.4.3, page III-29 */ +typedef struct { + fourb msec; /* Time in milliseconds from the sweep starting time. */ + twob cal_sig; /* Calibration Signal level. */ + bang azm; /* Azimuth (binary angle) */ + bang elev; /* Elevation (binary angle) */ + bang train_ord; /* Train order (binary angle) */ + bang elev_ord; /* Elevation order (binary angle) */ + bang pitch; /* Pitch (binary angle) */ + bang roll; /* Roll (binary angle) */ + bang heading; /* Heading (binary angle) */ + bang azm_rate; /* Azimuth Rate (binary angle/sec) */ + bang elev_rate; /* Elevation Rate (binary angle/sec) */ + bang pitch_rate; /* Pitch Rate (binary angle/sec) */ + bang roll_rate; /* Roll Rate (binary angle/sec) */ +#ifdef NSIG_VER2 + +#else + bang heading_rate; /* Heading Rate (binary angle/sec) */ +#endif + fourb lat; /* Latitude (binary angle) */ + fourb lon; /* Longitude (binary angle) */ + twob alt; /* Altitude (meters) */ + twob vel_e; /* Velocity East (cm/sec) */ + twob vel_n; /* Velocity North (cm/sec) */ + twob vel_u; /* Velocity Up (cm/sec) */ +#ifdef NSIG_VER2 + +#else + fourb time_update; /* Time since last update (milliseconds) */ +#endif + twob nav_sys_flag; /* Navigation system OK flag */ + twob rad_vel_cor; /* Radial velocity correction (velocity units) */ +} NSIG_Ext_header_ver1; +/*============================================================*/ +/*============================================================*/ + + + + +/*-----------------------------------------------------------------*/ +/* Note: + * All structure names are prefixed with NSIG_ and have the + * first letter of the remainder capitalized. + */ +/*-----------------------------------------------------------------*/ + +/* Structure header 3.2.35, page III-18 */ +typedef struct { + twob id; +#ifdef NSIG_VER2 + twob version; + fourb num_bytes; +#else + fourb num_bytes; + twob version; +#endif + twob spare; + twob flags; +} NSIG_Structure_header; +/*============================================================*/ +/*============================================================*/ + +/* Time sturcture 3.2.36, page III-18 */ +typedef struct { +#ifdef NSIG_VER2 + fourb sec; + twob msec; /* Fractions of seconds in milliseconds. */ + twob year; + twob month; + twob day; +#else + twob year; + twob month; + twob day; + fourb sec; +#endif +} NSIG_Ymds_time; +/*============================================================*/ +/*============================================================*/ + +/* ingest data header 3.4.1, page III-28 */ +typedef struct { + NSIG_Structure_header struct_head; + NSIG_Ymds_time time; +#ifdef NSIG_VER2 +#else + twob data_type; +#endif + twob sweep_num; + twob num_rays_swp; + twob ind_ray_one; + twob num_rays_exp; + twob num_rays_act; + bang fix_ang; + twob bits_bin; +#ifdef NSIG_VER2 + twob data_type; /* Data code (See Task_DSP_Info.IDATA) */ + char spare[36]; +#else + char spare[38]; +#endif +} NSIG_Ingest_data_header; +/*============================================================*/ +/*============================================================*/ + +/* No change for NSIG_VER2 */ +typedef struct { + twob rec_num; + twob sweep_num; + twob ray_loc; + twob ray_num; + twob flags; + twob spare; +} NSIG_Raw_prod_bhdr; +/*============================================================*/ +/*============================================================*/ +#ifdef NSIG_VER2 +/* Define the color scale conversion */ +typedef struct { +#define COLOR_SCALE_OVERRIDE (0x0200) +#define COLOR_SCALE_VARIABLE (0x0100) +#define COLOR_LABEL_MASK (0x00ff) + fourb iflags; + fourb istart; + fourb istep; + twob icolcnt; + twob ipalette_num; + twob ilevel_seams[16]; +} NSIG_Color_scale_def; +#endif +/*============================================================*/ +/*============================================================*/ + +/* Product configuration structure 3.5.1.1, page III-35 */ +typedef struct { + NSIG_Structure_header st_head; + twob prod_code; +#ifdef NSIG_VER2 + twob isch; /* Scheduling */ +#define PSC_HOLD_P 0 /* Do not run at all. */ +#define PSC_NEXT_P 1 /* Run once on next available data */ +#define PSC_ALL_P 2 /* Run as data becomes available */ +#define PSC_AGAIN_P 3 /* Run again on data last used */ + + fourb isch_skip; /* # seconds between runs */ + +#else + +#endif + NSIG_Ymds_time prod_time; + NSIG_Ymds_time file_time; + NSIG_Ymds_time schd_time; + twob schd_code; /* Not used in Ver 2. */ + fourb sec_skip; /* Not used in Ver 2. */ + char user_name[12]; +#ifdef NSIG_VER2 + +#else + char file_name[12]; +#endif + char task_name[12]; +#ifdef NSIG_VER2 + +#else + char spare_name[12]; +#endif + twob flag; +#ifdef NSIG_VER2 + fourb ixscale, iyscale, izscale; /* Scale in cm/pixel */ +#else + +#endif + fourb x_size; + fourb y_size; + fourb z_size; + fourb x_loc; + fourb y_loc; + fourb z_loc; + fourb max_rng; +#ifdef NSIG_VER2 + fourb irange_last_v20; /* Range of last bin in cm (raw only) */ + char ipad128x2[2]; + twob idata_out; /* Data type of data generated by product gen */ + + /* This section for version 2.1+ products: */ + char ipad132x12[12]; + twob idata_in; /* Data type used by the generator */ + char ipad146x2[2]; + twob iradial_smooth; /* Range in km*100 over which radial */ + /* smoothing should be done. 0:none. */ + twob iruns; /* # of times this pcf has been run */ + fourb izr_const; /* Z-R or Z-W constant and exponent */ + fourb izr_exp; /* in 1/1000 of integers */ + twob ix_smooth; /* X-Y Smoothing parameters for 2D */ + twob iy_smooth; /* products. km*100, 0:none */ + + /* ---- Product Specific Parameters ---- */ + /*The following area conveys information needed for each specific product.*/ + + char psi[80]; /* Do we need these?? -John 8/14/96 */ + + char ipad244x28[28]; + NSIG_Color_scale_def colors; + +#else + + twob bits_item; + twob data_type; + fourb data_start; + fourb data_step; + twob num_col; + /* The following depends on version 2.0, 2.1 etc check III-34,35 */ + /* Currently, though, this is not used. */ + char spare[178]; +#endif +} NSIG_Product_config; +/*============================================================*/ +/*============================================================*/ + + +/* product end 3.5.1.2 ,page III-36 */ +typedef struct { +#ifdef NSIG_VER2 + char sprod_sitename[16]; /* Name of product generator site, space padded */ + char sprod_version[8]; /* Product IRIS version, null terminated */ + char sing_version[8]; /* Ingest IRIS version, null terminated */ + NSIG_Ymds_time data_time; /* Oldest data in this file */ + char ipad44x46[42]; +#else + char part_name[80]; /* Path name of file on disk. */ + NSIG_Ymds_time data_time; /* Date/time structure. */ +#endif + char site_name[16]; /* Site name. Eg. mit, tog, kwa (upper-case?). */ + twob ahead_gms; /* # minutes ahead of GMT. */ + fourb lat; /* Latitude (binary angle format). */ + fourb lon; /* Longitude (binary angle format). */ + twob grnd_sea_ht; /* Signed ground height (meters). */ + twob rad_grnd_ht; /* Radar height above ground (meters). */ +#ifdef NSIG_VER2 + +#else + twob sig_proc; /* Type of signal processor used. */ +#endif + fourb prf; /* PRF (hz). */ + fourb pulse_wd; /* sample width in microsec/100*/ +#ifdef NSIG_VER2 + twob sig_proc; /* Type of signal processor used. */ +#else + +#endif + twob trg_rate; /* Trigger rate scheme. */ + twob num_samp; /* number of samples (per ray). */ + char clutter_file[12]; /* Clutter filter file name. */ + twob num_filter; /* Number of filter used for the first range bin. */ + fourb wavelen; /* Wavelength in 1/100 of centimeters. */ + fourb trunc_ht; /* Truncation height in cm. */ + fourb rng_f_bin; /* Range of the first bin in cm. */ + fourb rng_l_bin; /* Range of the last bin in cm. */ + fourb num_bin; /* Number of output bins. */ + twob flag; /* Flag word. */ +#define PH_OVERLAY_P (0x0001) /* Has an overlay \ For picture */ +#define PH_RINGS_P (0x0002) /* Has range rings/ products only */ + + twob file_up; /* Number of updates to the file. */ + char label[16][4]; /* Array of labels for color parameter legend. */ +#ifdef NSIG_VER2 + twob ilog_filter_first; /* Log filter used on first bin */ + char ipad238x10[10]; +#else + char label_unit[12]; /* Text holding units of the labels. (Ver 2 only) */ +#endif + twob prod_seq; /* Product sequence number. */ + twob color_num[16]; /* Color numbers for the up to 16 steps. */ + char color_reject; /* Color used for rejected data. */ +#ifdef NSIG_VER2 + char ipad283x2[3]; + + /* The number of results elements at the end of the file. + * Used for warning, shearline, and track only */ + twob iresults_count; + +#define PROD_END_PAD (20) + char ipad_end[PROD_END_PAD]; +#else + char color_unscan; /* Color used for unscanned area. */ + char color_over; /* Color used for overlays. */ + char spare; + fourb prod_max_rng; /* Max range of the first product used as input. */ + char spare2[18]; +#endif +} NSIG_Product_end; +/*============================================================*/ +/*============================================================*/ + +/* Ingest Summary Header 3.3.1 , page III-19 */ +typedef struct { + char file_name[80]; /* Name of file on disk. */ + twob num_file; /* Number of associated data files extant. */ +#ifdef NSIG_VER2 + twob isweeps_done ; /* # of sweeps that have been completed */ +#endif + fourb sum_size; /* Total size of all files in bytes. */ + NSIG_Ymds_time start_time; +#ifdef NSIG_VER2 + char ipad100x12[12]; +#else + char drive_name[16]; /* Name of tape drive written to. */ +#endif + twob size_ray_headers; /* Number of bytes in the ray headers. */ + twob size_ext_ray_headers; /* Number of bytes in extended ray headers. */ +#ifdef NSIG_VER2 + twob ib_task; /* # bytes in task config table */ + char ipad_118x6[6]; + char siris_version[8]; /* Null terminated */ + char ipad_132x18[18]; +#else + twob num_task_conf_tab; /* Number of task configuration table. */ + twob size_device_status_tab; /* Number of bytes in device status table. */ + twob gparam_size; /* Number of bytes in each gparam. */ + char spare[28]; +#endif + char site_name[16]; /* Name of site from setup program. */ + twob time_zone; /* Time zione of recorded time, +min of GMT */ + fourb lat_rad; /* Latitude of radar. */ + fourb lon_rad; /* Longitude of radar. */ + twob grd_height; /* Height of ground at site (meters) */ + twob ant_height; /* Height of radar above ground (meters) */ + twob azm_res; /* Resolution of delta azimuth in sweep. */ + twob ray_ind; /* Index of first rays from above set of rays. + * Or the angle of the first ray. + */ + twob num_rays; /* Number of rays in a sweep. */ + fourb ant_alt; /* Altitude of radar above sea level in cm */ + fourb vel[3]; /* [0]=east, [1]=north, [2]=up */ + fourb ant_offset[3]; /* [0]=starboard, [1]=bow, [2]=up */ +#ifdef NSIG_VER2 + char spare2[264]; +#else + char spare2[266]; +#endif +} NSIG_Ingest_summary; +/*============================================================*/ +/*============================================================*/ + +/* rvp5_gparam structure 3.3.4.1, page III-26 */ +typedef struct { + twob revision; /* Revision */ + twob num_bins; /* Number of range bins */ + twob cur_trig_p; /* Current trigger period */ + twob cur_tag1; /* Current TAG00 - TAG15 */ + twob cur_tag2; /* Current TAG16 - TAG31 */ + twob l_chan_noise; /* Log channel noise level */ + twob i_chan_noise; /* I Channel noise level */ + twob q_chan_noise; /* Q Channel noise level */ + twob lat_proc_status;/* Latched processor status */ + twob imm_proc_status;/* Immdiate processor status */ + twob diag_reg_a; /* Diagnostic register A */ + twob diag_reg_b; /* Diagnostic register B */ + twob num_pulses; /* Number of pulses per ray */ + twob trig_c_low; /* Trigger count (low 16 bits) */ + twob trig_c_high; /* Trigger count (high 8 bits) */ + twob num_acq_bins; /* # of properly acquired bins */ + twob num_pro_bins; /* # of properly processed bins */ + twob rng_off; /* 25-meter range offset */ + twob noise_rng; /* Noise range in KM */ + twob noise_trg; /* Noise trigger period */ + twob pulse_w_0; /* Pulse width 0 min trig period */ + twob pulse_w_1; /* Pulse width 1 min trig period */ + twob pulse_w_2; /* Pulse width 2 min trig period */ + twob pulse_w_3; /* Pulse width 3 min trig period */ + twob pulse_w_pat; /* Pulse width bit patterns */ + twob cur_wave_pw; /* Current waveform/pulsewidth */ + twob cur_trig_gen; /* Current trigger gen period */ + twob des_trig_gen; /* Desired trigger gen period */ + twob prt_start; /* PRT at start of last ray */ + twob prt_end; /* PRT at end of last ray */ + twob proc_thr_flag; /* Processing/threshold flags */ + twob log_con_slope; /* LOG conversion slope */ + twob log_noise_thr; /* LOG noise threshold */ + twob clu_cor_thr; /* Clutter correction threshold */ + twob sqi_thr; /* SQI threshold */ + twob log_thr_w; /* LOG threshold for width */ + twob cal_ref; /* Calibration reflectivity */ + twob q_i_cur_samp; /* Q and I current sample */ + twob l_cur_samp; /* Log current sample */ + twob rng_avr_cho; /* Range averaging choice */ + twob spare1[3]; + twob i_sqr_low; + twob i_sqr_high; + twob q_sqr_low; + twob q_sqr_high; + twob noise_mean; + twob noise_std; + twob spare2[15]; +} NSIG_Rpv5_gparam; +/*============================================================*/ +/*============================================================*/ + +typedef struct { + NSIG_Structure_header struct_head; + NSIG_Rpv5_gparam rpv5; +} NSIG_Gparam; +/*============================================================*/ +/*============================================================*/ + +/* One_device_structure. Sect: 3.3.3.1 */ +#ifdef NSIG_VER2 +typedef struct { + fourb status; +#define DEV_NULL_P (0) /*Not applicable*/ +#define DEV_OK_P (1) /*OK*/ +#define DEV_ERROR_P (2) /*Error has occured*/ +/* The following are only valid for network devices */ +#define DEV_REMOTE_P (5) /*Remote computer unavailable*/ +#define DEV_IRIS_P (6) /*Remote IRIS unavailable*/ + +/* This number indicates which process is using the device. */ + fourb process; +#define PROC_NONE_P (0) /*Noone is using it*/ +#define PROC_RTDISP_P (1) /*Real time display*/ +#define PROC_INGEST_P (2) /*Ingest*/ +#define PROC_INGFIO_P (3) /*Ingest file output*/ +#define PROC_REINGEST_P (4) /*Reingest !!!tom */ +#define PROC_OUTFMT_P (5) /*Output Formatter*/ +#define PROC_PRODUCT_P (6) /*Product generator*/ +#define PROC_NETWORK_P (7) /*Network !!!tom */ +#define PROC_QUICK_P (8) /*Quick look menu(part of out)*/ +#define PROC_TAPE_P (9) /*Tape process*/ +#define PROC_NORDRAD_P (10) /*NORDRAD process*/ + + /* Node name or user name */ + char nuser_name[16]; + /* Number of characters in the name */ + char nchar; + /* Process mode, see process_status structure */ + fourb imode; +#define MODE_NULL (0) +#define MODE_STOPPED (1) +#define MODE_IDLE (2) +#define MODE_RUNNING (3) +#define MODE_EXIT (4) +#define MODE_QUICK (5) +#define MODE_INIT (6) +#define MODE_HOLD (7) + +/* Used only for antenna device */ +#define MODE_ANT_NULL (0) +#define MODE_ANT_IRIS (1) +#define MODE_ANT_LOCAL (2) +#define MODE_ANT_MAIN (3) +#define MODE_ANT_COMP (4) +#define MODE_ANT_SHUT (5) + char spare[8]; +} NSIG_One_device; +#else +typedef struct { + twob status; + twob process; + char user_name[15]; + char nchar; + char spare[10]; +} NSIG_One_device; +/*============================================================*/ +/*============================================================*/ +#endif + +typedef struct { +#ifdef NSIG_VER2 +/* THIS IS WRONG.... but, does it matter for RSL ???? */ + NSIG_Structure_header struct_head; + NSIG_One_device dsp_stat[4]; + NSIG_One_device ant_stat[4]; + NSIG_One_device outdev_stat[12]; + char spare[120]; +#else + NSIG_Structure_header struct_head; + NSIG_One_device dsp_stat[4]; + NSIG_One_device ant_stat[4]; + NSIG_One_device outdev_stat[12]; + char spare[120]; +#endif +} NSIG_Device_status; +/*============================================================*/ +/*============================================================*/ + +/* No change for NSIG_VER2 */ +typedef struct { + fourb startt; /* Start time (seconds within a day) */ + fourb stopt; /* Stop time (seconds within a day) */ + fourb skipt; /* Desired skip time (seconds) */ + fourb time_last; /* Time last run (seconds w/in a day) */ + fourb time_used; /* Time used on last run (seconds) */ + fourb day_last; /* Relative day of last run. */ + twob iflag; /* bit 0=ASAP, bit 1= Mandatory, + * bit 2=Late skip, bit 3= Time used has been measured, + * bit 4=Stop after running. + */ + char spare[94]; +} NSIG_Task_sched_info; +/*============================================================*/ +/*============================================================*/ + + +/* Task dsp info 3.3.2.2, page III-22 */ +typedef struct { +#ifdef NSIG_VER2 + twob dsp_num; + fourb dsp_type; +#else + twob dsp_num; + twob dsp_type; +#endif + fourb data_mask; + fourb aux_data_def[32]; + fourb prf; + fourb pwid; + twob prf_mode; + twob prf_delay; + twob agc_code; + twob samp_size; + twob gain_con_flag; + char filter_name[12]; +#ifdef NSIG_VER2 + char idop_filter_first; /* Doppler based filter used on first bin */ + char ilog_filter_first; /* Z based filter used on first bin */ +#else + twob f_num; +#endif + twob atten_gain; +#ifdef NSIG_VER2 + twob igas_atten ; /* 100000 * db/km */ +#define TASK_DSP_INFO_PAD (148) + char ipad_end[TASK_DSP_INFO_PAD]; +#else + char spare[150]; +#endif +} NSIG_Task_dsp_info; +/*============================================================*/ +/*============================================================*/ + +/* task cal info struct: 3.3.2.3, page III-22, rec 2 offset 944 */ +/* No change for NSIG_VER2 */ +typedef struct { + twob slope; /* 00: Reflectivity slope (4096*dB/ A/D Count) */ + twob noise; /* 02: Noise threshold (1/16 dB above noise) */ + twob clutr_corr; /* 04: Clutter correction threshold (1/16 dB) */ + twob sqi; /* 06: (0-1)*256 */ + twob power; /* 08: (1/16 dBZ) */ + char spare1[8]; /* 10: 8 */ + twob cal_ref; /* 18: Calibration reflectivity */ + twob z_flag_unc; /* 20: Threshold flags for Unc. reflectivity */ + twob z_flag_cor; /* 22: Threshold flags for Cor. reflectivity */ + twob v_flag; /* 24: Threshold flags for velocity */ + twob w_flag; /* 26: Threshold flags for width */ + char spare2[8]; /* 28: 8 */ + twob speckle; /* 36: Speckle remover flag. See III-22 */ + twob slope_2; /* 38: Refl. slope for second processor */ + twob cal_ref_2; /* 40: Calibration reflectivity for 2nd proc */ + twob zdr_bias; /* 42: ZDR bias in signed 1/16 dB */ + char spare3[276]; /* 44: 276 */ +} NSIG_Task_calib_info; +/*============================================================*/ +/*============================================================*/ + + +/* Task_range_info Structure 3.3.2.4, page III-23 */ +typedef struct { + fourb rng_first; /* 00: Range to first bin [cm] */ + fourb rng_last; /* 04: Range to last bin [cm] */ +#ifdef NSIG_VER2 + fourb ibin_last; /* Range of last (input) bin in cm */ +#else +#endif + twob num_bins; /* 08: Number of input bins */ + twob num_rngbins; /* 10: Number of output range bins */ + twob var_bin_spacing; /* 12: Variable range bin spacing (0,1) */ + fourb binstep_in; /* 14: Step between input bins */ + fourb binstep_out; /* 18: Step between output bins */ + twob bin_avg_flag; /* 22: Range bin averaging flag */ + /* 0:No Avg, 1:Avg Pairs, ... */ +#ifdef NSIG_VER2 + char spare[132]; /* 24: 132 */ +#else + char spare[136]; /* 24: 136 */ +#endif +} NSIG_Task_range_info; +/*============================================================*/ +/*============================================================*/ + + +/* Task scan info structure 3.3.2.5, page III-23 */ +typedef struct { + twob ant_scan_mode; /* 1:PPI, 2:RHI, 3:manual, 4:file */ + twob ang_res; /* Desired angular resolution in 1/100 degree. */ +#ifdef NSIG_VER2 + bang iscan_speed ; +#else + twob spare1; +#endif + twob num_swp; /* Number of sweeps to perform. */ + bang beg_ang; /* Starting elevation(RHI)/azimuth(PPI) */ + bang end_ang; /* Ending elevation(RHI)/azimuth(PPI) */ + bang list[40]; /* List of azimuths(RSI)/elevations(PPI) */ +#ifdef NSIG_VER2 + /* +union serv_task_scan_info_u +{ + struct serv_task_rhi_scan_info rhi; + struct serv_task_ppi_scan_info ppi; + struct serv_task_file_scan_info fil; + struct serv_task_manual_scan_info man; +} ; +*/ + char spare2[116]; +#else + char spare3[112]; +#endif +} NSIG_Task_scan_info; +/*============================================================*/ +/*============================================================*/ + +typedef struct { + fourb wavelength; /* Wavelength in 1/100 of cm */ + char serial_num[16]; /* T/R Serial Number */ + fourb xmit_pwr; /* Transmit Power in watts. */ + twob flag; /* bit 0: Digital signal simulator in use. + * bit 4: Keep bit. + */ +#ifdef NSIG_VER2 + twob ipolar; /* Type of polarization, see dsp_lib.h */ + fourb itrunc; /* Truncation height in cm */ + char ipad32x18[18]; /* Reserved for polarization description */ + +#else + char spare1[24]; +#endif + twob display_parm1; /* Real time display parameter #1 */ + twob display_parm2; /* Real time display parameter #2 */ + /* The following 3 members are not used in Ver 2. */ + twob product_flag; /* Real time product flag */ + char spare2[2]; + fourb truncation_height;/* Truncation height (cm) */ + twob nbytes_comments; /* Number of bytes of comments entered. */ + char spare3[256]; +} NSIG_Task_misc_info; + +typedef struct { + twob major; /* Task major number */ + twob minor; /* Task minor number */ + char name[12]; /* Name of task configuration file. */ + char desc[80]; /* Task description. */ +#ifdef NSIG_VER2 + fourb ihybrid_count; /* Number of tasks in this hybrid set */ +#else + +#endif + twob state; /* Task state: 0=no task, 1=task being modified, + * 2=inactive, 3=scheduled, 4=running + */ +#ifdef NSIG_VER2 + char spare[218]; +#else + char spare[222]; +#endif +} NSIG_Task_end_data; +/*============================================================*/ +/*============================================================*/ + + +typedef struct { + NSIG_Structure_header struct_head; + NSIG_Task_sched_info sched_info; + NSIG_Task_dsp_info dsp_info; + NSIG_Task_calib_info calib_info; + NSIG_Task_range_info range_info; + NSIG_Task_scan_info scan_info; + NSIG_Task_misc_info misc_info; + NSIG_Task_end_data end_data; +#ifdef NSIG_VER2 +char comments[720]; +#else + +#endif +} NSIG_Task_config; +/*============================================================*/ +/*============================================================*/ + + +typedef struct { + NSIG_Structure_header struct_head; + NSIG_Product_config prod_config; + NSIG_Product_end prod_end; + char spare[5504]; +} NSIG_Record1; +/*============================================================*/ +/*============================================================*/ + +typedef struct { + NSIG_Structure_header struct_head; + NSIG_Ingest_summary ingest_head; + NSIG_Task_config task_config; + NSIG_Device_status device_stat; + NSIG_Gparam dsp1; + NSIG_Gparam dsp2; + char spare[1260]; +} NSIG_Record2; +/*============================================================*/ +/*============================================================*/ + + +/* This is the organization of the 2'nd to n'th file on the tape. + * This structure is incomplete in that only one data record is + * listed. Record 1, Record 2, a data record. As each data record + * is ingested, the data replaces the data record part and keeps + * the information in Record 1 and 2 unchanged. + */ +typedef unsigned char NSIG_Data_record[NSIG_BLOCK]; + +typedef struct { + NSIG_Record1 rec1; + NSIG_Record2 rec2; + NSIG_Data_record data; +} NSIG_Product_file; +/*============================================================*/ +/*============================================================*/ + + +/* This is the first physical file on the TAPE. It is the only + * file on the tape that has this organization. All other files + * are PRODUCT FILES (NSIG_Product_file). Normally, this is ignored + * when reading disk files; there you're only reading PRODUCT FILES. + */ +typedef struct { + NSIG_Structure_header struct_head; + char tape_id_name[16]; + char site_name[16]; + NSIG_Ymds_time ymds; + twob drive_num; + twob tape_type; + char spare[262]; +} NSIG_Tape_header_file; +/*============================================================*/ +/*============================================================*/ + +/* FUNCTION PROTOTYPES */ +FILE *nsig_open(char *file_name); +void swap_nsig_record1(NSIG_Record1 *rec1); +void swap_nsig_record2(NSIG_Record2 *rec2); +void swap_nsig_raw_prod_bhdr(NSIG_Raw_prod_bhdr *rp); +void swap_nsig_ingest_data_header(NSIG_Ingest_data_header *ih); + +/* Sweep reading structure */ +typedef struct { + NSIG_Ray_header h; + unsigned char *range; /* 0..h.num_bins-1 */ +} NSIG_Ray; +/*============================================================*/ +/*============================================================*/ + +typedef struct { + NSIG_Raw_prod_bhdr bhdr; + NSIG_Ingest_data_header idh; + NSIG_Ray **ray; + int nparams; /* For freeing. */ +} NSIG_Sweep; +/*============================================================*/ +/*============================================================*/ + +/* Each routine in nsig.c is renamed when compiling Ver2 code. + * The rename is simple: change nsig_ to nsig2_ + */ +#ifdef NSIG_VER2 + #define nsig_open nsig2_open + #define nsig_read_record nsig2_read_record + #define nsig_close nsig2_close + #define nsig_endianess nsig2_endianess + #define NSIG_I2 NSIG2_I2 + #define NSIG_I4 NSIG2_I4 + #define nsig_free_ray nsig2_free_ray + #define nsig_free_sweep nsig2_free_sweep + #define nsig_read_chunk nsig2_read_chunk + #define nsig_read_ext_header_ver0 nsig2_read_ext_header_ver0 + #define nsig_read_ext_header_ver1 nsig2_read_ext_header_ver1 + #define nsig_read_ray nsig2_read_ray + #define nsig_read_sweep nsig2_read_sweep + #define nsig_from_bang nsig2_from_bang + #define nsig_from_fourb_ang nsig2_from_fourb_ang + #define swap_nsig_structure_header swap_nsig2_structure_header + #define swap_nsig_ymds_time swap_nsig2_ymds_time + #define swap_nsig_color_scale_def swap_nsig2_color_scale_def + #define swap_nsig_product_config swap_nsig2_product_config + #define swap_nsig_product_end swap_nsig2_product_end + #define swap_nsig_ingest_summary swap_nsig2_ingest_summary + #define swap_nsig_task_sched_info swap_nsig2_task_sched_info + #define swap_nsig_task_dsp_info swap_nsig2_task_dsp_info + #define swap_nsig_task_calib_info swap_nsig2_task_calib_info + #define swap_nsig_task_range_info swap_nsig2_task_range_info + #define swap_nsig_task_scan_info swap_nsig2_task_scan_info + #define swap_nsig_task_misc_info swap_nsig2_task_misc_info + #define swap_nsig_task_end_data swap_nsig2_task_end_data + #define swap_nsig_task_config swap_nsig2_task_config + #define swap_nsig_one_device swap_nsig2_one_device + #define swap_nsig_device_status swap_nsig2_device_status + #define swap_nsig_gparam swap_nsig2_gparam + #define swap_nsig_record1 swap_nsig2_record1 + #define swap_nsig_record2 swap_nsig2_record2 + #define swap_nsig_raw_prod_bhdr swap_nsig2_raw_prod_bhdr + #define swap_nsig_ingest_data_header swap_nsig2_ingest_data_header + #define get_extended_header_info get2_extended_header_info +#endif + +void nsig_free_ray(NSIG_Ray *r); +void nsig_free_sweep(NSIG_Sweep **s); +NSIG_Sweep **nsig_read_sweep(FILE *fp, NSIG_Product_file *prod_file); +int nsig_read_record(FILE *fp, char *nsig_rec); +int nsig_endianess(NSIG_Record1 *rec1); +short NSIG_I2 (twob x); +int NSIG_I4 (fourb x); +void nsig_close(FILE *fp); + +float nsig_from_fourb_ang(fourb ang); +float nsig_from_bang(bang in); + +#endif diff --git a/nsig2_to_radar.c b/nsig2_to_radar.c new file mode 100644 index 0000000..5e0db58 --- /dev/null +++ b/nsig2_to_radar.c @@ -0,0 +1,23 @@ +/*************************************************************/ +/* */ +/* Function: nsig2_to_radar.c */ +/* */ +/* John H. Merritt */ +/* Space Applications Corporation */ +/* NASA/GSFC */ +/* TRMM/Code 910.1 */ +/* */ +/* Copyright 1996, 1997 */ +/*************************************************************/ + +/* The trick here is to reuse as much code from nsig_to_radar.c. + * To do that, #define NSIG_VER2, separates all version 2 code + * from version 1 code in nsig_to_radar.c, nsig.c, and nsig.h + */ + +#define NSIG_VER2 + +/* 'static' forces all routines in nsig.c to be static for this code. */ +#include "nsig.c" +#include "nsig_to_radar.c" + diff --git a/nsig_to_radar.c b/nsig_to_radar.c new file mode 100644 index 0000000..1e8b390 --- /dev/null +++ b/nsig_to_radar.c @@ -0,0 +1,788 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996 Paul A. Kucera of Applied Research Corporation, + Landover, Maryland, a NASA/GSFC on-site contractor. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/*************************************************************/ +/* */ +/* Function: nsig_to_radar.c */ +/* */ +/* Paul A. Kucera */ +/* Applied Research Corporation */ +/* NASA/GSFC */ +/* TRMM/Code 910.1 */ +/* */ +/* Modifications by: */ +/* John H. Merritt */ +/* Space Applications Corporation */ +/* NASA/GSFC */ +/* TRMM/Code 910.1 */ +/* */ +/* Started: 08 AUG 96 */ +/* */ +/* Derived from Paul Kucera's nsig_to_radar.c */ +/* Copyright 1996 */ +/*************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include"nsig.h" +#include"rsl.h" + +extern int radar_verbose_flag; +extern int rsl_qfield[]; /* See RSL_select_fields */ + + /* We need this entry for various things esp in Ray_header */ +#define MISSING_HEADER_DATA -9999 + /* The following is speed of light _in_ _air_ ! */ +#define SPEED_OF_LIGHT 299702547 +#define MIT_BEAMWIDTH 1.65 +#define TOG_BEAMWIDTH 1.65 +#define KWA_BEAMWIDTH 1.0 +#define DEFAULT_BEAMWIDTH 1.0 +#define NSIG_NO_DATA -1 +#define MAX_NSIG_SWEEPS 30 +#define MAX_NSIG_RAYS 400 +#define NSIG_NO_ECHO -32.0 + +static float (*f)(Range x); +static Range (*invf)(float x); + +FILE *file; + +void get_extended_header_info(NSIG_Sweep **nsig_sweep, int xh_size, int iray, + int nparams, + int *msec, float *azm, float *elev, + float *pitch, float *roll, float *heading, + float *azm_rate, float *elev_rate, + float *pitch_rate, float *roll_rate, float *heading_rate, + float *lat, float *lon, int *alt, float *rvc, + float *vel_east, float *vel_north, float *vel_up) +{ + static NSIG_Ext_header_ver1 xh; + int data_type, itype; + + *msec = *azm = *elev = *pitch = *roll = *heading = + *azm_rate = *elev_rate = *pitch_rate = *roll_rate = *heading_rate = + *lat = *lon = *alt = *rvc = 0; + + /* Determine where 'itype' for extended header is. */ + for (itype = 0; itypeidh.data_type); + if (data_type == NSIG_DTB_EXH) break; + } + /* printf("...extended header itype=%d, nparams=%d\n", itype, nparams); */ + if (itype == nparams) return; /* No extended header. */ + + /* Version 1. */ + if (nsig_sweep[itype]->ray[iray] == NULL) return; + if (nsig_sweep[itype]->ray[iray]->range == NULL) return; + memmove(&xh, nsig_sweep[itype]->ray[iray]->range, sizeof(xh)); + *msec = NSIG_I4(xh.msec); + /* printf("...extended header msec= %d\n", *msec); */ + if (xh_size <= 20) /* Stop, only have version 0. */ + return; + + /* Version 1 processing. */ + *azm = nsig_from_bang(xh.azm); + *elev = nsig_from_bang(xh.elev); + *pitch = nsig_from_bang(xh.pitch); + *roll = nsig_from_bang(xh.roll); + *heading = nsig_from_bang(xh.heading); + *azm_rate = nsig_from_bang(xh.azm_rate); + *elev_rate = nsig_from_bang(xh.elev_rate); + *pitch_rate = nsig_from_bang(xh.pitch_rate); + *roll_rate = nsig_from_bang(xh.roll_rate); +#ifdef NSIG_VER2 + +#else + *heading_rate = nsig_from_bang(xh.heading_rate); +#endif + *lat = nsig_from_fourb_ang(xh.lat); + *lon = nsig_from_fourb_ang(xh.lon); + if(*lat > 180.0) *lat -= 360.0; + if(*lon > 180.0) *lon -= 360.0; + *alt = NSIG_I2(xh.alt); + *rvc = NSIG_I2(xh.rad_vel_cor)/100.0; /* cm to m */ + *vel_east = NSIG_I2(xh.vel_e)/100.0; /* cm to m */ + *vel_north = NSIG_I2(xh.vel_n)/100.0; /* cm to m */ + *vel_up = NSIG_I2(xh.vel_u)/100.0; /* cm to m */ + return; +} + +/** Main code **/ +Radar * +#ifdef NSIG_VER2 +RSL_nsig2_to_radar +#else +RSL_nsig_to_radar +#endif +(char *filename) +{ + FILE *fp; + /* RSL structures */ + Radar *radar; + Ray *ray; + + int i, j, k, n; + int year, month, day; + int hour, minute, sec; + int numbins, numsweep; + int num_rays, sea_lvl_hgt; + int radar_number, num_samples; + int latd, latm, lats, lond, lonm, lons; + int data_type; + int bin_num; + int sweep_year, sweep_day, sweep_month; + int sweep_hour, sweep_minute, sweep_second; + int sweep_sec; + int z_flag_unc, z_flag_cor, v_flag, w_flag, speckle; + int ant_scan_mode; + float second; + float pw; + float bin_space; + float prf, wave, beam_width; + float vert_half_bw, horz_half_bw; + float rng_last_bin; + float rng_first_bin, freq; + float max_vel, sweep_rate, azim_rate; + float ray_data; + float az1, az2; + double tmp; + float sqi, log, csr, sig, cal_dbz; + char radar_type[50], state[2], city[15]; + char site_name[16]; + NSIG_Product_file *prod_file; + short id; + int data_mask, nrays; + int nparams, nsweeps; + NSIG_Sweep **nsig_sweep; + NSIG_Ray *ray_p; + int itype, ifield; + Sweep *sweep; + int msec; + float azm, elev, pitch, roll, heading, azm_rate, elev_rate, + pitch_rate, roll_rate, heading_rate, + lat, lon; + int alt; /* Altitude */ + float rvc; /* Radial correction velocity m/s */ + float vel_east, vel_north, vel_up; /* Platform velocity vectors m/sec */ + int xh_size; + extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */ + extern int rsl_qsweep_max; + extern float rsl_kdp_wavelen; + + radar = NULL; + if (radar_verbose_flag) + fprintf(stderr, "open file: %s\n", filename); + + /** Opening nsig file **/ + if((fp = nsig_open(filename)) == NULL) return NULL; + +#ifdef NSIG_VER2 + sprintf(radar_type, "nsig2"); + radar_number = 22; /** Arbitrary number given to nsig2 data **/ +#else + sprintf(radar_type, "nsig"); + radar_number = 21; /* What are these suppose to be? */ +#endif + sprintf(state,"NA"); + sprintf(city,"NA"); + + /* MAINLINE CODE */ + + prod_file = (NSIG_Product_file *)calloc(1, sizeof(NSIG_Product_file)); + + n = nsig_read_record(fp, (char *)&prod_file->rec1); + nsig_endianess(&prod_file->rec1); + if (radar_verbose_flag) + fprintf(stderr, "Read %d bytes for rec1.\n", n); + + id = NSIG_I2(prod_file->rec1.struct_head.id); + if (radar_verbose_flag) + fprintf(stderr, "ID = %d\n", (int)id); + if (id != 7 && id != 27) { /* testing: Use 27 for Version 2 data */ + fprintf(stderr, "File is not a SIGMET version 1 nor version 2 raw product file.\n"); + return NULL; + } + + n = nsig_read_record(fp, (char *)&prod_file->rec2); + if (radar_verbose_flag) + fprintf(stderr, "Read %d bytes for rec2.\n", n); + + /** Test for scan mode -- If scan is a RHI will return NULL **/ + /** because RSL can't handle RHI's. In the future, replace **/ + /** NULL will a routine to convert RHI's to RSL Format **/ + ant_scan_mode =NSIG_I2(prod_file->rec2.task_config.scan_info.ant_scan_mode); + if(ant_scan_mode == 2) + { + if (radar_verbose_flag) + fprintf(stderr, "RHI scan detected. Unable to process, returning NULL.\n"); + /* return NULL; */ + } + + /* Count the bits set in 'data_mask' to determine the number + * of parameters present. + */ + xh_size = NSIG_I2(prod_file->rec2.ingest_head.size_ext_ray_headers); + nrays = NSIG_I2(prod_file->rec2.ingest_head.num_rays); + if (radar_verbose_flag) + fprintf(stderr, "Expecting %d rays in each sweep.\n", nrays); + memmove(&data_mask, prod_file->rec2.task_config.dsp_info.data_mask, sizeof(fourb)); + for (nparams=i=0; i<32; i++) + nparams += (data_mask >> i) & 0x1; + + /* Number of sweeps */ + nsweeps = NSIG_I2(prod_file->rec2.task_config.scan_info.num_swp); + + + + memmove(site_name, prod_file->rec1.prod_end.site_name, sizeof(prod_file->rec1.prod_end.site_name)); + site_name[sizeof(site_name)-1] = '\0'; + if (radar_verbose_flag) { + fprintf(stderr, "nparams = %d, nsweeps = %d\n", nparams, nsweeps); + fprintf(stderr, "Site name = <%s>\n", site_name); + } + + /* nsig_sweep = nsig_read_sweep(fp, prod_file) + * + * Use: nsig_sweep[i]->ray[j]->range + * + * where 'range' is [0..nbins-1] + */ + + /* + * All the information you need is in: + * prod_file->rec1 + * .struct_head, .prod_config .prod_end + * prod_file->rec2 + * .struct_head, .ingest_head, .task_config .device_stat, + * .dsp1, .dsp2 + * nsig_sweep[0..nparams-1] 'nparams' is the true number + * of parameters present. You + * must check the 'id' (or type) + * to determine the field type. + * So far seen, nparams <= 6. + * nsig_sweep[i]->bhdr + * nsig_sweep[i]->idh + * nsig_sweep[i]->ray[j] + * + * Note: + * For extended header access, you'll typically use nsig_sweep[0] + * (double check the id) and the ray data allocated (nsig_ray->range) + * is a pointer to the extended header, either v0 or v1. + * You can typecast the pointer to NSIG_Ext_header_ver0 or + * NSIG_Ext_header_ver1, as you like. To determine which + * version of the extended headers you have use: + * xh_size <= 20 for version 0, else version 1. + * Access: + * xh_size = NSIG_I2(prod_file->rec2.ingest_head.size_ext_ray_headers) + * + * Functions: + * NSIG_I2(nsig_sweep[i]->idh.num_rays_act); -- # of rays. (j) + * NSIG_I2(nsig_sweep[i]->ray[j]->h.num_bins); -- # of bins in a ray. + * + * NSIG_I2(x), NSIG_I4(x) - Convert data, x, to floating point. + * + * IMPORTANT NOTE: It must be known whether or not to perform + * byte-swapping. To determine this, call + * 'nsig_endianess'. It returns 0 for no-swapping + * and 1 for swapping. Additionally, it transparently + * initializes the nsig library to automatically + * swap when using NSIG_I2 or NSIG_I4. + * The function 'nsig_read_sweep' automatically + * calls 'nsig_endianess', too. + */ + + sea_lvl_hgt = NSIG_I2(prod_file->rec1.prod_end.grnd_sea_ht); + + if (radar_verbose_flag) + fprintf(stderr, "sea: %d\n", sea_lvl_hgt); + if (radar_verbose_flag) + fprintf(stderr, "site_name: %s", site_name); + + /** Determine beamwidth from input variables (not saved in nsig file) **/ + if(strncmp(site_name,"mit",3) == 0 || strncmp(site_name,"MIT",3) == 0) + beam_width = MIT_BEAMWIDTH; + else if(strncmp(site_name,"tog",3) == 0 || strncmp(site_name,"TOG",3) == 0) + beam_width = TOG_BEAMWIDTH; + else if(strncmp(site_name,"kwa",3) == 0 || strncmp(site_name,"KWA",3) == 0) + beam_width = KWA_BEAMWIDTH; + else + beam_width = DEFAULT_BEAMWIDTH; + + if (radar_verbose_flag) + fprintf(stderr, "beamwidth: %f\n", beam_width); + + vert_half_bw = beam_width/2.0; + horz_half_bw = beam_width/2.0; + + /** Reading date and time **/ + month = NSIG_I2(prod_file->rec2.ingest_head.start_time.month); + year = NSIG_I2(prod_file->rec2.ingest_head.start_time.year); + day = NSIG_I2(prod_file->rec2.ingest_head.start_time.day); + sec = NSIG_I4(prod_file->rec2.ingest_head.start_time.sec); + + /* converting seconds since mid to time of day */ + tmp = sec/3600.0; + hour = (int)tmp; + tmp = (tmp - hour) * 60.0; + minute = (int)tmp; + second = (tmp - minute) * 60.0; + + /** records of the nsig file. **/ + num_rays = 0; + pw = (NSIG_I4(prod_file->rec1.prod_end.pulse_wd))/100.0; /* pulse width */ + prf = NSIG_I4(prod_file->rec1.prod_end.prf); /* pulse repetition frequency */ + wave = (NSIG_I4(prod_file->rec1.prod_end.wavelen))/100.0; /* wavelength (cm) */ + rsl_kdp_wavelen = wave; /* EXTERNAL (volume.c) This sets KD_F and KD_INVF + * to operate with the proper wavelength. + */ + numbins = NSIG_I4(prod_file->rec1.prod_end.num_bin); /* # bins in ray */ + rng_first_bin = (float)NSIG_I4(prod_file->rec1.prod_end.rng_f_bin)/100.0; + rng_last_bin = (float)NSIG_I4(prod_file->rec1.prod_end.rng_l_bin)/100.0; + bin_space = ((rng_last_bin-rng_first_bin)/numbins); /*rng res (m)*/ + + numsweep = NSIG_I2(prod_file->rec2.task_config.scan_info.num_swp); /* # sweeps in volume */ + num_samples = NSIG_I2(prod_file->rec1.prod_end.num_samp); + sweep_rate = 3.0; /** Approximate value -- info not stored **/ + azim_rate = sweep_rate*360.0/60.0; + max_vel = wave*prf/(100.0*4.0); + freq = (299793000.0/wave)*1.0e-4; /** freq in MHZ **/ + + sqi = NSIG_I2(prod_file->rec2.task_config.calib_info.sqi)/256.0; + log = NSIG_I2(prod_file->rec2.task_config.calib_info.noise)/16.0; + csr = NSIG_I2(prod_file->rec2.task_config.calib_info.clutr_corr)/(-16.0); + sig = NSIG_I2(prod_file->rec2.task_config.calib_info.power)/16.0; + cal_dbz = NSIG_I2(prod_file->rec2.task_config.calib_info.cal_ref)/16.0; + z_flag_unc = NSIG_I2(prod_file->rec2.task_config.calib_info.z_flag_unc); + z_flag_cor = NSIG_I2(prod_file->rec2.task_config.calib_info.z_flag_cor); + v_flag = NSIG_I2(prod_file->rec2.task_config.calib_info.v_flag); + w_flag = NSIG_I2(prod_file->rec2.task_config.calib_info.w_flag); + speckle = NSIG_I2(prod_file->rec2.task_config.calib_info.speckle); + + /** Verbose calibration information **/ + if (radar_verbose_flag) + { + fprintf(stderr, "LOG = %5.2f\n", log); + fprintf(stderr, "SQI = %5.2f\n", sqi); + fprintf(stderr, "CSR = %5.2f\n", csr); + fprintf(stderr, "SIG = %5.2f\n", sig); + fprintf(stderr, "Calibration reflectivity: %5.2f dBZ\n", cal_dbz); + fprintf(stderr, "ZT flags: %d\n", z_flag_unc); /** can find these **/ + fprintf(stderr, "DZ flags: %d\n", z_flag_cor); /** defn in the **/ + fprintf(stderr, "VR flags: %d\n", v_flag); /** SIGMET Doc **/ + fprintf(stderr, "SW flags: %d\n", w_flag); + fprintf(stderr, "Flags: -3856 = SQI thresholding\n"); + fprintf(stderr, " -21846 = LOG thresholding\n"); + fprintf(stderr, " -24416 = LOG & SQI thresholding\n"); + fprintf(stderr, " -24516 = LOG & SQI & SIG thresholding\n"); + fprintf(stderr, "speckle remover: %d\n", speckle); + } + + if (radar_verbose_flag) + fprintf(stderr, "vel: %f prf: %f\n", max_vel, prf); + + /** Extracting Latitude and Longitude from nsig file **/ + lat = nsig_from_fourb_ang(prod_file->rec2.ingest_head.lat_rad); + lon = nsig_from_fourb_ang(prod_file->rec2.ingest_head.lon_rad); + if(lat > 180.0) lat -= 360.0; + if(lon > 180.0) lon -= 360.0; + if (radar_verbose_flag) + fprintf(stderr, "nsig_to_radar: lat %f, lon %f\n", lat, lon); + /** Latitude deg, min, sec **/ + latd = (int)lat; + tmp = (lat - latd) * 60.0; + latm = (int)tmp; + lats = (int)((tmp - latm) * 60.0); + /** Longitude deg, min, sec **/ + lond = (int)lon; + tmp = (lon - lond) * 60.0; + lonm = (int)tmp; + lons = (int)((tmp - lonm) * 60.0); + + /** Allocating memory for radar structure **/ + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + if (radar == NULL) + { + fprintf(stderr, "nsig_to_radar: radar is NULL\n"); + return NULL; + } + + /** Filling Radar Header **/ + radar->h.month = month; + radar->h.day = day; + radar->h.year = year; /* Year 2000 compliant. */ + radar->h.hour = hour; + radar->h.minute = minute; + radar->h.sec = second; + sprintf(radar->h.radar_type, "%s", radar_type); + radar->h.number = radar_number; + memmove(radar->h.name, site_name, sizeof(radar->h.name)); + memmove(radar->h.radar_name, site_name, sizeof(radar->h.radar_name)); + memmove(radar->h.city, city, sizeof(radar->h.city)); + memmove(radar->h.state, state, sizeof(radar->h.state)); + radar->h.latd = latd; + radar->h.latm = latm; + radar->h.lats = lats; + radar->h.lond = lond; + radar->h.lonm = lonm; + radar->h.lons = lons; + radar->h.height = (int)sea_lvl_hgt; + radar->h.spulse = (int)(pw*1000); + radar->h.lpulse = (int)(pw*1000); + + if (radar_verbose_flag) { +#ifdef NSIG_VER2 + fprintf(stderr, "\nSIGMET version 2 raw product file.\n"); +#else + fprintf(stderr, "\nSIGMET version 1 raw product file.\n"); +#endif + fprintf(stderr, "Date: %2.2d/%2.2d/%4.4d %2.2d:%2.2d:%f\n", + radar->h.month, radar->h.day, radar->h.year, + radar->h.hour, radar->h.minute, radar->h.sec); + fprintf(stderr, "Name: "); + for (i=0; ih.name); i++) + fprintf(stderr, "%c", radar->h.name[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "Lat/lon (%d %d' %d'', %d %d' %d'')\n", + radar->h.latd, radar->h.latm, radar->h.lats, + radar->h.lond, radar->h.lonm, radar->h.lons); + } + + /** Converting data **/ + if (radar_verbose_flag) fprintf(stderr, "Expecting %d sweeps.\n", numsweep); + for(i = 0; i < numsweep; i++) + { + nsig_sweep = nsig_read_sweep(fp, prod_file); + if (nsig_sweep == NULL) { /* EOF possibility */ + if (feof(fp)) break; + else continue; + } + if (rsl_qsweep != NULL) { + if (i > rsl_qsweep_max) break; + if (rsl_qsweep[i] == 0) continue; + } + if (radar_verbose_flag) + fprintf(stderr, "Read sweep # %d\n", i); + /* The whole sweep is 'nsig_sweep' ... pretty slick. + * + * nsig_sweep[itype] -- [0..nparams], if non-null. + */ + for (itype=0; itypeidh.time.month); + sweep_year = NSIG_I2(nsig_sweep[itype]->idh.time.year); + sweep_day = NSIG_I2(nsig_sweep[itype]->idh.time.day); + sweep_sec = NSIG_I4(nsig_sweep[itype]->idh.time.sec); +#ifdef NSIG_VER2 + msec = NSIG_I2(nsig_sweep[itype]->idh.time.msec); + /* printf("....... msec == %d\n", msec); */ +#endif + /* converting seconds since mid to time of day */ + tmp = sweep_sec/3600.0; + sweep_hour = (int)tmp; + tmp = (tmp - sweep_hour) * 60.0; + sweep_minute = (int)tmp; + sweep_second = sweep_sec - (sweep_hour*3600 + sweep_minute*60); + + num_rays = NSIG_I2(nsig_sweep[itype]->idh.num_rays_exp); + + data_type = NSIG_I2(nsig_sweep[itype]->idh.data_type); + + ifield = 0; + switch (data_type) { + case NSIG_DTB_EXH: + ifield = -1; + break; + case NSIG_DTB_UCR: + ifield = ZT_INDEX; + f = ZT_F; + invf = ZT_INVF; + break; + case NSIG_DTB_CR: + ifield = DZ_INDEX; + f = DZ_F; + invf = DZ_INVF; + break; + case NSIG_DTB_VEL: + ifield = VR_INDEX; + f = VR_F; + invf = VR_INVF; + break; + case NSIG_DTB_WID: + ifield = SW_INDEX; + f = SW_F; + invf = SW_INVF; + break; + case NSIG_DTB_ZDR: + ifield = DR_INDEX; + f = DR_F; + invf = DR_INVF; + break; + case NSIG_DTB_KDP: + ifield = KD_INDEX; + f = KD_F; + invf = KD_INVF; + break; + case NSIG_DTB_PHIDP: /* SRB 990127 */ + ifield = PH_INDEX; + f = PH_F; + invf = PH_INVF; + break; + case NSIG_DTB_RHOHV: /* SRB 000414 */ + ifield = RH_INDEX; + f = RH_F; + invf = RH_INVF; + break; + case NSIG_DTB_SQI: + ifield = SQ_INDEX; + f = SQ_F; + invf = SQ_INVF; + break; + default: + fprintf(stderr,"Unknown field type: %d Skipping it.\n", data_type); + continue; + } + + if (radar_verbose_flag) + fprintf(stderr, " nsig_sweep[%d], data_type = %d, rays(expected) = %d, nrays(actual) = %d\n", itype, data_type, num_rays, NSIG_I2(nsig_sweep[itype]->idh.num_rays_act)); + + if (data_type != NSIG_DTB_EXH) { + if ((radar->v[ifield] == NULL)) { + if (rsl_qfield[ifield]) { + radar->v[ifield] = RSL_new_volume(numsweep); + radar->v[ifield]->h.f = f; + radar->v[ifield]->h.invf = invf; + } else { + /* Skip this field, because, the user does not want it. */ + continue; + } + } + if (radar->v[ifield]->sweep[i] == NULL) + radar->v[ifield]->sweep[i] = RSL_new_sweep(num_rays); + } + else + continue; /* Skip the actual extended header processing. + * This is different than getting it, so that + * the information is available for the other + * fields when filling the RSL ray headers. + */ + + /** DATA conversion time **/ + sweep = radar->v[ifield]->sweep[i]; + sweep->h.f = f; + sweep->h.invf = invf; + sweep->h.sweep_num = i; + sweep->h.beam_width = beam_width; + sweep->h.vert_half_bw = vert_half_bw; + sweep->h.horz_half_bw = horz_half_bw; + elev = nsig_from_bang(nsig_sweep[itype]->idh.fix_ang); + sweep->h.elev = elev; + + for(j = 0; j < num_rays; j++) + { + ray_p = nsig_sweep[itype]->ray[j]; + if (ray_p == NULL) continue; + bin_num = NSIG_I2(ray_p->h.num_bins); + + /* Load extended header information, if available. + * We need to pass the entire nsig_sweep and search for + * the extended header field (it may not be data_type==0). + */ + get_extended_header_info(nsig_sweep, xh_size, j, nparams, + &msec, &azm, &elev, + &pitch, &roll, &heading, + &azm_rate, &elev_rate, + &pitch_rate, &roll_rate, &heading_rate, + &lat, &lon, &alt, &rvc, + &vel_east, &vel_north, &vel_up); + + + if (radar->v[ifield]->sweep[i]->ray[j] == NULL) + radar->v[ifield]->sweep[i]->ray[j] = RSL_new_ray(bin_num); + ray = radar->v[ifield]->sweep[i]->ray[j]; + ray->h.f = f; + ray->h.invf = invf; + /** Ray is at nsig_sweep[itype].ray->... **/ + /** Loading nsig data into data structure **/ + + ray->h.month = sweep_month; + ray->h.day = sweep_day; + ray->h.year = sweep_year; /* Year 2000 compliant. */ + ray->h.hour = sweep_hour; + ray->h.minute = sweep_minute; + if (msec == 0) { /* No extended header */ + ray->h.sec = NSIG_I2(ray_p->h.sec) + sweep_second; + elev = sweep->h.elev; + } else + ray->h.sec = sweep_second + msec/1000.0; + + /* add time ... handles end of min,hour,month,year and century. */ + if (ray->h.sec >= 60) /* Should I fix the time no matter what? */ + RSL_fix_time(ray); /* Repair second overflow. */ + + ray->h.ray_num = j; + ray->h.elev_num = i; + ray->h.range_bin1 = (int)rng_first_bin; + ray->h.gate_size = (int)(bin_space+.5); /* Nearest int */ + ray->h.vel_res = bin_space; + ray->h.sweep_rate = sweep_rate; + ray->h.prf = (int)prf; + if (prf != 0) + ray->h.unam_rng = 299793000.0 / (2.0 * prf * 1000.0); /* km */ + else + ray->h.unam_rng = 0.0; + ray->h.fix_angle = (float)sweep->h.elev; + ray->h.azim_rate = azim_rate; + ray->h.pulse_count = (float)num_samples; + ray->h.pulse_width = pw; + ray->h.beam_width = beam_width; + ray->h.frequency = freq / 1000.0; /* GHz */ + ray->h.wavelength = wave/100.0; /* meters */ + ray->h.nyq_vel = max_vel; /* m/s */ + if (elev == 0.) elev = sweep->h.elev; + ray->h.elev = elev; + /* Compute mean azimuth angle for ray. */ + az1 = nsig_from_bang(ray_p->h.beg_azm); + az2 = nsig_from_bang(ray_p->h.end_azm); + /* printf("az1, %f, az2 %f\n", az1, az2); */ + if(az1 > az2) + if((az1 - az2) > 180.0) az2 += 360.0; + else + ; + else + if((az2 - az1) > 180.0) az1 += 360.0; + + az1 = (az1 + az2) / 2.0; + if (az1 > 360) az1 -= 360; + ray->h.azimuth = az1; + + /* From the extended header information, we learn the following. */ + ray->h.pitch = pitch; + ray->h.roll = roll; + ray->h.heading = heading; + ray->h.pitch_rate = pitch_rate; + ray->h.roll_rate = roll_rate; + ray->h.heading_rate = heading_rate; + ray->h.lat = lat; + ray->h.lon = lon; + ray->h.alt = alt; + ray->h.rvc = rvc; + ray->h.vel_east = vel_east; + ray->h.vel_north = vel_north; + ray->h.vel_up = vel_up; + + /* printf("Processing sweep[%d]->ray[%d]: %d %f %f %f %f %f %f %f %f %d nbins=%d, bin1=%d gate=%d\n", + i, j, msec, ray->h.sec, ray->h.azimuth, ray->h.elev, ray->h.pitch, ray->h.roll, ray->h.heading, ray->h.lat, ray->h.lon, ray->h.alt, ray->h.nbins, ray->h.range_bin1, ray->h.gate_size); + */ + if (data_type == NSIG_DTB_EXH) continue; + ray_data = 0; + for(k = 0; k < bin_num; k++) { + switch(data_type) { + case NSIG_DTB_UCR: + case NSIG_DTB_CR: + if (ray_p->range[k] == 0) ray_data = NSIG_NO_ECHO; + else ray_data = (float)((ray_p->range[k]-64.0)/2.0); + break; + + case NSIG_DTB_VEL: + if (ray_p->range[k] == 0) ray_data = NSIG_NO_ECHO; + else ray_data = (float)((ray_p->range[k]*max_vel/127.0)+ + max_vel*(1.0-255.0/127.0)); + break; + + case NSIG_DTB_WID: + if (ray_p->range[k] == 0) ray_data = NSIG_NO_ECHO; + else ray_data =(float)((ray_p->range[k])/256.0)*max_vel; + break; + + case NSIG_DTB_ZDR: + if (ray_p->range[k] == 0) ray_data = NSIG_NO_ECHO; + else ray_data = (float)((ray_p->range[k]-128.0)/16.0); + break; + + /* + * Special optimization note: + * For KDP, PHIDP, RHOHV we skip the float conversion, + * and carry the native sigmet data values into RSL storage. + */ + case NSIG_DTB_KDP: + ray_data = ray_p->range[k]; + /* F_OFFSET *must* match the definition in volume.c */ +#define F_OFFSET 4 + if (ray_data == 0 || ray_data == 255) ray_data = NSIG_NO_ECHO; + else ray_data += F_OFFSET; + break; + + case NSIG_DTB_RHOHV: + case NSIG_DTB_PHIDP: + if (ray_p->range[k] <= 0 || ray_p->range[k] >= 255) + ray_data = NSIG_NO_ECHO; + else + ray_data = ray_p->range[k]; + break; + case NSIG_DTB_SQI: + if (ray_p->range[k] == 0) ray_data = NSIG_NO_ECHO; + else ray_data = + (float)sqrt((ray_p->range[k]-1.0)/253.0); + } + + if (ray_data == NSIG_NO_ECHO) + ray->range[k] = ray->h.invf(BADVAL); + else + if ( (data_type == NSIG_DTB_KDP) || + (data_type == NSIG_DTB_RHOHV) || + (data_type == NSIG_DTB_PHIDP) ) + ray->range[k] = (Range)ray_data; + else + ray->range[k] = ray->h.invf(ray_data); + + /* + if (data_type == NSIG_DTB_KDP) + printf("v[%d]->sweep[%d]->ray[%d]->range[%d] = %f, %d, %f\n", + ifield, i, j, k, ray->h.f(ray->range[k]), + (int)ray_p->range[k], ray_data); + */ + } + } + } + nsig_free_sweep(nsig_sweep); + } + + /* Do not reset radar->h.nvolumes. It is already set properly. */ + if (radar_verbose_flag) + fprintf(stderr, "Max index of radar->v[0..%d]\n", radar->h.nvolumes); + + + /** close nsig file **/ + nsig_close(fp); + + radar = RSL_prune_radar(radar); + /** return radar pointer **/ + return radar; +} diff --git a/prune.c b/prune.c new file mode 100644 index 0000000..6ee0459 --- /dev/null +++ b/prune.c @@ -0,0 +1,107 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * The PRUNE functions eliminate NULL or non-present (no data present) + * substructures. This tightens the structures for output. Development + * was sparked by failing NCAR UF ingest programs; they cannot handle + * 0 sized volumes/sweeps/rays dispite conformity to the UF specification. + * + * These routines free memory that is pruned. + * + * John H. Merritt + * Space Applications Corporation + * December 12, 1995 + */ + +#include "rsl.h" +extern int radar_verbose_flag; + +Ray *RSL_prune_ray(Ray *ray) +{ + if (ray == NULL) return NULL; + if (ray->h.nbins > 0) return ray; + RSL_free_ray(ray); + return NULL; +} + +Sweep *RSL_prune_sweep(Sweep *s) +{ + int i, j; + + if (s == NULL) return NULL; + if (s->h.nrays == 0) { + RSL_free_sweep(s); + return NULL; + } +/* + * Squash out all dataless rays. 'j' is the index for the squashed (pruned) + * rays. + */ + for (i=0,j=0; ih.nrays; i++) + if ((s->ray[i] = RSL_prune_ray(s->ray[i]))) + s->ray[j++] = s->ray[i]; /* Keep this ray. */ + + if (j==0) { + RSL_free_sweep(s); + return NULL; /* All rays were pruned. */ + } + for (i=j; ih.nrays; i++) s->ray[i] = NULL; + s->h.nrays = j; + return s; +} + +Volume *RSL_prune_volume(Volume *v) +{ + int i, j; + + if (v == NULL) return NULL; + if (v->h.nsweeps == 0) { + RSL_free_volume(v); + return NULL; + } +/* + * Squash out all dataless sweeps. 'j' is the index for sweep containing data. + */ + for (i=0,j=0; ih.nsweeps; i++) + if ((v->sweep[i] = RSL_prune_sweep(v->sweep[i]))) + v->sweep[j++] = v->sweep[i]; /* Keep this sweep. */ + + if (j==0) { + RSL_free_volume(v); + return NULL; /* All sweeps were pruned. */ + } + for (i=j; ih.nsweeps; i++) v->sweep[i] = NULL; + v->h.nsweeps = j; + return v; +} + +Radar *RSL_prune_radar(Radar *radar) +{ + int i; + /* Volume indexes are fixed so we just prune the substructures. */ + if (radar == NULL) return NULL; + for (i=0; ih.nvolumes; i++) + radar->v[i] = RSL_prune_volume(radar->v[i]); + + return radar; +} diff --git a/radar.c b/radar.c new file mode 100644 index 0000000..ff138c8 --- /dev/null +++ b/radar.c @@ -0,0 +1,199 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * Radar routines coded in this file: + * + * RSL_radar_verbose_on(); + * RSL_radar_verbose_off(); + * Radar *RSL_new_radar(int nvolumes); + * void RSL_free_radar(Radar *r); + * Radar *RSL_clear_radar(Radar *r); + * Volume *RSL_get_volume(Radar *r, int type_wanted); + * Radar *RSL_wsr88d_to_radar(char *infile, unsigned int data_mask); + * + * Internal routines: + * print_vect(float v[], int istart, int istop); + * void radar_load_date_time(Radar *radar); + * int wsr88d_load_sweep_into_volume(Wsr88d_sweep ws, + * Volume *v, int nsweep, unsigned int vmask); + * + * Radar routines not coded in this file: + * + * Radar *RSL_read_radar(char *infile); + * int RSL_write_radar(Radar *radar, char *outfile); + * Radar *RSL_clear_radar(Radar *r); + * void RSL_radar_to_uf(Radar *r, char *outfile); + * Radar *RSL_uf_to_radar(char *infile); + * + * See the file radar.ez and version.notes for more detailed documentation. + * + * All routines herein coded, unless otherwise stated, by: + * John Merritt + * Space Applications Corporation + * + */ +#include +#include +#include + +#include "rsl.h" + +void RSL_print_version() +{ + printf("RSL version %s.\n", RSL_VERSION_STR); +} + +/* Debug printing global variable: radar_verbose_flag */ +int radar_verbose_flag = 0; + +void RSL_radar_verbose_on() +{ + radar_verbose_flag = 1; +} +void RSL_radar_verbose_off() +{ + radar_verbose_flag = 0; +} + +void print_vect(float v[], int istart, int istop) +{ + int i; + for (i=istart; i<=istop; i++) + fprintf(stderr,"v[%d] = %f\n", i, v[i]); +} + + +/**********************************************************************/ +/* */ +/* RSL_get_nyquist_from_radar */ +/* */ +/**********************************************************************/ +float RSL_get_nyquist_from_radar(Radar *radar) +{ + /* Find a velocity volume. + * Find first sweep in that volume. + * Find first ray in that sweep. + * Return the nyquist velocity. + * + * This code required for loading nyquist value in non-velocity + * volumes; UF output is affected by this in a good way. + */ + Volume *vol; + Ray *ray; + + if (radar == NULL) return 0.0; + if (radar->h.nvolumes <= VR_INDEX) return 0.0; + + vol = radar->v[VR_INDEX]; + ray = RSL_get_first_ray_of_volume(vol); + if (ray == NULL) return 0.0; + return ray->h.nyq_vel; +} + +/**********************************************************************/ +/* */ +/* done 3/30 new_radar() */ +/* done 3/30 free_radar() */ +/* done 4/21 clear_radar() */ +/* */ +/**********************************************************************/ +Radar *RSL_new_radar(int nvolumes) +{ + Radar *r; + r = (Radar *) calloc(1, sizeof(Radar)); + r->v = (Volume **) calloc(nvolumes, sizeof(Volume *)); + r->h.nvolumes = nvolumes; + return r; +} + +void RSL_free_radar(Radar *r) +{ + int i; + + /* Chase down all the pointers and free everything in sight. */ + if (r) { + for (i=0; ih.nvolumes; i++) + RSL_free_volume(r->v[i]); + if (r->v) free(r->v); + free(r); + } +} + +Radar *RSL_clear_radar(Radar *r) +{ + int i; + + if (r == NULL) return r; + for (i=0; ih.nvolumes; i++) + RSL_clear_volume(r->v[i]); + + return r; +} + +/**********************************************************************/ +/* */ +/* done 8/26 radar_load_date_time */ +/* */ +/**********************************************************************/ +void radar_load_date_time(Radar *radar) +{ + /* Search for the first existing ray of the first sweep of the first + * volume; steal that information. + */ + + int i; + Ray *first_ray; + + radar->h.month = 0; + radar->h.day = 0; + radar->h.year = 0; + radar->h.hour = 0; + radar->h.minute= 0; + radar->h.sec= 0.0; + first_ray = NULL; + + for (i=0; iv[i] != NULL) { + first_ray = RSL_get_first_ray_of_volume(radar->v[i]); + if (first_ray) { + radar->h.month = first_ray->h.month; + radar->h.day = first_ray->h.day; + radar->h.year = first_ray->h.year; + radar->h.hour = first_ray->h.hour; + radar->h.minute= first_ray->h.minute; + radar->h.sec = first_ray->h.sec; + return; + } + } + } +} + +/**********************************************************************/ +/* */ +/* done 3/30 Volume *RSL_get_volume */ +/* */ +/**********************************************************************/ +Volume *RSL_get_volume(Radar *r, int type_wanted) +{ + return r->v[type_wanted]; +} diff --git a/radar_to_hdf_1.c b/radar_to_hdf_1.c new file mode 100644 index 0000000..66d134f --- /dev/null +++ b/radar_to_hdf_1.c @@ -0,0 +1,1107 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBTSDISTK +/****************************************************************** + + Writes one VOS from a RSL radar structure into one 1B-51/1C-51 HDF + file. + + A 1B-51/1C-51 HDF file contains multiple VOS's recorded by a radar + site during a 1-hour time period, and the HDF file is named using + the date/hour of the constituent VOS's. + + Functions defined herein perform tasks preparatory to building a + TSDIS toolkit 'L1B_1C_GV' structure, the contents of which are + written into the HDF file by the TSDIS toolkit. Construction of the + toolkit 'L1B_1C_GV' structure is done via the subroutines defined + in RSL file 'radar_to_hdf_2.c'. + + ----------------------------------------------------------------- + Libraries required for execution of this code : + -ltsdistk : TSDIS toolkit + -lmfhdf -ldf -ljpeg -lz : HDF + -lrsl : rsl + -lm : C math + + ----------------------------------------------------------------- +*******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* TSDIS toolkit function and structure definitions. */ +#include "IO.h" +#include "IO_GV.h" +/* RSL function and structure definitions. */ +#include "rsl.h" +/* Parameter definitions for 1B-51 and 1C-51 HDF + file handling applications using the TSDIS toolkit. */ +#include "toolkit_1BC-51_appl.h" + +/*************************************************************/ +/* */ +/* Function Prototypes */ +/* */ +/*************************************************************/ +void RSL_set_tkMetaDataString(char *string, int param); +void RSL_set_hdf_qc_parameters(float *inParm); +void radarVolumesSave(Volume *v[MAX_RADAR_VOLUMES], Radar *radar); +void radarVolumesRestore(Radar *radar, Volume *v[MAX_RADAR_VOLUMES]); +int nextVolume(Radar *radar, int last_volume); +Volume *maskBuild(Volume *cv, Volume *ucv); +void metaDataWrite(IO_HANDLE *granuleHandle, Radar *radar, + char *hdfFileName, int fileAccessMode); +int tkVosDimensions(VosSize *vs, Radar *radar); +Ray *first_ray_in_sweep(Sweep *sweep); +int rslVosDimensions(VosSize *vs, Radar *radar, float maxRange); +int L1GVtemplateInit(VosSize *vs, Radar *radar, char *hdfFileName, + float maxRange); +static int hdfFileOpen(IO_HANDLE *granuleHandle, VosSize *vs, + char *hdfFileName, Radar *radar); +int radarPrep1B51(Radar *radar); +int radarPrep1C51(Radar *radar); +int nullGranuleCreate(char *hdfFileName, IO_HANDLE *granuleHandle, + Radar *radar); +int RSL_radar_to_hdf(Radar *radar, char *hdfFileName); + +extern L1B_1C_GV *gvl1Build(Radar *radar, float *qcParm, VosSize *vs, + int productID); +extern int radar_verbose_flag; + +/* The 1st non-NULL ray in each volume is widely used. Hence global. */ +Ray *first_ray_in_volume[MAX_RADAR_VOLUMES]; + + + +/*************************************************************/ +/* */ +/* RSL_set_tkMetaDataString */ +/* */ +/*************************************************************/ +static struct +{ + char GenInputDate[128]; + char AlgorithmVersion[128]; + int ProductVersion; + char SoftwareVersion[128]; +} tkMetaDataString; + +void RSL_set_tkMetaDataString(char *string, int param) +{ +/* Allows the application 'level_1' to store metadata strings into + the tkMetaDataString buffers for later insertion by RSL function + 'metaDataWrite()' into the HDF file. + Call **before** RSL_radar_to_hdf(). +*/ + +#define CP_TKMETA(s, str) \ + memset(tkMetaDataString.s, '\0', sizeof(tkMetaDataString.s));\ + strncpy(tkMetaDataString.s, str, sizeof(tkMetaDataString.s)-1) + + + if (param == TK_GEN_DATE_INPUT_FILES) { + CP_TKMETA(GenInputDate, string); + /* 1C-51 kludge... + To decide whether or not to write a VOS into a 1C-51 HDF file + (See 'hdf1C51Create()' in file 'level_1.c'), I need to know + something about the times of the VOSs already in the file; + ie, if no satellite overpass, the file is to contain just one + VOS from each half-hour. The only efficient way to do this is + by encoding time info into a metadata field. + + The 'GenInputDate' metaData string contains info indicating + which hourly time slots are filled by the VOSs contained in the + HDF file. (See function 'metaDataWrite()' in this file for details.) + + Called by 'hdfFilePeek()' in file 'level_1.c'. + */ + } + else if (param == TK_ALGORITHM_VERSION) { + CP_TKMETA(AlgorithmVersion, string); + + } else if (param == TK_SOFTWARE_VERSION) { + CP_TKMETA(SoftwareVersion, string); + + if (radar_verbose_flag) + fprintf(stderr, "TK_SOFTWARE_VERSION = <%s>\n", string); + + } else if (param == TK_PRODUCT_VERSION) { + sscanf(string, "%d", &tkMetaDataString.ProductVersion); + + + } else { + fprintf(stderr, "RSL_set_tkMetaDataString: Unknown param==%d!!\n", param); + } +} + +/*************************************************************/ +/* */ +/* RSL_set_hdf_qc_parameters */ +/* */ +/*************************************************************/ +static float qcParm[NUMBER_QC_PARAMS] = +{ + NOVAL_FLOAT, NOVAL_FLOAT, NOVAL_FLOAT, NOVAL_FLOAT, NOVAL_FLOAT, + NOVAL_FLOAT, NOVAL_FLOAT, NOVAL_FLOAT, NOVAL_FLOAT, NOVAL_FLOAT +}; + +void RSL_set_hdf_qc_parameters(float *inParm) +{ +/* Stores 1C-51 QC parameters for later insertion into 1C-51 HDF + file. Call **before** RSL_radar_to_hdf(). +*/ + int j; + + for (j=0; jh.nvolumes; j++) + v[j] = radar->v[j]; +} + +/*************************************************************/ +/* */ +/* radarVolumesRestore */ +/* */ +/*************************************************************/ +void radarVolumesRestore(Radar *radar, Volume *v[MAX_RADAR_VOLUMES]) +{ +/* Restore array of radar volume pointers. */ + int j; + + for (j=0; jh.nvolumes; j++) + radar->v[j] = v[j]; +} + +/*************************************************************/ +/* */ +/* nextVolume */ +/* */ +/*************************************************************/ +int nextVolume(Radar *radar, int last_volume) +/* Find the index of the next volume in the radar structure, given + the index of the last volume found. + Returns: + index of next volume, if success. + -1 if failure. +*/ +{ + int j; + + for (j=last_volume+1; jh.nvolumes; j++) + if (radar->v[j] != NULL) + return(j); /* Found volume. Return the index. */ + + return(-1); /* No volume found. Return bogus index. */ +} + +/*************************************************************/ +/* */ +/* maskBuild */ +/* */ +/*************************************************************/ +Volume *maskBuild(Volume *cv, Volume *ucv) +{ +/* Create a mask volume. A mask value, in conjunction with a corresponding + corrected reflectivity value, enables the future recovery of a + uncorrected value from a 1C-51 HDF file, since the original, uncorrected + reflectivity values are not stored in 1C-51 HDF files. + + This function used for both reflectivity 'DZ' and differential reflectivity + 'ZD'. + + cv: corrected volume pointer. (CZ or CD) + ucv: uncorrected volume pointer. (DZ or ZD) + mv: mask volume pointer. (MZ or MD) +*/ + Volume *mv; + int sindex, rindex, bindex; + + + mv = RSL_copy_volume(cv); + mv->h.f = MZ_F; /* MZ_F identical to MD_F. Can use either. */ + mv->h.invf = MZ_INVF; /* MZ_INVF identical to MD_INVF. Can use either. */ + for (sindex=0; sindexh.nsweeps; sindex++) + { + if (cv->sweep[sindex] == NULL) continue; + mv->sweep[sindex]->h.f = MZ_F; + mv->sweep[sindex]->h.invf = MZ_INVF; + for (rindex=0; rindexsweep[sindex]->h.nrays; rindex++) + { + if (cv->sweep[sindex]->ray[rindex] == NULL) continue; + mv->sweep[sindex]->ray[rindex]->h.f = MZ_F; + mv->sweep[sindex]->ray[rindex]->h.invf = MZ_INVF; + for (bindex=0; bindexsweep[sindex]->ray[rindex]->h.nbins; bindex++) + /* Has the Z_value been corrected by the QC algorithm? */ + + if (cv->sweep[sindex]->ray[rindex]->range[bindex] == cv->h.invf(BADVAL)) + mv->sweep[sindex]->ray[rindex]->range[bindex] = 1; + else /* Uncorrected Z_value. */ + mv->sweep[sindex]->ray[rindex]->range[bindex] = 0; + } /* end for (rindex=0; ... */ + } /* end for (sindex=0; ... */ + + return(mv); +} + +/*************************************************************/ +/* */ +/* metaDataWrite */ +/* */ +/*************************************************************/ +void metaDataWrite(IO_HANDLE *granuleHandle, Radar *radar, + char *hdfFileName, int fileAccessMode) +{ +/* Write out some metadata values into toolkit structures. */ + /* + * YOU REALLY DON'T KNOW, A PRIORI, WHAT DATATYPE THE METADATA ITEM IS. + * TRIAL and ERROR is how we figured some of them out. + * + * THEY SHOULD ALL BE STRINGS!!!!! + */ + char buf[1024]; + int intVal, vindex; + float floatVal; + DATE_STR tkdate; + TIME_STR tktime; + + vindex = nextVolume(radar, -1); /* Find 1st non-NULL rsl volume. */ + + /* ----------------- Core MetaData ---------------*/ + /* Begin/end date of the HDF granule. */ + tkdate.tkyear = (short) radar->h.year; + tkdate.tkmonth = (short) radar->h.month; + tkdate.tkday = (short) radar->h.day; + TKwriteMetadataInt(granuleHandle, TK_BEGIN_DATE, &tkdate); + TKwriteMetadataInt(granuleHandle, TK_END_DATE, &tkdate); + /* Begin time of the HDF granule. */ + tktime.tkhour = (int8) radar->h.hour; + tktime.tkminute = (int8) 0; + tktime.tksecond = (int8) 0; + TKwriteMetadataInt(granuleHandle, TK_BEGIN_TIME, &tktime); + /* End time of the HDF granule. */ + tktime.tkhour = (int8) radar->h.hour; + tktime.tkminute = (int8) 59; + tktime.tksecond = (int8) 59; + TKwriteMetadataInt(granuleHandle, TK_END_TIME, &tktime); + + /* Longitude & Bounding Coordinates */ + floatVal = radar->h.lond + radar->h.lonm/60.0 + radar->h.lons/3600.0; + TKwriteMetadataFloat(granuleHandle, TK_CENTER_POINT_LON, &floatVal); + floatVal = floatVal - 2.0; + TKwriteMetadataFloat(granuleHandle, TK_WEST_BOUND_COORD, &floatVal); + floatVal = floatVal + 4.0; + TKwriteMetadataFloat(granuleHandle, TK_EAST_BOUND_COORD, &floatVal); + /* Latitude & Bounding Coordinates */ + floatVal = radar->h.latd + radar->h.latm/60.0 + radar->h.lats/3600.0; + TKwriteMetadataFloat(granuleHandle, TK_CENTER_POINT_LAT, &floatVal); + floatVal = floatVal - 2.0; + TKwriteMetadataFloat(granuleHandle, TK_SOUTH_BOUND_COORD, &floatVal); + floatVal = floatVal + 4.0; + TKwriteMetadataFloat(granuleHandle, TK_NORTH_BOUND_COORD, &floatVal); + + TKwriteMetadataChar(granuleHandle, TK_CONTACT, "Danny Rosenfeld"); + + + + /* ----------------- PS MetaData ---------------*/ + TKwriteMetadataChar(granuleHandle, TK_ALGORITHM_VERSION, + tkMetaDataString.AlgorithmVersion); + TKwriteMetadataInt(granuleHandle, TK_PRODUCT_VERSION, + &tkMetaDataString.ProductVersion); + TKwriteMetadataChar(granuleHandle, TK_SOFTWARE_VERSION, + tkMetaDataString.SoftwareVersion); + TKwriteMetadataChar(granuleHandle, TK_MAX_VALID_CHANNEL, "70 dBz"); + TKwriteMetadataChar(granuleHandle, TK_MIN_VALID_CHANNEL, "-20 dBz"); + if (radar->h.nvolumes > 0) + { + floatVal = first_ray_in_volume[vindex]->h.wavelength; + } + else /* No radar volumes. Creating empty granule. */ + { + TKwriteMetadataChar(granuleHandle, TK_ANOMALY_FLAG, "EMPTY: REASON UNKNOWN"); + floatVal = 0.0; + } + TKwriteMetadataFloat(granuleHandle, TK_RADAR_WAVELENGTH, &floatVal); + + floatVal = -20.0; /* MIN_REFL_THRESHOLD */ + TKwriteMetadataFloat(granuleHandle, TK_MIN_REF_THRESHOLD, &floatVal); + TKwriteMetadataChar(granuleHandle, TK_RADAR_NAME, radar->h.radar_name); + TKwriteMetadataChar(granuleHandle, TK_RADAR_CITY, radar->h.city); + TKwriteMetadataChar(granuleHandle, TK_RADAR_STATE, radar->h.state); + TKwriteMetadataChar(granuleHandle, TK_RADAR_COUNTRY, radar->h.country); + + intVal = (int)TKgetNvos(granuleHandle); + TKwriteMetadataInt(granuleHandle, TK_NUM_VOS, &intVal); + TKwriteMetadataFloat(granuleHandle, TK_GV_DZCAL, &qcParm[ZCAL]); + floatVal = X; /* Mask scale factor */ + TKwriteMetadataFloat(granuleHandle, TK_GV_L1C_SCALE, &floatVal); + floatVal = 0.0; /* Correction for gaseous two-way attenuation */ + TKwriteMetadataFloat(granuleHandle, TK_GV_ALPHA, &floatVal); + + TKwriteMetadataChar(granuleHandle, TK_INPUT_FILES, "8mm tape files"); + TKwriteMetadataChar(granuleHandle, TK_DATA_CENTER_SRC, radar->h.radar_name); + + /* I really, really hate this 1C-51 kludge, but... + To decide (within function 'hdf1C51Create') whether or not to write + a VOS into a 1C-51 file, I need to know something about the times + of the VOSs already in the file; ie, if no satellite overpass, the + file is to contain just one VOS from each half-hour. + The only efficient way to do this is by encoding info into a metadata + field. + + So... I use the 'GEN_DATE_INPUT_FILES' metaData field. The intial + value of this field is the string 'unKNOWN'. When a VOS from the + first half_of_the_hour is written into the file, change the first + char 'u' to upper_case. When a VOS from the second half_of_the_hour + is written into the file, change the second char 'n' to upper_case. + The final string, after both time slots are filled, is entirely + upper_case: 'UNKOWN'. + */ + if (granuleHandle->productID == TK_L1C_GV) /* 1C-51 file? */ + { + /* If new file, then intitialize 'GEN_DATE_INPUT_FILES' string. + If file exists, then get the existing string from the file. */ + if (fileAccessMode == TK_NEW_FILE) strcpy(buf, "unKNOWN"); + else strcpy(buf, tkMetaDataString.GenInputDate); + if (radar->h.nvolumes > 0) /* Don't mess with an empty granule. */ + { + if (radar->h.minute < 30) /* 1st half_of_the_hour? */ + buf[0] = (char) toupper((int)buf[0]); /* Convert char to upper_case */ + else /* 2nd half_of_the_hour */ + buf[1] = (char) toupper((int)buf[1]); /* Convert char to upper_case */ + } + } + else /* 1B-51 file */ + { + strcpy(buf, "UNKNOWN"); + } + TKwriteMetadataChar(granuleHandle, TK_GEN_DATE_INPUT_FILES, buf); +} + +/*************************************************************/ +/* */ +/* newPhysicalSweep */ +/* */ +/*************************************************************/ +int newPhysicalSweep(Sweep *phys_sweep, Sweep *sweep) +{ + /* Checks if the rsl 'sweep' belongs to a different physical sweep + than 'phys_sweep'. + Returns: 1, if sweep is a new physical sweep + 0, if not new physical sweep + -1, if error. + */ + int nrays, iray; + + /* If elevations don't match, new sweep. */ + if (phys_sweep->h.elev != sweep->h.elev) return(1); + + /* Check the first 50 rays of both sweeps. + * If azimuths don't match, new sweep. + */ + nrays = 50; + if (sweep->h.nrays < nrays) nrays = sweep->h.nrays; + if (phys_sweep->h.nrays < nrays) nrays = phys_sweep->h.nrays; + for (iray=0; irayray[iray] == NULL) continue; + if (phys_sweep->ray[iray] == NULL) continue; + if (phys_sweep->ray[iray]->h.azimuth != sweep->ray[iray]->h.azimuth) + return(1); /* New physical sweep */ + } + + /* No new physical sweep. */ + return(0); +} + +/*************************************************************/ +/* */ +/* tkVosDimensions */ +/* */ +/*************************************************************/ +int tkVosDimensions(VosSize *vs, Radar *radar) +{ + /* Logically reconfigures the VOS in the rsl radar structure into + a sequence of physical sweeps as required for the toolkit + L1GV structure. + + Records required toolkit gvl1 dimensions in the 'VosSize->tk' + structure. When we later load the toolkit gvl1 structure with + actual data values, vs->tk.ncell[tk_sindex][pindex] will be zero + for those data types not collected by the radar during physical + sweep 'tk_sindex'. + + The algorithm used herein to locate physical sweeps is as simple + as possible. It works for all VOSs processed to date. However, + if more complicated radar scanning regimes turn up, this function + will surely require an overhaul and additional complexity. + + Algorithm: Within the rsl radar structure, walks horizontally + across the radar volumes at one sweep level, checking for elev + and azim values different from the last physical sweep located. + Then increments the sweep level and repeats at the next rsl sweep + level. + + Returns: OK, if success. + <0, if error. + */ + int pindex, sindex, tk_sindex, status; + Sweep *sweep; + + /* Note: 'vs->tk' structure contains all zeroes upon entry into this + function. */ + sindex = 0; /* rsl sweep index */ + tk_sindex = -1; /* toolkit sweep index */ + while (sindex < vs->rsl.maxNsweep) /* for each rsl sweep... */ + { + for (pindex=0; pindextk.nparm; pindex++) /* for each rsl volume */ + { + if (sindex >= vs->rsl.nsweep[pindex]) continue; + sweep = vs->rsl.v[pindex]->sweep[sindex]; + /* No null sweep ptrs allowed in rsl ptr array. */ + if (sweep == NULL) return(QUIT); + /* Check for a new physical sweep. */ + if (tk_sindex == -1) + { + tk_sindex++; + vs->tk.nray[tk_sindex] = vs->rsl.nray[pindex][sindex]; + vs->rsl.sweep[tk_sindex] = sweep; + } + else if ((status=newPhysicalSweep(vs->rsl.sweep[tk_sindex], sweep))) + { + if (status < 0) return(status); + tk_sindex++; + if (tk_sindex >= MAX_SWEEP) + { + if (radar_verbose_flag) + fprintf(stderr, "tkVosDimensions(): Too many toolkit sweeps.\n"); + return(QUIT); + } + vs->tk.nray[tk_sindex] = vs->rsl.nray[pindex][sindex]; + vs->rsl.sweep[tk_sindex] = sweep; + } /* end if (newPhysicalSweep */ + + vs->tk.ncell[tk_sindex][pindex] = vs->rsl.ncell[pindex][sindex]; + } /* end for (pindex=0;... */ + + sindex++; + } /* end while (sindex < vs->rsl.maxNsweep) */ + vs->tk.nsweep = tk_sindex + 1; + return(OK); +} + +/*************************************************************/ +/* */ +/* first_ray_in_sweep */ +/* */ +/*************************************************************/ +Ray *first_ray_in_sweep(Sweep *sweep) +{ + /* + * Return the first non-NULL ray in the sweep. + * Returns NULL, if error. + */ + int iray; + + if (sweep == NULL) return(NULL); + for (iray=0; irayh.nrays; iray++) + { + if (sweep->ray[iray] != NULL) + return(sweep->ray[iray]); + } + + return(NULL); +} + +/*************************************************************/ +/* */ +/* rslVosDimensions */ +/* */ +/*************************************************************/ +int rslVosDimensions(VosSize *vs, Radar *radar, float maxRange) +{ + /* Scopes out all dimensions of the VOS contained in the rsl + radar structure. Records dimensions in the 'VosSize->rsl' + structure. + + The ncell values may be less than the actual number of + bins in the radar structure, since the 1B-51/1C-51 standards + call for range truncation. Truncates range as necessary. + For 1B-51: Max range is the lesser of: + 1: max_range from radar structure, and + 2: 230 km + + For 1C-51: Max range is the lesser of: + 1: max_range from radar structure, and + 2: 200 km + + Returns OK, or + <0, if error. + */ + + /* Must differentiate between rsl and vosSize array indices, + since the rsl arrays may contain NULL elements. */ + int ivolume, isweep, iray; /* Indices for rsl arrays. */ + int Vindex, Sindex; /* Indices for non-NULL rsl array elements. */ + int nrays_in_sweep; + float maxRangeActual = 0.0; + Ray *ray; + Ray *longest_ray_in_sweep; + + /* Initialize the 'VosSize' structure. */ + memset(vs, '\0', sizeof(VosSize)); + vs->rsl.sweep[0] = NULL; + +/* + if (radar_verbose_flag) + fprintf(stderr, "RSL VOS Dimensions...\n"); +*/ + Vindex = -1; + for (ivolume=0; ivolumeh.nvolumes; ivolume++) + { + if (radar->v[ivolume] == NULL) continue; + Vindex++; + vs->rsl.v[Vindex] = radar->v[ivolume]; + Sindex = -1; + for (isweep=0; isweepv[ivolume]->h.nsweeps; isweep++) + { + if (radar->v[ivolume]->sweep[isweep] == NULL) continue; + Sindex++; + longest_ray_in_sweep = first_ray_in_sweep(radar->v[ivolume]->sweep[isweep]); + if (longest_ray_in_sweep == NULL) + { + fprintf(stderr, "rslVosDimensions(): no rays in sweep:%d ???\n\n", + isweep); + return(QUIT); + } + nrays_in_sweep = 0; + if (Sindex == 0) /* First sweep in volume? */ + first_ray_in_volume[ivolume] = longest_ray_in_sweep; + /* + * Go thru the entire sweep to find the number of + * rays, and the longest ray. + */ + for (iray=0; irayv[ivolume]->sweep[isweep]->h.nrays; iray++) + { + if (radar->v[ivolume]->sweep[isweep]->ray[iray] == NULL) continue; + ray = radar->v[ivolume]->sweep[isweep]->ray[iray]; + nrays_in_sweep++; + if (ray->h.nbins > longest_ray_in_sweep->h.nbins) + longest_ray_in_sweep = ray; + } /* end for (iray=0;... */ + + if (Sindex == 0) /* 1st sweep of this volume? */ + { + /* Find max range (km) of data in this sweep. */ + maxRangeActual = (longest_ray_in_sweep->h.range_bin1 + + longest_ray_in_sweep->h.nbins * + longest_ray_in_sweep->h.gate_size) / 1000.0; /*km*/ + if (maxRangeActual > maxRange+0.5) /* Truncate range at maxRange km */ + vs->rsl.ncell[Vindex][Sindex] = (int) + ((maxRange*1000.0 - longest_ray_in_sweep->h.range_bin1) / + longest_ray_in_sweep->h.gate_size); + else + vs->rsl.ncell[Vindex][Sindex] = (int) + ((maxRangeActual*1000.0 - longest_ray_in_sweep->h.range_bin1) / + longest_ray_in_sweep->h.gate_size); + if (vs->rsl.ncell[Vindex][Sindex] > MAX_CELL) + { + fprintf(stderr, "rslVosDimensions(): ncell[parm%d]=%d > MAX_CELL=%d ", + Vindex, vs->rsl.ncell[Vindex][Sindex], MAX_CELL); + fprintf(stderr, " gate_size:%d\n", longest_ray_in_sweep->h.gate_size); + return(QUIT); + } + } /* end if (Sindex == 0) */ + else /* Not the 1st sweep of volume. */ + { + if (longest_ray_in_sweep->h.nbins > vs->rsl.ncell[Vindex][0]) + vs->rsl.ncell[Vindex][Sindex] = vs->rsl.ncell[Vindex][0]; + else + vs->rsl.ncell[Vindex][Sindex] = longest_ray_in_sweep->h.nbins; + } + + vs->rsl.nray[Vindex][Sindex] = nrays_in_sweep; + if (vs->rsl.nray[Vindex][Sindex] > vs->rsl.maxNray) + { + vs->rsl.maxNray = vs->rsl.nray[Vindex][Sindex]; + if (vs->rsl.maxNray > MAX_RAY) + { + fprintf(stderr, "rslVosDimensions(): v[%d]->sweep[%d].nray=%d > MAX_RAY=%d\n", + ivolume, isweep, vs->rsl.nray[Vindex][Sindex], MAX_RAY); + return(QUIT); + } + } + } /* end for (isweep=0;... */ + vs->rsl.nsweep[Vindex] = Sindex + 1; + if (vs->rsl.nsweep[Vindex] > vs->rsl.maxNsweep) + { + vs->rsl.maxNsweep = vs->rsl.nsweep[Vindex]; + if (vs->rsl.maxNsweep > MAX_SWEEP) + { + fprintf(stderr, "rslVosDimensions(): v[%d].nsweep=%d > MAX_SWEEP=%d\n", + ivolume, vs->rsl.nsweep[Vindex], MAX_SWEEP); + return(QUIT); + } + } +/* + if (radar_verbose_flag) + { + fprintf(stderr, + " vIndex:%2d nsweeps:%d cellSize(m):%4d ncells:%d maxRng(km):%.1f\n", + ivolume, vs->rsl.nsweep[Vindex], longest_ray_in_sweep->h.gate_size, + longest_ray_in_sweep->h.nbins, maxRangeActual); + } +*/ + } /* for (ivolume=0;... */ + vs->tk.nparm = Vindex + 1; + if ((vs->tk.nparm == 0) || (vs->tk.nparm > MAX_PARM)) + { + fprintf(stderr, "rslVosDimensions(): Invalid nparm=%d\n", vs->tk.nparm); + return(QUIT); + } + + return(OK); +} + +/*************************************************************/ +/* */ +/* L1GVtemplateInit */ +/* */ +/*************************************************************/ +int L1GVtemplateInit(VosSize *vs, Radar *radar, char *hdfFileName, + float maxRange) +{ +/* Create a toolkit 'Level_1B_1C_GV' template_node for the VOS + contained in the radar structure. To do this: + 1: Based on the data contained in the rsl structure, initialize + the following toolkit arrays: + 'TKnparm' : no. of volumes in radar structure (DZ, VR, ZD, etc). + 'TKnsweep': max no. of sweeps/volume, over all volumes. + 'TKnray' : max no. of rays per sweep, over all volumes. + 'TKncell': max no. of cells (bins) per ray, over all volumes, all sweeps. + These values are parameters for the 'TKsetL1GVtemplate()' + toolkit function call. + 2: Call TKsetL1GVtemplate(). + + Returns: + OK, if success. + <0, if failure. +*/ + int pindex, status; + int32 TKnparm[MAX_VOS], TKnsweep[MAX_VOS], TKnray[MAX_VOS]; + int32 TKncell[MAX_VOS][MAX_PARM]; + + /* Scope out all dimensions of the VOS contained in the rsl structure. */ + status = rslVosDimensions(vs, radar, maxRange); + if (status < 0) return(status); + /* Set the toolkit VOS dimensions. These are different from the rsl + dimensions. The toolkit L1GV structure is organized as a + sequence of physical sweeps, while RSL is organized as a + sequence of logical "volumes". + */ + status = tkVosDimensions(vs, radar); + if (status < 0) return(status); + + /* Fill required toolkit array values for TKsetL1GVtemplate() call. */ + TKnparm[0] = vs->tk.nparm; + TKnsweep[0] = vs->tk.nsweep; + TKnray[0] = vs->rsl.maxNray; +/* + if (radar_verbose_flag) + fprintf(stderr, "Toolkit VOS Dimensions...\n"); +*/ + for (pindex=0; pindextk.nparm; pindex++) + { + TKncell[0][pindex] = vs->rsl.ncell[pindex][0]; +/* + if (radar_verbose_flag) + fprintf(stderr, " pIndex:%d nsweep:%d nray:%d ncell:%d\n", pindex, + (int)TKnsweep[0], (int)TKnray[0], (int)TKncell[0][pindex]); +*/ + } + + /* Create a toolkit template_node for this VOS. */ + status = TKsetL1GVtemplate(1, TKnparm, TKncell, TKnray, TKnsweep, hdfFileName); + if (status != TK_SUCCESS) + { + fprintf(stderr, "L1GVtemplateInit(): *****TKsetL1GVtemplate() error\n"); + return(ABORT); + } + + return(OK); /* Successful template_node creation. */ +} + +/*************************************************************/ +/* */ +/* hdfFileOpen */ +/* */ +/*************************************************************/ +static int hdfFileOpen(IO_HANDLE *granuleHandle, VosSize *vs, + char *hdfFileName, Radar *radar) +{ +/* Create a toolkit template node for the new VOS, and then open + a HDF file in which to write the VOS. + + Returns: + OK, if success. + <0, if failure. +*/ + char fileAccessMode; + int productID, status; + float maxRange; + struct stat buf; + + /* Based on the product desired, set the maximum range of radar data + values for the HDF file. + For 1B-51: Max range = 230.0 km. + For 1C-51: Max range = 200.0 km + */ + productID = (int)granuleHandle->productID; + if (productID == TK_L1B_GV) + maxRange = MAX_RANGE_1B51; + else if (productID == TK_L1C_GV) + maxRange = MAX_RANGE_1C51; + else + { + fprintf(stderr, "hdfFileOpen(): Invalid product type\n"); + return(ABORT); + } + + /* Create a L1BGV template node for the new VOS. */ +/* + if (radar_verbose_flag) + fprintf(stderr, "\n****** Creating toolkit template_node for VOS ...\n"); +*/ + status = L1GVtemplateInit(vs, radar, hdfFileName, maxRange); + if (status < 0) return(status); + + /* Determine if the HDF file to which this VOS belongs already exists.*/ + if (stat(hdfFileName, &buf) == 0) + { + /* The HDF file already exists. We will append this VOS to it. */ + fileAccessMode = TK_APPEND; + if (radar_verbose_flag) + fprintf(stderr, "\n****** Opening HDF file: %s to append VOS ...\n", + hdfFileName); + } + else /* The HDF file does not exist. We must create it. */ + { + fileAccessMode = TK_NEW_FILE; + if (radar_verbose_flag) + fprintf(stderr, "\n****** Opening new HDF file: %s to write VOS ...\n", + hdfFileName); + } + + /* Finally, open the HDF file. */ + status = TKopen(hdfFileName, productID, fileAccessMode, granuleHandle); + if (status != TK_SUCCESS) + { + if (radar_verbose_flag) + fprintf(stderr, "level_1(): ***** TKopen() error\n"); + return(ABORT); + } + + /* Find the slot number in the HDF granule for this VOS. */ + vs->vos_num = TKgetNvos(granuleHandle) - 1; + + /* Write metadata fields into HDF file. */ + metaDataWrite(granuleHandle, radar, hdfFileName, fileAccessMode); + + return(OK); +} + +/*************************************************************/ +/* */ +/* radarPrep1B51 */ +/* */ +/*************************************************************/ +int radarPrep1B51(Radar *radar) +{ +/* + Prepare the RSL radar structure for 1B-51 processing: + Null the pointers to RSL volumes not required for 1B-51. + + Returns OK. +*/ + int j; + + /* For 1B-51, we need only the DZ, VR, and ZD data volumes. NULL the + pointers to all other volumes. */ + for (j=0; jh.nvolumes; j++) + { + if (radar->v[j] == NULL) + continue; + if ((j == DZ_INDEX) || (j == VR_INDEX) || (j == ZD_INDEX)) + continue; + radar->v[j] = NULL; + } /* end for (j=0; ... */ + + return(OK); +} + +/*************************************************************/ +/* */ +/* radarPrep1C51 */ +/* */ +/*************************************************************/ +int radarPrep1C51(Radar *radar) +{ +/* + Prepare the RSL radar structure for 1C-51 processing. + 1. Check that the necessary RSL volumes exist. + 2. Create mask volumes. + 3. Null the pointers to RSL volumes not required for 1C-51. + + Returns: + OK, if success. + <0, if failure. +*/ + int j; + + if (radar->v[DZ_INDEX] != NULL) /* Is there a DZ volume? */ + { + if (radar->v[CZ_INDEX] == NULL) /* DZ exists, hence CZ should exist. */ + { + fprintf(stderr, "RSL_radar_to_hdf(): CZ volume expected but not found.\n"); + return(QUIT); + } + else /* Both DZ and CZ volumes exist. */ + { + /* Construct mask volume MZ */ + radar->v[MZ_INDEX] = maskBuild(radar->v[CZ_INDEX], radar->v[DZ_INDEX]); + /* We're now finished with the RSL CZ data, so let the CZ volume point + to the uncorrected volume DZ. We will later use it, + in combination with the mask volume MZ, to create the HDF CZ volume. + (The HDF CZ values differ from the RSL CZ values.) + */ + radar->v[CZ_INDEX] = radar->v[DZ_INDEX]; + } + } /* end if (radar->v[DZ_INDEX] != NULL) */ + + /* For 1C-51, we need only the following volumes: + CZ: QC'ed reflectivity, which we will later obtain from DZ and MZ + MZ: mask to obtain DZ from CZ + NULL the pointers to all other volumes. + */ + for (j=0; jh.nvolumes; j++) + { + if (radar->v[j] == NULL) + continue; + if ((j == CZ_INDEX) || (j == MZ_INDEX)) + continue; + radar->v[j] = NULL; + } /* end for (j=0; ... */ + + return(OK); +} + +/*************************************************************/ +/* */ +/* nullGranuleCreate */ +/* */ +/*************************************************************/ +int nullGranuleCreate(char *hdfFileName, IO_HANDLE *granuleHandle, + Radar *radar) +{ +/* + Create an HDF file containing an empty granule. +*/ + int status; + struct stat buf; + /* Following arrays required by toolkit function 'TKsetL1GVtemplate()'*/ + int32 TKnparm[MAX_VOS], TKnsweep[MAX_VOS], TKnray[MAX_VOS]; + int32 TKncell[MAX_VOS][MAX_PARM]; + + /* Check if this HDF file already exists. If it exists, abort. */ + if (stat(hdfFileName, &buf) == 0) + { + if (radar_verbose_flag) + fprintf(stderr, "\nnullGranuleCreate(): File %s already exists.\n", + hdfFileName); + return(ABORT); + } + + /* Fill toolkit array values for subsequent TKsetL1GVtemplate() call. */ + TKnparm[0] = TKnsweep[0] = TKnray[0] = TKncell[0][0] = 0; + /* Create a L1 GV template_node. */ + status = TKsetL1GVtemplate(0, TKnparm, TKncell, TKnray, TKnsweep, hdfFileName); + if (status != TK_SUCCESS) + { + fprintf(stderr, "nullGranuleCreate(): ***** TKsetL1GVtemplate() error\n"); + return(ABORT); + } + + /* Open the HDF file. */ + if (radar_verbose_flag) + fprintf(stderr, "\n\n****** Opening new HDF file: %s for empty granule...\n", + hdfFileName); + status = TKopen(hdfFileName, TK_L1C_GV, TK_NEW_FILE, granuleHandle); + if (status != TK_SUCCESS) + { + if (radar_verbose_flag) + fprintf(stderr, "nullGranuleCreate(): ***** TKopen() error\n"); + return(ABORT); + } + /* Write metadata fields into HDF file. */ + metaDataWrite(granuleHandle, radar, hdfFileName, TK_NEW_FILE); + /* Close the HDF file */ + if (radar_verbose_flag) + fprintf(stderr, "\n****** Closing HDF file: %s ...\n\n", hdfFileName); + status = TKclose(granuleHandle); + if (status != TK_SUCCESS) + { + if (radar_verbose_flag) + fprintf(stderr, "nullGranuleCreate(): ***** TKclose() error\n"); + return(ABORT); + } + + return(OK); +} + +/*************************************************************/ +/* */ +/* RSL_radar_to_hdf */ +/* */ +/*************************************************************/ +int RSL_radar_to_hdf(Radar *radar, char *hdfFileName) +{ +/* + Writes one VOS from a RSL radar structure into one HDF file. + Returns: + OK , if success. + <0 , if failure. (See Error code definitions at top of file.) +*/ + char product[8]; + int status; + L1B_1C_GV *gvl1; /* Toolkit structure for VOS storage. */ + IO_HANDLE granuleHandle; /* Toolkit file_descriptor structure. */ + VosSize vs; /* Storage of VOS dimensions. */ + Volume *v[MAX_RADAR_VOLUMES]; /* Storage of radar volume pointers. */ + + if (radar == NULL) return(ABORT); + + if (radar->h.nvolumes == 0) + /* Create an HDF file to contain an empty granule. */ + { + status = nullGranuleCreate(hdfFileName, &granuleHandle, radar); + return(status); + } + /* We will, within functions radarPrep1B51() and radarPrep1C51(), + manipulate the array of radar volume pointers radar->v[]. + Hence we here save the array radar->v[] in v[], so we can restore + radar->v[] to its original condition before leaving this function. + */ + radarVolumesSave(v, radar); + + /* Get the desired product out of the HDF filename. */ + sscanf(strrchr(hdfFileName, '/'), "/%4s", product); + if (strcmp(product, "1B51") == 0) + { + granuleHandle.productID = TK_L1B_GV; + status = radarPrep1B51(radar); + } + else if (strcmp(product, "1C51") == 0) + { + granuleHandle.productID = TK_L1C_GV; + status = radarPrep1C51(radar); /* Creates mask volumes. */ + } + else /* Unknown product. */ + { + status = ABORT; + if (radar_verbose_flag) + fprintf(stderr, "RSL_radar_to_hdf(): Unknown product requested: %s.\n", + product); + } + if (status < 0) goto quit; + + /* Open the HDF file 'hdfFileName'. */ + status = hdfFileOpen(&granuleHandle, &vs, hdfFileName, radar); + if (status < 0) goto quit; + + /* Build toolkit 'L1B_1C_GV' structure using data from radar structure.*/ + if (radar_verbose_flag) + fprintf(stderr, "\n****** Moving VOS from RSL structure --> toolkit structure ...\n"); + gvl1 = gvl1Build(radar, qcParm, &vs, (int)granuleHandle.productID); + + /* Write data from toolkit 'L1B_1C_GV' structure to HDF file. */ + if (radar_verbose_flag) + fprintf(stderr, "\n****** Writing VOS to HDF file: %s ...\n", hdfFileName); + status = TKwriteL1GV(&granuleHandle, gvl1); + if (status != TK_SUCCESS) + { + TKclose(&granuleHandle); + status = ABORT; + if (radar_verbose_flag) + fprintf(stderr, "RSL_radar_to_hdf(): *** TKwriteL1GV() error\n"); + goto free_memory_and_quit; + } + + /* Close the HDF file */ + if (radar_verbose_flag) + fprintf(stderr, "\n****** Closing HDF file: %s ...\n\n", hdfFileName); + status = TKclose(&granuleHandle); + if (status == TK_SUCCESS) + status = OK; + else + { + if (radar_verbose_flag) + fprintf(stderr, "RSL_radar_to_hdf(): *** TKclose() error\n"); + status = ABORT; + } + + free_memory_and_quit: + /* Free memory allocated to the toolkit 'L1B_1C_GV' structure. */ + TKfreeGVL1(gvl1); + /* If RSL mask volumes for 1C-51 were created above, free them. */ + if (radar->v[MZ_INDEX] != NULL) + RSL_free_volume(radar->v[MZ_INDEX]); + if (radar->v[MD_INDEX] != NULL) + RSL_free_volume(radar->v[MD_INDEX]); + quit: + /* Restore the array of radar volume pointers in radar->v[]. */ + radarVolumesRestore(radar, v); + return(status); +} +#endif diff --git a/radar_to_hdf_2.c b/radar_to_hdf_2.c new file mode 100644 index 0000000..2fac4b0 --- /dev/null +++ b/radar_to_hdf_2.c @@ -0,0 +1,781 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBTSDISTK +/****************************************************************** + + Subroutines to write one VOS from a RSL radar structure into one + 1B-51/1C-51 HDF file. + + A 1B-51/1C-51 HDF file contains multiple VOS's recorded by a radar + site during a 1-hour time period, and the HDF file is named using + the date/hour of the constituent VOS's. + + All functions defined herein build the components of the TSDIS + toolkit 'L1B_1C_GV' structure using the data from a RSL radar + structure. These functions are executed via a call from the top-level + RSL function 'RSL_radar_to_hdf()', defined in RSL file + 'radar_to_hdf_1.c'. + + ----------------------------------------------------------------- + Libraries required for execution of this code : + -ltsdistk : TSDIS toolkit + -lmfhdf -ldf -ljpeg -lz : HDF + -lrsl : rsl + -lm : C math + + ----------------------------------------------------------------- +*******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* TSDIS toolkit function and structure definitions. */ +#include "IO.h" +#include "IO_GV.h" +/* RSL function and structure definitions. */ +#include "rsl.h" +/* Parameter definitions for 1B-51 and 1C-51 HDF + file handling applications using the TSDIS toolkit. */ +#include "toolkit_1BC-51_appl.h" + + +/*************************************************************/ +/* */ +/* Function Prototypes */ +/* */ +/*************************************************************/ +static int julian(int year, int mo, int day); +int8 ***parmData1byteBuild(Volume *v, int pindex, VosSize *vs); +int16 ***parmData2byteBuild(Radar *radar, PARAMETER_DESCRIPTOR *parmDesc, + int vindex, int pindex, VosSize *vs); +void cellRangeVectorFill(CELL_RANGE_VECTOR *cellRangeVector, + int vindex, int pindex, VosSize *vs); +void parmDescFill(PARAMETER_DESCRIPTOR *parmDesc, Radar *radar, int vindex); +PARAMETER *parmBuild(Radar *radar, VosSize *vs, int vindex, + int pindex); +void rayInfoFill(int32 rayInfoInteger[MAX_SWEEP][MAX_RAY][7], + float32 rayInfoFloat[MAX_SWEEP][MAX_RAY][4], + Radar *radar, VosSize *vs); +void sweepInfoFill(SWEEP_INFO sweepInfo[MAX_SWEEP], Radar *radar, VosSize *vs); +void radarDescFill(RADAR_DESCRIPTOR *radarDesc, Radar *radar, int vindex, + VosSize *vs); +void sensorFill(SENSORS *sensor, Radar *radar, VosSize *vs, int productID); +struct tm *timeUTC(void); +void volDesFill(VOLUME_DESCRIPTORS *volDes, Radar_header *h, VosSize *vs); +void commentsFill(char *comments, VosSize *vs, Radar *radar, + float *qcParm, int productID); +L1B_1C_GV *gvl1Build(Radar *radar, float *qcParm, VosSize *vs, + int productID); + +extern int nextVolume(Radar *radar, int last_volume); +extern int radar_verbose_flag; +extern Ray *first_ray_in_volume[MAX_RADAR_VOLUMES]; + +/*************************************************************/ +/* */ +/* julian */ +/* */ +/*************************************************************/ +static int daytab[2][13] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} +}; + +static int julian(int year, int mo, int day) +{ +/* Converts a calendar date (month, day, year) to a Julian date. + Returns: + Julian day. +*/ + int leap; + + leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; + return(day + daytab[leap][mo-1]); +} + +/*************************************************************/ +/* */ +/* parmData1byteBuild */ +/* */ +/*************************************************************/ +int8 ***parmData1byteBuild(Volume *v, int pindex, VosSize *vs) +/* Move all data from one mask volume of the RSL structure into + the array parmData1byte[][][] . +*/ +{ + int sindex, rindex, bindex; /* Indices for rsl arrays. */ + int tk_sindex, tk_rindex; /* Indices for toolkit arrays. */ + int ncell; + int8 ***data1byte; + Ray *ray; + + ncell = vs->rsl.ncell[pindex][0]; + data1byte = (int8 ***)TKnewParmData1byte(vs->tk.nsweep, vs->rsl.maxNray, + ncell); + /* Move data values from all non-NULL rsl sweeps into the + 'parmData1byte' array. */ + sindex = -1; + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + { + if (vs->tk.ncell[tk_sindex][pindex] == 0) + { + /* No data from this parm in this physical sweep. + Fill bins of this 'parmData1byte' sweep with 0 */ + for (rindex=0; rindexrsl.maxNray; rindex++) + for (bindex=0; bindexsweep[sindex]->h.nrays; rindex++) + { + if (v->sweep[sindex]->ray[rindex] == NULL) continue; + tk_rindex++; + ray = v->sweep[sindex]->ray[rindex]; + /* Move the rsl bin values which exist into the 'parmData1byte' ray.*/ + for (bindex=0; bindextk.ncell[tk_sindex][pindex]; bindex++) + { + if (bindex >= ray->h.nbins) /* Short rsl ray? */ + data1byte[tk_sindex][tk_rindex][bindex] = (int8) 0; + else /* Valid bin */ + data1byte[tk_sindex][tk_rindex][bindex] = (int8) ray->range[bindex]; + } /* end for (bindex=0... */ + /* Fill all remaining bins of 'parmData1byte' ray with 0. */ + for (bindex=vs->tk.ncell[tk_sindex][pindex]; bindexrsl.maxNray; rindex++) + for (bindex=0; bindexrsl.ncell[pindex][0]; + data2byte = (int16 ***)TKnewParmData2byte(vs->tk.nsweep, vs->rsl.maxNray, ncell); + v = radar->v[vindex]; + /* Move data values from all non-NULL rsl sweeps into the + 'parmData2byte' array. */ + sindex = -1; + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + { + if (vs->tk.ncell[tk_sindex][pindex] == 0) + { + /* No data from this parm in this physical sweep. + Fill bins of this 'parmData2byte' sweeps with NO_VALUE. */ + for (rindex=0; rindexrsl.maxNray; rindex++) + for (bindex=0; bindexsweep[sindex]->h.nrays; rindex++) + { + if (v->sweep[sindex]->ray[rindex] == NULL) continue; + tk_rindex++; + ray = v->sweep[sindex]->ray[rindex]; + /* Move the rsl bin values which exist into the 'parmData2byte' ray.*/ + for (bindex=0; bindextk.ncell[tk_sindex][pindex]; bindex++) + { + /* if short rsl ray, fill cell with NO_VALUE */ + if (bindex >= ray->h.nbins) + { + data2byte[tk_sindex][tk_rindex][bindex] = (int16) NO_VALUE; + continue; + } + value = v->h.f(ray->range[bindex]); + if (value >= NOECHO) /* Handle anomalous condition flags */ + { + if (value == BADVAL) + data2byte[tk_sindex][tk_rindex][bindex] = (int16) NO_VALUE; + else if (value == RFVAL) + data2byte[tk_sindex][tk_rindex][bindex] = (int16) RNG_AMBIG_VALUE; + else if (value == APFLAG) + data2byte[tk_sindex][tk_rindex][bindex] = (int16) AP_VALUE; + else + data2byte[tk_sindex][tk_rindex][bindex] = (int16) NOECHO_VALUE; + } + else /* Valid rsl data */ + { + if (vindex == CZ_INDEX) /* Corrected Z data */ + { + /* CZ = DZ + dzCal - mask_val * X ... From Ferrier memo. */ + value = (value + v->h.calibr_const - + radar->v[MZ_INDEX]->sweep[sindex]->ray[rindex]->range[bindex] * X); + } + else if (vindex == CD_INDEX) /* Corrected differential Z data */ + { + /* CD = ZD - mask_val * X */ + value = value - + radar->v[MD_INDEX]->sweep[sindex]->ray[rindex]->range[bindex] * X; + } + /* Apply scale and offset factors, then store value in + parmData2byte structure. */ + data2byte[tk_sindex][tk_rindex][bindex] = (int16) + (value * parmDesc->scaleFactor + parmDesc->offsetFactor); + } /* end else Valid rsl data */ + } /* end for (bindex=0;... */ + + /* Fill all remaining bins of 'parmData2byte' ray with NO_VALUE. */ + for (bindex=vs->tk.ncell[tk_sindex][pindex]; bindexrsl.maxNray; rindex++) + for (bindex=0; bindexnumOfCells = (int32) vs->rsl.ncell[pindex][0]; + ray_head = &first_ray_in_volume[vindex]->h; + + /* Do first cell (m) */ + cellRangeVector->distanceToCell[0] = (float32) (ray_head->range_bin1 + + 0.5 * ray_head->gate_size); + + /* Do remaining cells. Just add gate_size to previous cellRange value. */ + for (j=1; jnumOfCells; j++) + { + cellRangeVector->distanceToCell[j] = (float32) + (cellRangeVector->distanceToCell[j-1] + ray_head->gate_size); + } +} + +/*************************************************************/ +/* */ +/* parmDescFill */ +/* */ +/*************************************************************/ +void parmDescFill(PARAMETER_DESCRIPTOR *parmDesc, Radar *radar, int vindex) +{ + static char *parm_list[20][3] = + { + { "Z", "dBz", "Reflectivity" }, + { "V", "m/s", "Radial Velocity" }, + { "SW", "m2/s2", "Spectral Width" }, + { "QCZ", "dBz", "QC'ed Reflectivity" }, + { "ZT", "dBz", "Total Reflectivity" }, + { "DR", "?", "Differential reflectivity" }, + { "LR", "?", "Differential reflectivity" }, + { "ZDR", "dB", "Differential Reflectivity" }, + { "DM", "dBm", "Received power" }, + { "RH", "-", "Correlation Coefficient" }, + { "PH", "?", "Phi" }, + { "XZ", "dBz", "X-band Reflectivity" }, + { "QCZDR", "dB", "QC'ed Differential Reflectivity" }, + { "QCMZ", "-", "Z Mask" }, + { "QCMZDR", "-", "ZDR Mask" }, + { "ZE", "-", "Edited Reflectivity" }, + { "VE", "-", "Edited Velocity" }, + { "--", "-", "*******" }, + { "--", "-", "*******" }, + { "--", "-", "*******" } + }; + + strncpy(parmDesc->parmName, parm_list[vindex][0], 7); + strncpy(parmDesc->parmDesc, parm_list[vindex][2], 39); + strncpy(parmDesc->parmUnits, parm_list[vindex][1], 7); + parmDesc->interPulsePeriod = (int16) 0; + parmDesc->transFreq = (int16) 1; + /* Receiver Bandwidth (MHz) */ + parmDesc->receiverBandwidth = (float32) 0.0; + /* Pulse width (m) */ + parmDesc->pulseWidth = (int16) (300.0 * + first_ray_in_volume[vindex]->h.pulse_width); + parmDesc->polarTransWave = (int16) 0; + parmDesc->numOfsamples = (int16) 0; + /* No thresholding done in 1B-51, 1C-51 HDF files. */ + strncpy(parmDesc->thresholdField, "NONE", 8); + parmDesc->thresholdValue = (float32) 0.0; + parmDesc->offsetFactor = (float32) 0.0; + if ((vindex == MZ_INDEX) || (vindex == MD_INDEX)) + { + parmDesc->parmDataType = (int16) 1; /* 1_byte mask value. */ + parmDesc->scaleFactor = (float32) 1.0; + parmDesc->deletedOrMissDataFlag = (int32) 0; + } + else /* 2_byte data value. */ + { + parmDesc->parmDataType = (int16) 2; + parmDesc->scaleFactor = (float32) SCALE_FACTOR; + parmDesc->deletedOrMissDataFlag = (int32) NO_VALUE; + } +} + +/*************************************************************/ +/* */ +/* parmBuild */ +/* */ +/*************************************************************/ +PARAMETER *parmBuild(Radar *radar, VosSize *vs, int vindex, + int pindex) +{ + PARAMETER *parm; + + /* Allocate memory for a new parameter structure. */ + parm = (PARAMETER *)TKnewGVL1parm(); + + parmDescFill(&parm->parmDesc, radar, vindex); + cellRangeVectorFill(&parm->cellRangeVector, vindex, pindex, vs); + if ((vindex == MZ_INDEX) || (vindex == MD_INDEX)) /* Mask? */ + parm->parmData1byte = (int8 ***)parmData1byteBuild(radar->v[vindex], + pindex, vs); + else + parm->parmData2byte = (int16 ***)parmData2byteBuild(radar, &parm->parmDesc, + vindex, pindex, vs); + return(parm); +} + +/*************************************************************/ +/* */ +/* rayInfoFill */ +/* */ +/*************************************************************/ +void rayInfoFill(int32 rayInfoInteger[MAX_SWEEP][MAX_RAY][7], + float32 rayInfoFloat[MAX_SWEEP][MAX_RAY][4], + Radar *radar, VosSize *vs) +/* For each ray in the rsl structure, move ray header info into the + arrays rayInfoInteger[][][] and rayInfoFloat[][][]. +*/ +{ + int tk_sindex, rindex, tk_rindex; + double second; + Ray_header *ray_head; + Sweep *sweep; + static int32 julday; + static int day=-1; + + /* For each physical sweep...*/ + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + { + sweep = vs->rsl.sweep[tk_sindex]; + tk_rindex = -1; + for (rindex=0; rindexh.nrays; rindex++) + { + if (sweep->ray[rindex] == NULL) continue; + tk_rindex++; + /*********** Fill in ray info fields. ***************/ + ray_head = &sweep->ray[rindex]->h; + /* No. of sweep which contains this ray. */ + rayInfoInteger[tk_sindex][tk_rindex][0] = (int32)(tk_sindex + 1); + /* Compute Julian Day. Usually do only once per vos. */ + if (day != ray_head->day) + { + day = ray_head->day; /* Note day & julday are static. */ + julday = (int32) + julian(ray_head->year, ray_head->month, ray_head->day); + } + rayInfoInteger[tk_sindex][tk_rindex][1] = (int32) julday; + rayInfoInteger[tk_sindex][tk_rindex][2] = (int32) ray_head->hour; + rayInfoInteger[tk_sindex][tk_rindex][3] = (int32) ray_head->minute; + rayInfoInteger[tk_sindex][tk_rindex][5] = (int32) (1000.0 * + modf(ray_head->sec, &second)); + rayInfoInteger[tk_sindex][tk_rindex][4] = (int32) second; + /* Ray status. 0:Normal , 1:Tansition , 2:Bad , 3:Questionable */ +/* rayInfoInteger[tk_sindex][tk_rindex][6] = (int32) 0; */ + + rayInfoFloat[tk_sindex][tk_rindex][0] = (float32) ray_head->azimuth; + rayInfoFloat[tk_sindex][tk_rindex][1] = (float32) ray_head->elev; + /* Store num_of_samples here instead of power. */ + rayInfoFloat[tk_sindex][tk_rindex][2] = (float32) ray_head->pulse_count; + /* Store prf here instead of Sweep Rate */ + rayInfoFloat[tk_sindex][tk_rindex][3] = (float32) ray_head->prf; + } /* end (rindex=0;... */ + } /* end for (tk_sindex=0;...*/ +} + +/*************************************************************/ +/* */ +/* sweepInfoFill */ +/* */ +/*************************************************************/ +void sweepInfoFill(SWEEP_INFO sweepInfo[MAX_SWEEP], Radar *radar, VosSize *vs) +{ + int rindex, tk_sindex; + Sweep *sweep; + + /* For each physical sweep...*/ + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + { + sweep = vs->rsl.sweep[tk_sindex]; + /* Fill in sweep info from the 1st non-NULL rsl ray we find. */ + for (rindex=0; rindexh.nrays; rindex++) + { + if (sweep->ray[rindex] == NULL) continue; + strncpy(sweepInfo[tk_sindex].radarName, radar->h.radar_name, 8); + /* 1st sweep number (for tsdis structures) is 1 */ + sweepInfo[tk_sindex].sweepNum = (int32) (tk_sindex + 1); + /* No. of rays in sweep */ + sweepInfo[tk_sindex].numRays = (int32) vs->tk.nray[tk_sindex]; + sweepInfo[tk_sindex].trueStartAngle = (float32) + sweep->ray[rindex]->h.azimuth; + if (sweep->ray[sweep->h.nrays-1] != NULL) + sweepInfo[tk_sindex].trueStopAngle = (float32) + sweep->ray[sweep->h.nrays-1]->h.azimuth; + else + sweepInfo[tk_sindex].trueStopAngle = (float32) + sweepInfo[tk_sindex].trueStartAngle; + /* degrees. Only for PPI scans. */ + sweepInfo[tk_sindex].fixedAngle = (float32) sweep->h.elev; + /* Filter Flag. 0: No filtering, 1: filtered (descr in comment block) */ +/* sweepInfo[tk_sindex].filterFlag = (int32) 0; */ + break; + } + } /* end for (tk_sindex=0;... */ +} + +/*************************************************************/ +/* */ +/* radarDescFill */ +/* */ +/*************************************************************/ +void radarDescFill(RADAR_DESCRIPTOR *radarDesc, Radar *radar, int vindex, + VosSize *vs) +{ + strncpy(radarDesc->radarName, radar->h.name, 8); +/*radarDesc->radarConstant = (float32) 0.0; + radarDesc->nomPeakPower = (float32) 0.0; + radarDesc->nomNoisePower = (float32) 0.0; + radarDesc->receiverGain = (float32) 0.0; + radarDesc->antennaGain = (float32) 0.0; + radarDesc->radarSystemGain = (float32) 0.0; +*/ + radarDesc->horBeamWidth = (float32) first_ray_in_volume[vindex]->h.beam_width; + radarDesc->verBeamWidth = (float32) first_ray_in_volume[vindex]->h.beam_width; + radarDesc->radarType = (int16) 0; /* 0: Ground-based radar */ + radarDesc->scanMode = (int16) 1; /* 1: PPI , 3: RHI */ + /* radar sweep rate (deg/sec) */ + radarDesc->nomScanRate = (float32) + (first_ray_in_volume[vindex]->h.sweep_rate * 6.0); + /* Following holds only for PPI scans. ??? */ + radarDesc->nomStartAngle = (float32) + first_ray_in_volume[vindex]->h.azimuth; + radarDesc->nomStopAngle = (float32) radarDesc->nomStartAngle; + radarDesc->numParmDesc = (int16) vs->tk.nparm; + radarDesc->numDesc = (int16) vs->tk.nparm; + /* Data compression. Always 0 . Data compression done by HDF.*/ + radarDesc->dataComp = (int16) 0; + /* Data reduction algorithm. */ + radarDesc->dataReductAlg = (int16) 0; /* 0: No reduction */ + radarDesc->dataReductParm1 = (float32) 4.0; /* TBD */ + radarDesc->dataReductParm2 = (float32) 4.0; /* TBD */ + radarDesc->radarLon = (float32) (radar->h.lond + radar->h.lonm/60.0 + + radar->h.lons/3600.0); + radarDesc->radarLat = (float32) (radar->h.latd + radar->h.latm/60.0 + + radar->h.lats/3600.0); + /* altitude above Mean Sea Level (km) */ + radarDesc->radarAlt = (float32)((float)(radar->h.height) / 1000.0); + /* Effective unambiguous velocity (m/s) Leave blank. See range comments + below. */ +/* + if (radar->v[VR_INDEX] != NULL) + radarDesc->velocity = (float32) + first_ray_in_volume[VR_INDEX]->h.nyq_vel; + else + radarDesc->velocity = (float32)0.0; +*/ + /* Effective unambiguous range (km). Leave blank. For wsr88d, + unambig_range varies with sweep. See range_info_float block. */ +/* + radarDesc->range = (float32) + first_ray_in_volume[vindex]->h.unam_rng; +*/ + /* No. of transmitted freqs */ + radarDesc->numTransfreqency = (int16) 1; +/* radarDesc->numInterPulsePeriods = (int16) 0; */ + /* Freq. GHz. */ + radarDesc->frequency1 = (float32) first_ray_in_volume[vindex]->h.frequency; +} + +/*************************************************************/ +/* */ +/* sensorFill */ +/* */ +/*************************************************************/ +void sensorFill(SENSORS *sensor, Radar *radar, VosSize *vs, int productID) +/* Fill the substructures of the sensor data structure using + data from the radar structure. */ +{ + int pindex, tk_sindex, vindex; + + vindex = nextVolume(radar, -1); /* Find 1st non-NULL rsl volume. */ + + radarDescFill(&sensor->radarDesc, radar, vindex, vs); + sweepInfoFill(sensor->sweepInfo, radar, vs); + rayInfoFill(sensor->rayInfoInteger, sensor->rayInfoFloat, radar, vs); + + /* Move data from each of the radar structure volumes into a + corresponding L1GV parameter structure. */ + if (productID == TK_L1B_GV) + { + for (pindex=0; pindextk.nparm; pindex++) + { + sensor->parm[pindex] = (PARAMETER *)parmBuild(radar, vs, vindex, pindex); + /* Find the next non-NULL volume in radar structure. */ + vindex = nextVolume(radar, vindex); + } /* end for (pindex=0; ... */ + } + else /* 1C-51 */ + { + /* This is a hatchet job to conform with newest toolkit. The toolkit + arbitrarily assumes that the mask volume precedes the corresponding + data volume. + */ + for (pindex=0; pindextk.nparm/2; pindex++) + { + if (vindex == CZ_INDEX) + sensor->parm[pindex] = (PARAMETER *)parmBuild(radar, vs, MZ_INDEX, + pindex); + else if (vindex == CD_INDEX) + sensor->parm[pindex*2] = (PARAMETER *)parmBuild(radar, vs, MD_INDEX, + pindex); + else + continue; + sensor->parm[pindex*2+1] = (PARAMETER *)parmBuild(radar, vs, vindex, + pindex); + /* Find the next non-NULL volume in radar structure. */ + vindex = nextVolume(radar, vindex); + } /* end for (pindex=0... */ + } /* end else 1C-51 */ + + if (radar_verbose_flag) + { + for (pindex=0; pindextk.nparm; pindex++) + { + fprintf(stderr, "Toolkit parameter type : %s '%s'\n", + sensor->parm[pindex]->parmDesc.parmDesc, + sensor->parm[pindex]->parmDesc.parmName); + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + if (vs->tk.ncell[tk_sindex][pindex] == 0) + fprintf(stderr, " tk_sweep[%.2d] elev=%4.1f nrays=%3d cells/ray=%d\n", + tk_sindex, sensor->sweepInfo[tk_sindex].fixedAngle, + (int)0, + vs->tk.ncell[tk_sindex][pindex]); + else + fprintf(stderr, " tk_sweep[%.2d] elev=%4.1f nrays=%3d cells/ray=%d\n", + tk_sindex, sensor->sweepInfo[tk_sindex].fixedAngle, + (int)sensor->sweepInfo[tk_sindex].numRays, + vs->tk.ncell[tk_sindex][pindex]); + } /* end for (pindex=0;... */ + } /* end if (radar_verbose_flag) */ +} + +/*************************************************************/ +/* */ +/* timeUTC */ +/* */ +/*************************************************************/ +struct tm *timeUTC(void) +{ +/* Find the current time (UTC). + If success: return pointer to filled time_t structure. + If failure: return NULL. +*/ + time_t time_current; + + /* Get the current system clock time */ + time_current = (time_t) time(NULL); + if (time_current != -1) /* valid time? */ + return(gmtime(&time_current)); /* Convert to UTC and return. */ + else + return(NULL); /* Couldn't get the current time. */ +} + + +/*************************************************************/ +/* */ +/* volDesFill */ +/* */ +/*************************************************************/ +void volDesFill(VOLUME_DESCRIPTORS *volDes, Radar_header *h, VosSize *vs) +{ + struct tm *time_utc; + int32 max_ncell; + int pindex; + + /* Version no. of DORADE specifications used. Currently 1 */ + volDes->verNum = (int16) 1; + /* No. of this volume scan in granule */ + volDes->volNum = (int16) (vs->vos_num + 1); + /* Max size of DORADE data record in this VOS. 2bytes x max(ncell) */ + max_ncell = 0; + for (pindex=0; pindextk.nparm; pindex++) + if (vs->tk.ncell[0][pindex] > max_ncell) + max_ncell = vs->tk.ncell[0][pindex]; + volDes->sizeDataRec = (int32) (2 * max_ncell); + strncpy(volDes->projectName, "TRMM GV", 20); + volDes->year = (int16) h->year; /* Year of volume scan */ + volDes->month = (int16) h->month; /* Month of volume scan */ + volDes->day = (int16) h->day; /* Day ... */ + volDes->hour = (int16) h->hour; /* Hour ... */ + volDes->minute = (int16) h->minute; /* Minute ... */ + volDes->second = (int16) floor((double)h->sec); /* Second ... */ + /* Flight no. for airborne radar, or IOP no. for ground radar */ + strncpy(volDes->flightNum, "***", 8); + /* Data product generation facility name */ + strncpy(volDes->facName, "TSDIS", 8); + /* Get the current time; ie, the time of creation of this hdf file. */ + time_utc = timeUTC(); + if (time_utc != NULL) /* Valid time? */ + { + volDes->genYear = (int16) (1900 + time_utc->tm_year); + volDes->genMonth = (int16) (time_utc->tm_mon + 1); + volDes->genDay = (int16) time_utc->tm_mday; + } + else /* Couldn't get valid time. */ + { + volDes->genYear = (int16) 0; + volDes->genMonth = (int16) 0; + volDes->genDay = (int16) 0; + } + /* No. of sensor descriptors in this volume scan */ + volDes->numSensorDesc = (int16) 1; /* 1 for ground-based radar */ +} + +/*************************************************************/ +/* */ +/* commentsFill */ +/* */ +/*************************************************************/ +void commentsFill(char *comments, VosSize *vs, Radar *radar, + float *qcParm, int productID) +{ +/* Write the following into the comments field of the gvl1 + structure: + 1. VOS comment_field header line. + 2. cell/ray/sweep count. + 3. 1C-51 QC parameters, if we're writing a 1C-51 HDF file. +*/ + char buf[256]; + int pindex, tk_sindex; + + /* Write out the dimensions of the toolkit structure which contains + this VOS. */ + sprintf(buf, "nSweep=%d\n", vs->tk.nsweep); + strcat(comments, buf); + for (tk_sindex=0; tk_sindextk.nsweep; tk_sindex++) + { + sprintf(buf, "sweep[%.2d]--\n nRay=%d\n", tk_sindex, + vs->tk.nray[tk_sindex]); + strcat(comments, buf); + for (pindex=0; pindextk.nparm; pindex++) + { + sprintf(buf, " nCell_parm[%d]=%d\n", pindex, + vs->tk.ncell[tk_sindex][pindex]); + strcat(comments, buf); + } + strcat(comments, "\n"); + } /* end for (pindex=0 ... */ + + strcat(comments, "********\n"); + /* If 1C-51 file, write out the QC parameters. */ + if (productID == TK_L1C_GV) + { + sprintf(buf, "-hThresh1 %.2f -hThresh2 %.2f -hThresh3 %.2f -zThresh0 %.2f -zThresh1 %.2f -zThresh2 %.2f -zThresh3 %.2f -hFreeze %.2f -dbzNoise %.2f -zCal %.2f\n\n", + qcParm[HTHRESH1], qcParm[HTHRESH2], qcParm[HTHRESH3], + qcParm[ZTHRESH0], qcParm[ZTHRESH1], qcParm[ZTHRESH2], qcParm[ZTHRESH3], + qcParm[HFREEZE], qcParm[DBZNOISE], qcParm[ZCAL]); + strcat(comments, buf); + } /* end if (productID == TK_L1C_GV) */ +} + +/*************************************************************/ +/* */ +/* gvl1Build */ +/* */ +/*************************************************************/ +L1B_1C_GV *gvl1Build(Radar *radar, float *qcParm, VosSize *vs, + int productID) +{ +/* Build the components of the Toolkit 'L1B_1C_GV' structure using + the data from the RSL radar structure. +*/ + L1B_1C_GV *gvl1; + + /* Allocate memory for a TSDIS level_1 structure. */ + gvl1 = (L1B_1C_GV *)TKnewGVL1(); + + /* Fill the structure, using data from the radar structure. */ + commentsFill(gvl1->comments, vs, radar, qcParm, productID); + volDesFill(&gvl1->volDes, &radar->h, vs); + sensorFill(&gvl1->sensor, radar, vs, productID); + return(gvl1); +} + +#endif diff --git a/radar_to_uf.c b/radar_to_uf.c new file mode 100644 index 0000000..6708396 --- /dev/null +++ b/radar_to_uf.c @@ -0,0 +1,539 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include +#include + +#include "rsl.h" +extern int radar_verbose_flag; +/* Missing data flag : -32768 when a signed short. */ +#define UF_NO_DATA 0X8000 + + +/* Any convensions may be observed. */ +/* Typically: + * DZ = Reflectivity (dBZ). + * VR = Radial Velocity. + * SW = Spectrum Width. + * CZ = Corrected Reflectivity. (Quality controlled: AP removed, etc.) + * ZT = Total Reflectivity (dB(mW)). Becomes UZ in UF files. + * DR = Differential Reflectivity. + * LR = Another DR (LDR). + * ZD = Tina Johnson use this one. + * DM = Received power. + * RH = Rho coefficient. + * PH = Phi (MCTEX parameter). + * XZ = X-band reflectivity. + * CD = Corrected ZD. + * MZ = DZ mask for 1C-51 HDF. + * MD = ZD mask for 1C-51 HDF. + * ZE = Edited reflectivity. + * VE = Edited velocity. + * KD = KDP wavelength*deg/km + * TI = TIME (units unknown). + * These fields may appear in any order in the UF file. + */ + +char *UF_field_name[] = {"DZ", "VR", "SW", "CZ", "ZT", "DR", "LR", + "ZD", "DM", "RH", "PH", "XZ", "CD", "MZ", + "MD", "ZE", "VE", "KD", "TI", "DX", "CH", + "AH", "CV", "AV", "SQ" +}; + + +typedef short UF_buffer[16384]; /* Bigger than documented 4096. */ + +void swap_uf_buffer(UF_buffer uf); +void swap2(short *buf, int n); + +/**********************************************************************/ +/* */ +/* RSL_radar_to_uf_fp */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* May 20, 1994 */ +/**********************************************************************/ +void RSL_radar_to_uf_fp(Radar *r, FILE *fp) + +{ + /* + * 1. Fill the UF buffers with data from the Radar structure. + * 2. Write to a stream. Assume open and leave it so. + */ + + + UF_buffer uf; + +/* These are pointers to various locations within the UF buffer 'uf'. + * They are used to index the different components of the UF structure in + * a manor consistant with the UF documentation. For instance, uf_ma[1] + * will be equivalenced to the second word (2 bytes/each) of the UF + * buffer. + */ + short *uf_ma; /* Mandatory header block. */ + short *uf_op; /* Optional header block. */ + short *uf_lu; /* Local Use header block. */ + short *uf_dh; /* Data header. */ + short *uf_fh; /* Field header. */ + short *uf_data; /* Data. */ + +/* The length of each header. */ + int len_ma, len_op, len_lu, len_dh, len_fh, len_data; + +/* Booleans to flag inclusion of headers. */ + int q_op, q_lu, q_dh, q_fh; + + int current_fh_index; + int scale_factor; + int rec_len, save_rec_len; + int nfield; + float vr_az; + + struct tm *tm; + time_t the_time; + + int i,j,k,m; + int degree, minute; + float second; + + +/* Here are the arrays for each field type. Each dimension is the number + * of fields in the radar structure. I do this because the radar organization + * is by volumes (field types) and the UF demands that each ray contain + * all the field types. + */ + Volume **volume; + Sweep **sweep; + Ray *ray; + int *nsweeps; + int nvolumes, maxsweeps, nrays; + int true_nvolumes; + int sweep_num, ray_num, rec_num; + float x; + + if (r == NULL) { + fprintf(stderr, "radar_to_uf_fp: radar pointer NULL\n"); + return; + } + + +/* Do all the headers first time around. Then, prune OP and LU. */ + q_op = q_lu = q_dh = q_fh = 1; + + memset(&uf, 0, sizeof(uf)); /* Init to 0 or NULL for pointers. */ + + sweep_num = ray_num = rec_num = 0; + true_nvolumes = nvolumes = maxsweeps = nrays = 0; + +/* + * The organization of the Radar structure is by volumes, then sweeps, then + * rays, then gates. This is different from the UF file organization. + * The UF format wants sweeps, rays, then gates for all field types (volumes). + * So, we have to do a back flip, here. This is achieved by maintaining + * an array of volume pointers and sweep pointers, each dimensioned by + * 'nvolumes', which contains the data for the different field types; this + * is our innermost loop. The variables are 'volume[i]' and 'sweep[i]' where + * 'i' is the volume index. + * + * In other words, we are getting all the field types together, when we + * are looping on the number of rays in a sweep, so we can load the UF_buffer + * appropriately. + */ + + nvolumes = r->h.nvolumes; + volume = (Volume **) calloc(nvolumes, sizeof(Volume *)); + sweep = (Sweep **) calloc(nvolumes, sizeof(Sweep *)); + nsweeps = (int *) calloc(nvolumes, sizeof(int)); + +/* Get the the number of sweeps in the radar structure. This will be + * the main controlling loop variable. + */ + for (i=0; iv[i]; + if(volume[i]) { + nsweeps[i] = volume[i]->h.nsweeps; + if (nsweeps[i] > maxsweeps) maxsweeps = nsweeps[i]; + true_nvolumes++; + } + } + + if (radar_verbose_flag) { + fprintf(stderr,"True number of volumes for UF is %d\n", true_nvolumes); + fprintf(stderr,"Maximum # of volumes for UF is %d\n", nvolumes); + } +/*-------- + * LOOP for all sweeps (typically 11 or 16 for wsr88d data. + * + */ + for (i=0; isweep[i]; + + /* Check if we really can access this sweep. Paul discovered that + * if the actual number of sweeps is less than the maximum that we + * could be chasing a bad pointer (a NON-NULL garbage pointer). + */ + if (i >= nsweeps[k]) sweep[k] = NULL; + + if (sweep[k]) if (sweep[k]->h.nrays > nrays) nrays = sweep[k]->h.nrays; + } + + sweep_num++; /* I guess it will be ok to count NULL sweeps. */ + ray_num = 0; + if (radar_verbose_flag) + fprintf(stderr,"Processing sweep %d for %d rays.", i, nrays); + if (radar_verbose_flag) + if (little_endian()) fprintf(stderr," ... On Little endian.\n"); + else fprintf(stderr,"\n"); + + +/* Now LOOP for all rays within this particular sweep (i). + * Get all the field types together for the ray, see ray[k], and + * fill the UF data buffer appropriately. + */ + for (j=0; jh.nrays) + if (sweep[k]->ray) + if ((ray = sweep[k]->ray[j])) break; + } + + /* If there is no such ray, then continue on to the next ray. */ + if (ray) { +/* + 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); +*/ + + /* + * ---- Begining of MANDITORY HEADER BLOCK. + */ + uf_ma = uf; + memcpy(&uf_ma[0], "UF", 2); + if (little_endian()) memcpy(&uf_ma[0], "FU", 2); + uf_ma[1] = 0; /* Not known yet. */ + uf_ma[2] = 0; /* Not known yet. Really, I do. */ + uf_ma[3] = 0; /* Not known yet. */ + uf_ma[4] = 0; /* Not known yet. */ + + uf_ma[6] = 1; + uf_ma[7] = ray_num; + uf_ma[8 ] = 1; + uf_ma[9 ] = sweep_num; + memcpy(&uf_ma[10], r->h.radar_name, 8); + if (little_endian()) swap2(&uf_ma[10], 8/2); + memcpy(&uf_ma[14], r->h.name, 8); + if (little_endian()) swap2(&uf_ma[14], 8/2); + /* Convert decimal lat/lon to d:m:s */ + + if (ray->h.lat != 0.0) { + degree = (int)ray->h.lat; + minute = (int)((ray->h.lat - degree) * 60); + second = (ray->h.lat - degree - minute/60.0) * 3600.0; + } else { + degree = r->h.latd; + minute = r->h.latm; + second = r->h.lats; + } + uf_ma[18] = degree; + uf_ma[19] = minute; + if (second > 0.0) uf_ma[20] = second*64 + 0.5; + else uf_ma[20] = second*64 - 0.5; + + if (ray->h.lon != 0.0) { + degree = (int)ray->h.lon; + minute = (int)((ray->h.lon - degree) * 60); + second = (ray->h.lon - degree - minute/60.0) * 3600.0; + } else { + degree = r->h.lond; + minute = r->h.lonm; + second = r->h.lons; + } + uf_ma[21] = degree; + uf_ma[22] = minute; + if (second > 0.0) uf_ma[23] = second*64 + 0.5; + else uf_ma[23] = second*64 - 0.5; + if (ray->h.alt != 0) + uf_ma[24] = ray->h.alt; + else + uf_ma[24] = r->h.height; + + uf_ma[25] = ray->h.year % 100; /* By definition: not year 2000 compliant. */ + uf_ma[26] = ray->h.month; + uf_ma[27] = ray->h.day; + uf_ma[28] = ray->h.hour; + uf_ma[29] = ray->h.minute; + uf_ma[30] = ray->h.sec; + memcpy(&uf_ma[31], "UT", 2); + if (little_endian()) memcpy(&uf_ma[31], "TU", 2); + if (ray->h.azimuth > 0) uf_ma[32] = ray->h.azimuth*64 + 0.5; + else uf_ma[32] = ray->h.azimuth*64 - 0.5; + uf_ma[33] = ray->h.elev*64 + 0.5; + uf_ma[34] = 1; /* Sweep mode: PPI = 1 */ + if (ray->h.fix_angle != 0.) + uf_ma[35] = ray->h.fix_angle*64.0 + 0.5; + else uf_ma[35] = sweep[k]->h.elev*64.0 + 0.5; + uf_ma[36] = ray->h.sweep_rate*(360.0/60.0)*64.0 + 0.5; + + the_time = time(NULL); + tm = gmtime(&the_time); + + uf_ma[37] = tm->tm_year % 100; /* Same format as data year */ + uf_ma[38] = tm->tm_mon+1; + uf_ma[39] = tm->tm_mday; + memcpy(&uf_ma[40], "RSL" RSL_VERSION_STR, 8); + if (little_endian()) swap2(&uf_ma[40], 8/2); + uf_ma[44] = (signed short)UF_NO_DATA; + len_ma = 45; + uf_ma[2] = len_ma+1; + /* + * ---- End of MANDITORY HEADER BLOCK. + */ + + /* ---- Begining of OPTIONAL HEADER BLOCK. */ + len_op = 0; + if (q_op) { + q_op = 0; /* Only once. */ + uf_op = uf+len_ma; + memcpy(&uf_op[0], "TRMMGVUF", 8); + if (little_endian()) swap2(&uf_op[0], 8/2); + uf_op[4] = (signed short)UF_NO_DATA; + uf_op[5] = (signed short)UF_NO_DATA; + uf_op[6] = ray->h.hour; + uf_op[7] = ray->h.minute; + uf_op[8] = ray->h.sec; + memcpy(&uf_op[9], "RADAR_UF", 8); + if (little_endian()) swap2(&uf_op[9], 8/2); + uf_op[13] = 2; + len_op = 14; + } + /* ---- End of OPTIONAL HEADER BLOCK. */ + + /* ---- Begining of LOCAL USE HEADER BLOCK. */ + /* If we have DZ and VR, check to see if their azimuths are + * different. If they are, we store VR azimuth in Local Use + * Header. These differences occur with WSR-88D radars, which + * run separate sweeps for DZ and VR at low elevations. + */ + q_lu = 0; + if (sweep[DZ_INDEX] && sweep[VR_INDEX]) { + if (sweep[DZ_INDEX]->ray[j] && sweep[VR_INDEX]->ray[j]) { + vr_az = sweep[VR_INDEX]->ray[j]->h.azimuth; + if (sweep[DZ_INDEX]->ray[j]->h.azimuth != vr_az) + q_lu = 1; /* Set to use Local Use Header block. */ + } + } + len_lu = 0; + if (q_lu) { + /* Store azimuth for WSR-88D VR ray in Local Use Header. */ + uf_lu = uf+len_ma+len_op; + memcpy(&uf_lu[0], "AZ", 2); + if (little_endian()) memcpy(&uf_lu[0], "ZA", 2); + if (vr_az > 0) uf_lu[1] = vr_az*64 + 0.5; + else uf_lu[1] = vr_az*64 - 0.5; + len_lu = 2; + } + /* ---- End of LOCAL USE HEADER BLOCK. */ + + + /* Here is where we loop on each field type. We need to keep + * track of how many FIELD HEADER and FIELD DATA sections, one + * for each field type, we fill. The variable that tracks this + * index into 'uf' is 'current_fh_index'. It is bumped by + * the length of the FIELD HEADER and FIELD DATA for each field + * type encountered. Field types expected are: Reflectivity, + * Velocity, and Spectrum width; this is a typicial list but it + * is not restricted to it. + */ + + for (k=0; kray) + ray = sweep[k]->ray[j]; + else + ray = NULL; + else ray = NULL; + + if (k >= sizeof(UF_field_name)) { + ray = NULL; + fprintf(stderr,"RSL_uf_to_radar: Unknown field type encountered.\n"); + fprintf(stderr,"The field type index in Radar exceeds the number of known UF field types.\n"); + } + + if (ray) { + /* ---- Begining of DATA HEADER. */ + nfield++; + if (q_dh) { + len_dh = 2*true_nvolumes + 3; + uf_dh = uf+len_ma+len_op+len_lu; + uf_dh[0] = nfield; + uf_dh[1] = 1; + uf_dh[2] = nfield; + /* 'nfield' indexes the field number. + * 'k' indexes the particular field from the volume. + */ + memcpy(&uf_dh[3+2*(nfield-1)], UF_field_name[k], 2); + if (little_endian()) swap2(&uf_dh[3+2*(nfield-1)], 2/2); + if (current_fh_index == 0) current_fh_index = len_ma+len_op+len_lu+len_dh; + uf_dh[4+2*(nfield-1)] = current_fh_index + 1; + } + /* ---- End of DATA HEADER. */ + + /* ---- Begining of FIELD HEADER. */ + if (q_fh) { + uf_fh = uf+current_fh_index; + uf_fh[1] = scale_factor = 100; + uf_fh[2] = ray->h.range_bin1/1000.0; + uf_fh[3] = ray->h.range_bin1 - (1000*uf_fh[2]); + uf_fh[4] = ray->h.gate_size; + uf_fh[5] = ray->h.nbins; + uf_fh[6] = ray->h.pulse_width*(RSL_SPEED_OF_LIGHT/1.0e6); + uf_fh[7] = sweep[k]->h.beam_width*64.0 + 0.5; + uf_fh[8] = sweep[k]->h.beam_width*64.0 + 0.5; + uf_fh[9] = ray->h.frequency*64.0 + 0.5; /* Bandwidth (mHz). */ + uf_fh[10] = 0; /* Horizontal polarization. */ + uf_fh[11] = ray->h.wavelength*64.0*100.0; /* m to cm. */ + uf_fh[12] = ray->h.pulse_count; + memcpy(&uf_fh[13], " ", 2); + uf_fh[14] = (signed short)UF_NO_DATA; + uf_fh[15] = (signed short)UF_NO_DATA; + if (k == DZ_INDEX || k == ZT_INDEX) { + uf_fh[16] = volume[k]->h.calibr_const*100.0 + 0.5; + } + else { + memcpy(&uf_fh[16], " ", 2); + } + if (ray->h.prf != 0) + uf_fh[17] = 1.0/ray->h.prf*1000000.0; /* Pulse repetition time(msec) = 1/prf */ + else + uf_fh[17] = (signed short)UF_NO_DATA; /* Pulse repetition time = 1/prf */ + uf_fh[18] = 16; + if (VR_INDEX == k || VE_INDEX == k) { + uf_fh[19] = scale_factor*ray->h.nyq_vel; + uf_fh[20] = 1; + len_fh = 21; + } else { + len_fh = 19; + } + + uf_fh[0] = current_fh_index + len_fh + 1; + /* ---- End of FIELD HEADER. */ + + /* ---- Begining of FIELD DATA. */ + uf_data = uf+len_fh+current_fh_index; + len_data = ray->h.nbins; + for (m=0; mh.f(ray->range[m]); + if (x == BADVAL || x == RFVAL || x == APFLAG || x == NOECHO) + uf_data[m] = (signed short)UF_NO_DATA; + else + uf_data[m] = scale_factor * x; + } + + current_fh_index += (len_fh+len_data); + } + } + /* ---- End of FIELD DATA. */ + } + /* Fill in some infomation we didn't know. Like, buffer length, + * record number, etc. + */ + rec_num++; + uf_ma[1] = current_fh_index; + uf_ma[3] = len_ma + len_op + 1; + uf_ma[4] = len_ma + len_op + len_lu + 1; + uf_ma[5] = rec_num; + + /* WRITE the UF buffer. */ + rec_len =(int)uf_ma[1]*2; + save_rec_len = rec_len; /* We destroy 'rec_len' when making it + big endian on a little endian machine. */ + if (little_endian()) swap_4_bytes(&rec_len); + (void)fwrite(&rec_len, sizeof(int), 1, fp); + if (little_endian()) swap_uf_buffer(uf); + (void)fwrite(uf, sizeof(char), save_rec_len, fp); + (void)fwrite(&rec_len, sizeof(int), 1, fp); + } /* if (ray) */ + } + } +} + +/**********************************************************************/ +/* */ +/* RSL_radar_to_uf */ +/* */ +/**********************************************************************/ +void RSL_radar_to_uf(Radar *r, char *outfile) +{ + FILE *fp; + if (r == NULL) { + fprintf(stderr, "radar_to_uf: radar pointer NULL\n"); + return; + } + + if ((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + return; + } + + RSL_radar_to_uf_fp(r, fp); + fclose(fp); +} + +/**********************************************************************/ +/* */ +/* RSL_radar_to_uf_gzip */ +/* */ +/**********************************************************************/ +void RSL_radar_to_uf_gzip(Radar *r, char *outfile) +{ + FILE *fp; + if (r == NULL) { + fprintf(stderr, "radar_to_uf_gzip: radar pointer NULL\n"); + return; + } + + if ((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + return; + } + + fp = compress_pipe(fp); + RSL_radar_to_uf_fp(r, fp); + rsl_pclose(fp); +} diff --git a/radtec.c b/radtec.c new file mode 100644 index 0000000..366bbce --- /dev/null +++ b/radtec.c @@ -0,0 +1,300 @@ +/* + * General RADTEC ingest code. + * + * By John H. Merritt + * + * May 21, 1998 + */ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1998 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBIMPLODE +#include +#include +#include "radtec.h" +#include + +static int nray_headers_expected = 0; +static int nrays_expected = 0; +Radtec_ray_header *ray_header_array; +Radtec_ray *ray_array; + +void radtec_print_header(Radtec_header *h) +{ + printf("version = %d\n", h->version); + printf("scan_type = %d\n", h->scan_type); + printf("scan_mode = %d\n", h->scan_mode); + printf("seqno = %d\n", h->seqno); + printf("month = %d\n", h->month); + printf("day = %d\n", h->day); + printf("year = %d\n", h->year); + printf("hour = %d\n", h->hour); + printf("min = %d\n", h->min); + printf("sec = %d\n", h->sec); + printf("az_el = %f\n", h->az_el); + printf("azim_resolution = %f\n", h->azim_resolution); + printf("azim_offset = %f\n", h->azim_offset); + printf("elev_resolution = %f\n", h->elev_resolution); + printf("elev_offset = %f\n", h->elev_offset); + printf("site_elevation = %f\n", h->site_elevation); + printf("site_latitude = %f\n", h->site_latitude); + printf("site_longitude = %f\n", h->site_longitude); + printf("skip = %f\n", h->skip); + printf("range_bin_size = %f\n", h->range_bin_size); + printf("num_range_bins = %d\n", h->num_range_bins); + printf("num_integrations = %d\n", h->num_integrations); + printf("num_rays = %d\n", h->num_rays); +} + +void radtec_print_ray_header(Radtec_ray_header *h) +{ + fprintf(stderr, "ray_num = %d\n", h->ray_num); + fprintf(stderr, "azim_angle = %f\n", h->azim_angle); + fprintf(stderr, "elev_angle = %f\n", h->elev_angle); + fprintf(stderr, "hour = %d\n", h->hour); + fprintf(stderr, "min = %d\n", h->min); + fprintf(stderr, "sec = %d\n", h->sec); + fprintf(stderr, "\n"); +} + +struct PassedParam +{ + unsigned int CmpPhase; + FILE *InFile; + FILE *OutFile; + unsigned long CRC; +}; + +/*------------------------------------------------------------------- + Routine to supply data to the implode() or explode() routines. + When this routine returns 0 bytes read, the implode() or explode() + routines will terminate. Also calculate the CRC-32 on the original + uncompressed data during the implode() call. +*/ + +#define explode _explode +#define implode _implode +#define crc32 _crc32 + +int total_bytes_read = 0; +int total_bytes_written = 0; +unsigned int ReadFile(char *Buff, unsigned int *Size, void *Param) +{ + size_t Read; + struct PassedParam *Par = (struct PassedParam *)Param; + + Read = fread(Buff, 1, *Size, Par->InFile); + total_bytes_read += *Size; + if (Par->CmpPhase) + Par->CRC = crc32(Buff, (unsigned int *)&Read, &Par->CRC); + + return (unsigned int)Read; +} + +/*------------------------------------------------------------------- + Routine to write compressed data output from implode() or + uncompressed data from explode(). Also calculate the CRC on + the uncompressed data during the explode() call. +*/ + +void radtec_load_rsl_ray_data(char *Buff, unsigned int *Size, void *Param) +{ + struct PassedParam *Par = (struct PassedParam *)Param; + Radtec_ray_header ray_header; + static int i = 0; + static int nray_headers_seen = 0; + static int nrays_seen = 0; + int ray_size; + static int bytes_remaining = 0; + + + /* fwrite(Buff, 1, *Size, Par->OutFile); */ + /* Buff -- Contains the data. + * *Size -- Contains the length of data. + * Par -- Contains CRC, and FILE* information. + */ + + if (!Par->CmpPhase) + Par->CRC = crc32(Buff, Size, &Par->CRC); + total_bytes_written += *Size; + + while(i<*Size && nray_headers_seen < nray_headers_expected) { + /* Because of word alignment problems, use this painful memcpy approach. */ + memcpy(&ray_header.ray_num, &Buff[i], sizeof(short)); i+=sizeof(short); + memcpy(&ray_header.azim_angle, &Buff[i], sizeof(float)); i+=sizeof(float); + memcpy(&ray_header.elev_angle, &Buff[i], sizeof(float)); i+=sizeof(float); + memcpy(&ray_header.hour, &Buff[i], sizeof(short)); i+=sizeof(short); + memcpy(&ray_header.min, &Buff[i], sizeof(short)); i+=sizeof(short); + memcpy(&ray_header.sec, &Buff[i], sizeof(short)); i+=sizeof(short); + i+=4; /* Fill to 20 bytes. */ +#define RSL_DEBUG +#undef RSL_DEBUG +#ifdef RSL_DEBUG + radtec_print_ray_header(&ray_header); +#endif + ray_header_array[nray_headers_seen] = ray_header; + nray_headers_seen++; + } + /* Ok, whenever 'i' exceeds *Size, we must return to the explode routine + * so that we get another buffer 'Buff'. This new 'Buff' will pick + * up where explode left off, and therefore, we must also pick up where + * we left off. + */ + if (i >= *Size) { + i = 0; +#ifdef RSL_DEBUG + fprintf(stderr, "Need another Buff for ray headers.\n"); +#endif + return; + } + + /* Getting to this point means that i < *Size and we have seen + * all the expected number of ray headers. Now, we must collect + * the expected number of rays (the data). + */ + + ray_size = sizeof(Radtec_ray); + while(i<*Size && nrays_seen < nrays_expected) { +#ifdef RSL_DEBUG + fprintf(stderr, "WHILE i=%d, i+ray_size=%d\n", i, i+ray_size); +#endif + if (i+ray_size > *Size) { /* Possible over flow. */ + /* Load what we can. */ + memcpy(&ray_array[nrays_seen].dbz, &Buff[i], *Size-i); + bytes_remaining = ray_size - *Size + i; +#ifdef RSL_DEBUG + fprintf(stderr, "Buffer overflow : i=%d ray_size=%d loading %d bytes_remaining=%d\n", + i, ray_size, *Size-i, bytes_remaining); +#endif + i=*Size; + break; + } else { + if (bytes_remaining > 0) { +#ifdef RSL_DEBUG + fprintf(stderr,"Load remaining: i=%d ray_size=%d bytes_remaining=%d\n", + i, ray_size, bytes_remaining); +#endif + memcpy(&ray_array[nrays_seen].dbz[(ray_size-bytes_remaining)/4], &Buff[i], bytes_remaining); + i+=bytes_remaining; + bytes_remaining = 0; + } else { +#ifdef RSL_DEBUG + fprintf(stderr, "Load full buff: i=%d ray_size=%d bytes_remaining=%d\n", + i, ray_size, bytes_remaining); +#endif + memcpy(&ray_array[nrays_seen].dbz, &Buff[i], ray_size); + i+=ray_size; + } + } + ray_array[nrays_seen].h = &ray_header_array[nrays_seen]; + nrays_seen++; +#ifdef RSL_DEBUG + fprintf(stderr, "Ray data # %d, sizeof(Radtec_ray)=%d, i=%d\n", nrays_seen, sizeof(Radtec_ray), i); +#endif + } + + if (i >= *Size) { + i = 0; +#ifdef RSL_DEBUG + fprintf(stderr, "Need another Buff for ray data. i=%d *Size=%d\n", i, *Size); +#endif + return; + } + + +} + +Radtec_file *radtec_read_file(char *infile) +{ + FILE *fp; + Radtec_file *rfile; + + char *WorkBuff; /* buffer for compression tables */ + unsigned int Error; + struct PassedParam Param; /* Parameters passed to callback functions */ + + + if (infile == NULL) { + fp = stdin; + } else { + if((fp = fopen(infile, "r")) == NULL) { + perror(infile); + return NULL; + } + } + + rfile = (Radtec_file *)calloc(1, sizeof(Radtec_file)); + if (rfile == NULL) { perror("calloc Radtec_file"); return NULL; } + fread(&rfile->h, sizeof(Radtec_header), 1, fp); + + /* Initialize the global for the unpacking routine. The unpacking + * routine is a callback for 'explode'; the second argument. + */ + nray_headers_expected = rfile->h.num_rays; + nrays_expected = rfile->h.num_rays; + + /* Allocate space for all the headers and rays expected. */ + ray_header_array = (Radtec_ray_header *)calloc(rfile->h.num_rays, sizeof(Radtec_ray_header)); + if (ray_header_array == NULL) { perror("calloc Radtec_ray_header"); return NULL; } + ray_array = (Radtec_ray *)calloc(rfile->h.num_rays, sizeof(Radtec_ray)); + if (ray_array == NULL) { perror("calloc Radtec_ray"); return NULL; } + + /* -------------- PKWARE ----------- */ + WorkBuff = (char *)malloc(EXP_BUFFER_SIZE); + if (WorkBuff == NULL) { + perror("RADETC, unable to allocate work buffer."); + return NULL; + } + + Param.InFile = fp; + Param.OutFile = NULL; + + /* Initialize CRC */ + Param.CmpPhase = 0; + Param.CRC = (unsigned long) -1; + + Error = explode(ReadFile, radtec_load_rsl_ray_data, WorkBuff, &Param); + + Param.CRC = ~Param.CRC; + free(WorkBuff); + fclose(Param.InFile); + fclose(Param.OutFile); + if (Error != 0) { + fprintf(stderr, "RADTEC: uncompression completed - Error %d\n", Error); + fprintf(stderr, "RADTEC: Total bytes read = %d\n", total_bytes_read); + fprintf(stderr, "RADTEC: Total bytes written = %d\n", total_bytes_written); + } + /* -------------- PKWARE ----------- */ + rfile->ray = ray_array; + + return rfile; +} + +void radtec_free_file(Radtec_file *rfile) +{ + free(rfile->ray); + free(rfile); +} +#endif diff --git a/radtec.h b/radtec.h new file mode 100644 index 0000000..9890af1 --- /dev/null +++ b/radtec.h @@ -0,0 +1,138 @@ +/* + * RADTEC Version 3.20 data structures. + * + * By John H. Merritt + * + * May 21, 1998 + */ +/* + + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1998 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +/* + * An integer word in RADTEC is 16 bits, however, floats and doubles + * are 32 and 64 bits respectively. + */ + +typedef struct { + double rcvr_slope; + short isolation; + short noise_level; + short counts_hi; + short counts_lo; + short power_hi; + short power_lo; +} Video_calibration; /* 16 bytes */ + +typedef struct { + short average_power; + short reference_range; + double zconstant; + double zcorrection; +} Radar_calibration; /* 20 bytes */ + +typedef struct { + Video_calibration video_cal; + Radar_calibration radar_cal; +} Log_video_transmitter; /* 36 bytes */ + +typedef Log_video_transmitter Doppler_transmitter; + +typedef struct { + short doppler_velocity_range; /* 0=0-16, 1=0-32 */ + short ground_clutter_filter_status; + short adtnl_log_gc_filter_status; + short adtnl_lin_gc_filter_status; +} Model_info; + +typedef struct { + short version; /* Version number multiplied by 100. 320 means 3.20 */ + short scan_type; /* 1=PPI, 2=RHI */ + short scan_mode; /* Recording mode. 0=Log Video, 1=Doppler */ + short seqno; /* Sequence number of this data file. */ + short month; /* 1-12 */ + short day; /* 1-31 */ + short year; /* YYYY */ + short hour; /* 0-23 */ + short min; /* 0-59 */ + short sec; /* 0-59 */ + float az_el; /* RHI azimuth or PPI elevation in degrees. */ + double azim_resolution; + double azim_offset; + double elev_resolution; + double elev_offset; + double site_elevation; + double site_latitude; + double site_longitude; + float skip; /* In microseconds, 1-1024. */ + float range_bin_size; /* In microseconds, 1-1024. */ + short num_range_bins; /* 16-240. */ + short num_integrations; /* # of integrations comprising each ray. 1-1024. */ + short num_rays; /* Number of rays. */ + Log_video_transmitter log_video; + Doppler_transmitter doppler; + short model; /* Processor model. 0=none, 1=750, 2=940, 3=950. */ + Model_info model_info; + char spare[12]; /* Fill to 200 bytes. */ +} Radtec_header; + +typedef struct { + short ray_num; /* Ray number. 0-n */ + float azim_angle; /* Azimuth angle in degrees. */ + float elev_angle; /* Elevation angle in degrees. */ + short hour; /* 0-23 */ + short min; /* 0-59 */ + short sec; /* 0-59 */ +} Radtec_ray_header; + +typedef float Radtec_dbz[240]; +typedef struct { + Radtec_ray_header *h; /* May be set during reading of data. Can + * be safely ignored. However, you'd have + * to maintain two arrays -- headers and rays. + */ + Radtec_dbz dbz; +} Radtec_ray; + + +typedef struct { + Radtec_header h; + Radtec_ray *ray; +} Radtec_file; + +void radtec_free_file(Radtec_file *rfile); +Radtec_file *radtec_read_file(char *infile); +void radtec_print_header(Radtec_header *h); +void radtec_print_ray_header(Radtec_ray_header *h); + + unsigned int _explode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param); + + unsigned long _crc32( + char *buffer, + unsigned int *size, + unsigned long *old_crc); diff --git a/radtec_to_radar.c b/radtec_to_radar.c new file mode 100644 index 0000000..59cf5fe --- /dev/null +++ b/radtec_to_radar.c @@ -0,0 +1,216 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997, 1998 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include "rsl.h" + +#ifdef HAVE_LIBIMPLODE +#include "radtec.h" + +extern int radar_verbose_flag; + +static void fill_ray_header(Ray_header *h, Radtec_header *rh, Radtec_ray_header *rrh) +{ + + /* Fill the limited ray header information. */ + h->month = rh->month; /* Time for this ray; month (1-12). */ + h->day = rh->day; /* Time for this ray; day (1-31). */ + h->year = rh->year; /* Time for this ray; year (eg. 1993). */ + h->hour = rrh->hour; /* Date for this ray; hour (0-23). */ + h->minute = rrh->min;/* Date for this ray; minute (0-59).*/ + h->sec = rrh->sec; /* Date for this ray; second + fraction of second. */ + h->azimuth = rrh->azim_angle; /* Azimuth angle. (degrees). Must be positive + * 0=North, 90=east, -90/270=west. + * This angle is the mean azimuth for the whole ray. + * Eg. for NSIG the beginning and end azimuths are + * averaged. + */ + h->ray_num = rrh->ray_num; /* Ray no. within elevation scan. */ + h->elev = rrh->elev_angle; /* Elevation angle. (degrees). */ + + h->gate_size = rh->range_bin_size * RSL_SPEED_OF_LIGHT / 1e6; /* Data gate size (meters)*/ + h->lat = rh->site_latitude; /* Latitude (degrees) */ + h->lon = rh->site_longitude; /* Longitude (degrees) */ + h->alt = rh->site_elevation; /* Altitude (m) */ + h->nbins = rh->num_range_bins; /* Number of array elements for 'Range'. */ + h->beam_width = rh->azim_resolution; /* Beamwidth in degrees. */ + +#ifdef RADTEC_UNKNOWN + h->unam_rng = 0; /* Unambiguous range. (KM). */ + h->elev_num = 0; /* Elevation no. within volume scan. */ + h->range_bin1 = 0; /* Range to first gate.(meters) */ + h-> vel_res = 0; /* Doppler velocity resolution */ + h->sweep_rate = 0; /* Sweep rate. Full sweeps/min. */ + h->prf = 0; /* Pulse repetition frequency, in Hz. */ + h->azim_rate; /* degrees/sec */ + h->fix_angle; + h->pitch; /* Pitch angle. */ + h->roll; /* Roll angle. */ + h->heading; /* Heading. */ + h->pitch_rate; /* (angle/sec) */ + h->roll_rate; /* (angle/sec) */ + h->heading_rate; /* (angle/sec) */ + h->rvc; /* Radial velocity correction (m/sec) */ + h->vel_east; /* Platform velocity to the east (m/sec) */ + h->vel_north; /* Platform velocity to the north (m/sec) */ + h->vel_up; /* Platform velocity toward up (m/sec) */ + h->pulse_count; /* Pulses used in a single dwell time. */ + h->pulse_width; /* Pulse width (micro-sec). */ + h->frequency; /* Carrier freq. GHz. */ + h->wavelength; /* Wavelength. Meters. */ + h->nyq_vel; /* Nyquist velocity. m/s */ +#endif + + return; +} + + +Radar *RSL_radtec_to_radar(char *infile) +{ + Radar *radar; + Volume *volume; + Sweep *sweep; + Ray *ray; + float (*f)(Range x); /* Data conversion function. f(x). */ + Range (*invf)(float x); /* Data conversion function. invf(x). */ + + Radtec_file *rfile; + float tmp; + int nsweeps, nrays, nbins; + int isweep, iray, ibin; + float sum_elev; + + rfile = radtec_read_file(infile); + + if (radar_verbose_flag) { + radtec_print_header(&rfile->h); + } + + /* Have the entire radtec file; headers and data. + * Initialize the RSL radar and load it up. + * + * Handles both RHI and PPI scan types. + */ + + /* Only one field type per file. */ + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + + if (rfile->h.scan_type == 1) { /* PPI */ + nrays = (int)(360.0 / rfile->h.azim_resolution + 0.5); + nsweeps = (int)(rfile->h.num_rays / nrays + 0.5); + } else { /* RHI */ + nrays = 1; + nsweeps = (int)(rfile->h.num_rays / nrays + 0.5); + /* Each sweep will contain one ray for RHI scans. */ + } + nbins = rfile->h.num_range_bins; + + if (radar_verbose_flag) { + fprintf(stderr,"Expecting %d sweeps.\n", nsweeps); + fprintf(stderr,"Expecting %d rays.\n", nrays); + fprintf(stderr,"Expecting %d bins.\n", nbins); + } + + if (rfile->h.scan_mode == 0) { /* Log video == Reflectivity. */ + f = DZ_F; + invf = DZ_INVF; + volume = radar->v[DZ_INDEX] = RSL_new_volume(nsweeps); + volume->h.type_str = strdup("Reflectivity"); + } else { /* Doppler */ + f = VR_F; + invf = VR_INVF; + volume = radar->v[VR_INDEX] = RSL_new_volume(nsweeps); + volume->h.type_str = strdup("Velocity"); + } + volume->h.f = f; + volume->h.invf = invf; + + /* Load the radar header information. */ + radar->h.month = rfile->h.month; + radar->h.day = rfile->h.day; + radar->h.year = rfile->h.year; + radar->h.hour = rfile->h.hour; + radar->h.minute = rfile->h.min; + radar->h.sec = rfile->h.sec; /* Second plus fractional part. */ + sprintf(radar->h.radar_type,"radtec"); + + radar->h.number = rfile->h.version; /* arbitrary number of this radar site */ + sprintf(radar->h.name,"radtec"); /* Nexrad site name */ + sprintf(radar->h.radar_name,"RADTEC"); /* Radar name. */ + sprintf(radar->h.city,"Unknown"); /* nearest city to radar site */ + sprintf(radar->h.state,"??"); /* state of radar site */ + sprintf(radar->h.country,"???"); + + /** Latitude deg, min, sec **/ + radar->h.latd = (int)rfile->h.site_latitude; + tmp = (rfile->h.site_latitude - radar->h.latd) * 60.0; + radar->h.latm = (int)tmp; + radar->h.lats = (int)((tmp - radar->h.latm) * 60.0); + /** Longitude deg, min, sec **/ + radar->h.lond = (int)rfile->h.site_longitude; + tmp = (rfile->h.site_longitude - radar->h.lond) * 60.0; + radar->h.lonm = (int)tmp; + radar->h.lons = (int)((tmp - radar->h.lonm) * 60.0); + radar->h.height = rfile->h.site_elevation; /* height of site in meters above sea level*/ + radar->h.spulse = 0; /* length of short pulse (ns)*/ + radar->h.lpulse = 0; /* length of long pulse (ns) */ + + /* Loop through the RSL number of sweeps and attach the data. */ + for (isweep = 0; isweep < nsweeps; isweep++) { + sweep = volume->sweep[isweep] = RSL_new_sweep(nrays); + sweep->h.f = f; + sweep->h.invf = invf; + sum_elev = 0; + for (iray = 0; iray < nrays; iray++) { + ray = sweep->ray[iray] = RSL_new_ray(nbins); + ray->h.f = f; + ray->h.invf = invf; + fill_ray_header(&ray->h, &rfile->h, rfile->ray[iray].h); + RSL_fix_time(ray); + sum_elev += ray->h.elev; + /* Fill the data. */ + for (ibin=0; ibin < nbins; ibin++) { + /* printf ("ray[%d].dbz[%d] = %f\n", iray, ibin, rfile->ray[iray].dbz[ibin]); */ + ray->range[ibin] = invf(rfile->ray[iray].dbz[ibin]); + } + } + sweep->h.elev = sum_elev / nrays; + sweep->h.beam_width = rfile->h.azim_resolution; /* This is in the ray header too. */ + sweep->h.vert_half_bw = sweep->h.beam_width/2; /* Vertical beam width divided by 2 */ + sweep->h.horz_half_bw = sweep->h.beam_width/2; /* Horizontal beam width divided by 2 */ + } + + radtec_free_file(rfile); + rfile = NULL; + + return radar; +} +#else +Radar *RSL_radtec_to_radar(char *infile) +{ + fprintf(stderr, "RADTEC is not installed in this version of RSL.\n"); + fprintf(stderr, "The library libimplode.a (or .so) was not found during\n"); + fprintf(stderr, "the RSL configuration.\n"); + return NULL; +} +#endif diff --git a/rainbow.c b/rainbow.c new file mode 100644 index 0000000..e8cedc1 --- /dev/null +++ b/rainbow.c @@ -0,0 +1,286 @@ +/* + NASA/TRMM, Code 912 + This is the TRMM Office Radar Software Library. + Copyright (C) 2004 + Bart Kelley + George Mason University + Fairfax, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include "rsl.h" +#include "rainbow.h" + +static int get_param_int(char *buf) +{ + /* Returns an integer parameter from a header line. */ + + int value; + char *substr; + + substr = index(buf, ':'); + sscanf(substr, ": %d", &value); + return value; +} + +static float get_param_float(char *buf) +{ + /* Returns a floating point parameter from a header line. */ + + float value; + char *substr; + + substr = index(buf, ':'); + sscanf(substr, ": %f", &value); + return value; +} + + +static char *get_param_string(char *buf) +{ + /* Returns a string parameter from a header line. */ + + static char string[20]; + char *substr; + + substr = index(buf, ':'); + sscanf(substr, ": %s", string); + return string; +} + +void A_label(Rainbow_hdr *rainbow_header, char* buf) +{ + int labelnum; + char label; + + sscanf(buf, "%c%d", &label, &labelnum); + + if (labelnum == 3) + rainbow_header->az_step = get_param_float(buf); + else if (labelnum == 9) + rainbow_header->nsweeps = get_param_int(buf); +} + +void F_label(Rainbow_hdr *rainbow_header, char* buf) +{ + int labelnum, day, month, year, sec, minute, hour; + float lat, lon; + + sscanf(buf, "%*c%d", &labelnum); + + switch (labelnum) { + case 3: + rainbow_header->compressed = get_param_int(buf); + break; + case 4: + sscanf(buf, "%*c%*d : %f %f", &lon, &lat); + rainbow_header->lon = lon; + rainbow_header->lat = lat; + break; + case 5: + sscanf(buf, "%*c%*d : %d %d %d", &day, &month, &year); + rainbow_header->month = month; + rainbow_header->day = day; + rainbow_header->year = year; + break; + case 6: + sscanf(buf, "%*c%*d : %d %d %d", &sec, &minute, &hour); + rainbow_header->hour = hour; + rainbow_header->minute = minute; + rainbow_header->sec = sec; + break; + case 9: + rainbow_header->datatype = get_param_int(buf); + break; + } +} + +void H_label(Rainbow_hdr *rainbow_header, char* buf) +{ + int labelnum; + char label; + + sscanf(buf, "%c%d", &label, &labelnum); + + if (labelnum == 3) + rainbow_header->filetype = get_param_int(buf); + else if (labelnum == 8) + strcpy(rainbow_header->radarname, get_param_string(buf)); +} + +void P_label(Rainbow_hdr *rainbow_header, char* buf) +{ + int labelnum; + char label; + + sscanf(buf, "%c%d", &label, &labelnum); + + if (labelnum == 3) + rainbow_header->range_start= get_param_float(buf); + else if (labelnum == 4) + rainbow_header->range_stop = get_param_float(buf); + else if (labelnum == 5) + rainbow_header->range_step = get_param_float(buf); +} + +void R_label(Rainbow_hdr *rainbow_header, char* buf) +{ + int labelnum; + + sscanf(buf, "%*c%d", &labelnum); + + if (labelnum == 1) + rainbow_header->nbins = get_param_int(buf); + else if (labelnum == 2) + rainbow_header->bin_resolution = get_param_float(buf); + else if (labelnum == 8) + rainbow_header->nvalues = get_param_int(buf); +} + +void W_label(Rainbow_hdr *rainbow_hdr, char* buf) +{ + int labelnum, az_start, az_stop, pw_code, prf_high, prf_low, zdata; + int vdata, wdata, unfolding, cdata, ddata, uzdata; + float elev, az_step, az_rate, range_stop; + char label; + + sscanf(buf, "%*c%d : %f %d %d %f %f %d %d %d %d %d %d %d %f %d %d %d", + &labelnum, &elev, &az_start, &az_stop, &az_step, + &az_rate, &pw_code, &prf_high, &prf_low, &zdata, &vdata, + &wdata, &unfolding, &range_stop, &cdata, &ddata, &uzdata); + + /* Note: Only need to collect parameters 1, 5, 7, 8, and 13 for each + * elevation. Parameters 2, 3, and 4 are fixed at 0, 359, and 1 for volume + * scan. The remaining parameters can be taken once from label number 1 + * (first elevation). Also, don't need az_step; got it from A3. + */ + + if (labelnum == 1) { + rainbow_hdr->az_start = az_start; + rainbow_hdr->az_stop = az_stop; + rainbow_hdr->pulse_width_code = pw_code; + rainbow_hdr->zdata = zdata; + rainbow_hdr->vdata = vdata; + rainbow_hdr->wdata = wdata; + rainbow_hdr->unfolding = unfolding; + rainbow_hdr->cdata = cdata; + rainbow_hdr->ddata = ddata; + rainbow_hdr->uzdata = uzdata; + } + rainbow_hdr->elev_params[labelnum-1] = + (struct elev_params *) malloc(sizeof(struct elev_params)); + rainbow_hdr->elev_params[labelnum-1]->elev_angle = elev; + rainbow_hdr->elev_params[labelnum-1]->az_rate = az_rate; + rainbow_hdr->elev_params[labelnum-1]->prf_high = prf_high; + rainbow_hdr->elev_params[labelnum-1]->prf_low = prf_low; + rainbow_hdr->elev_params[labelnum-1]->maxrange = range_stop; +} + +/**********************************************************/ +/* */ +/* read_hdr_line */ +/* */ +/**********************************************************/ + +static int read_hdr_line(char *buf, int maxchars, FILE *fp) +{ + /* Read a line from the Rainbow file header into character buffer. + * Function returns the first character in buffer (the "label") if + * the line was successfully read, -1 otherwise. + * + * Note: the following control characters (defined in rainbow.h) are used + * in the Rainbow header: + * CR - Carriage Return: end of a line. + * ETB - End of Transmission Block: divides header into sections (we can + * ignore this one.) + * ETX - End of Text: end of header. + */ + + int c = 0; + int badline = 0, i; + + i = 0; + while ((c = getc(fp)) != CR && c != ETX) { + if (c == ETB) { + c = getc(fp); /* Read past both and the */ + if (c == CR) c = getc(fp); /* combination . */ + } + + buf[i++] = c; + + if (i == maxchars) { + badline = 1; + break; + } + } + + if (badline) { + fprintf(stderr,"A header line exceeded buffer size %d.\n",maxchars); + fprintf(stderr,"Did not find end-of-line character 0x%02x.\n",CR); + buf[maxchars - 1] = '\0'; /* Make it a legal string anyway. */ + return -1; + } + + buf[i] = '\0'; + + if (c != ETX) c = (int) buf[0]; + return c; +} + +/**********************************************************/ +/* */ +/* read_rainbow_header */ +/* */ +/**********************************************************/ + +#define BUFSIZE 128 + +void read_rainbow_header(Rainbow_hdr *rainbow_header, FILE *fp) +{ + /* Reads parameters from Rainbow file header into a rainbow header + structure. */ + + char buf[BUFSIZE]; + int label; + + /* Read each line of the header and extract parameters according to the + * label. The label is a single alphabetic character at the beginning + * of the line which indicates a category of parameters. + */ + + while ((label = read_hdr_line(buf, BUFSIZE, fp)) != ETX && label > 0) { + switch (label) { + case 'H': H_label(rainbow_header, buf); + break; + case 'P': P_label(rainbow_header, buf); + break; + case 'W': W_label(rainbow_header, buf); + break; + case 'F': F_label(rainbow_header, buf); + break; + case 'R': R_label(rainbow_header, buf); + break; + case 'A': A_label(rainbow_header, buf); + break; + case 'N': rainbow_header->product = get_param_int(buf); + break; + case 'X': /* X_label(rainbow_header, buf); */ + break; + } + } +} diff --git a/rainbow.h b/rainbow.h new file mode 100644 index 0000000..21fea87 --- /dev/null +++ b/rainbow.h @@ -0,0 +1,61 @@ +/* Control characters used in Rainbow data header */ + +#define SOH 0x01 /* Start of header: first character in Rainbow file. */ +#define ETX 0x03 /* End of text: end of header. */ +#define CR 0x0d /* Carriage return: end of line, same as '\r'. */ +#define ETB 0x17 /* End of transmission block: marks header sections. */ + +/* Other constants */ + +#define SCAN_DATA 2 +#define VOLUME_SCAN 100 + +/* Declarations */ + +struct elev_params { + float elev_angle; + float az_rate; + int prf_high; + int prf_low; + float maxrange; +}; + +typedef struct { + int filetype; + int product; + int datatype; + int compressed; + char radarname[9]; + int month; + int day; + int year; + int hour; + int minute; + int sec; + float lat; /* radar latitude, degrees */ + float lon; /* radar longitude, degrees */ + int nsweeps; + int az_start; /* degrees */ + int az_stop; /* degrees */ + float az_step; /* degrees */ + float range_start; /* km */ + float range_stop; /* km */ + float range_step; /* km */ + int nbins; + float bin_resolution; /* km */ + int nvalues; + int pulse_width_code; + int zdata; + int vdata; + int wdata; + int unfolding; + int cdata; + int ddata; + int uzdata; + struct elev_params *elev_params[20]; +} Rainbow_hdr; + +/* Function prototypes */ + +Radar *RSL_rainbow_to_radar(char *infile); +int rainbow_data_to_radar(Radar *radar, Rainbow_hdr rainbow_hdr, FILE *fp); diff --git a/rainbow_to_radar.c b/rainbow_to_radar.c new file mode 100644 index 0000000..1bf5599 --- /dev/null +++ b/rainbow_to_radar.c @@ -0,0 +1,308 @@ +/* + NASA/TRMM, Code 912 + This is the TRMM Office Radar Software Library. + Copyright (C) 2004 + Bart Kelley + George Mason University + Fairfax, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include "rsl.h" +#include "rainbow.h" + +struct dms { + int deg; + int minute; + int sec; +}; + +struct dms deg_to_dms(float deg) +{ + /* Convert value in degrees to degrees-minutes-seconds. */ + + int sign, ideg, iminute, sec; + float fminute; /* minute with fractional part */ + struct dms dms; + + sign = (deg < 0.) ? -1 : 1; + deg = sign * deg; /* absolute value */ + ideg = deg; /* truncated degree */ + iminute = fminute = (deg - ideg) * 60.; + sec = (fminute - iminute) * 60. + .5; + dms.deg = sign * ideg; + dms.minute = sign * iminute; + dms.sec = sign * sec; + return dms; +} + +static float (*f)(Range x); +static Range (*invf)(float x); + +/**********************************************************/ +/* */ +/* RSL_rainbow_to_radar */ +/* */ +/**********************************************************/ + +Radar *RSL_rainbow_to_radar(char *infile) +{ + /* This function reads the Rainbow format scan data file and returns a + * radar structure. + */ + + Radar *radar; + FILE *fp; + int c; + int nvolumes; + Rainbow_hdr rainbow_hdr; + struct dms latdms, londms; + + /* These next lines allow program to read from a regular file, a + * compressed file, or standard input. I lifted them from RSL_uf_to_radar + * by John Merritt. + */ + + if (infile == NULL) { + int save_fd; + save_fd = dup(0); + fp = fdopen(save_fd, "r"); + } + else if ((fp = fopen(infile, "r")) == NULL) { + perror(infile); + return NULL; + } + fp = uncompress_pipe(fp); /* Transparently gunzip. */ + + /* Read first character and verify file format. */ + + if ((c = fgetc(fp)) != SOH) { + fprintf(stderr,"%s is not a valid Rainbow format file.\n",infile); + return NULL; + } + + /* Read Rainbow file header and check for correct product. */ + + read_rainbow_header(&rainbow_hdr, fp); + + if (rainbow_hdr.filetype != SCAN_DATA ) { + fprintf(stderr,"ERROR: File is not a scan data file.\n"); + fprintf(stderr,"File type number (header label H3) is %d\n", + rainbow_hdr.filetype); + fprintf(stderr,"See Rainbow File Format Document for details on " + "header labels.\n"); + return NULL; + } + if (rainbow_hdr.product != VOLUME_SCAN) { + fprintf(stderr,"WARNING: Product is not volume scan as expected.\n"); + fprintf(stderr,"Header label N is %d, expected %d\n", + rainbow_hdr.product, VOLUME_SCAN); + fprintf(stderr,"See Rainbow File Format Document for details on " + "header labels.\n"); + } + if (rainbow_hdr.compressed) { + fprintf(stderr,"RSL_rainbow_to_radar: Label F3 indicates data " + "compression.\n"); + fprintf(stderr,"This routine can not handle compressed data.\n"); + fprintf(stderr,"See Rainbow File Format Document for details on " + "header labels.\n"); + return NULL; + } + + /* Make radar structure and assign header information. */ + + nvolumes = 1; /* There is only one raw data type in a volume scan file. */ + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + if (radar == NULL) { + perror("RSL_new_radar returned NUL to RSL_rainbow_to_radar"); + return NULL; + } + radar->h.nvolumes = nvolumes; + strcpy(radar->h.radar_name, rainbow_hdr.radarname); + strcpy(radar->h.radar_type, "rainbow"); + radar->h.month = rainbow_hdr.month; + radar->h.day = rainbow_hdr.day; + radar->h.year = rainbow_hdr.year; + radar->h.hour = rainbow_hdr.hour; + radar->h.minute = rainbow_hdr.minute; + radar->h.sec = (float) rainbow_hdr.sec; + latdms = deg_to_dms(rainbow_hdr.lat); + londms = deg_to_dms(rainbow_hdr.lon); + radar->h.latd = latdms.deg; + radar->h.latm = latdms.minute; + radar->h.lats = latdms.sec; + radar->h.lond = londms.deg; + radar->h.lonm = londms.minute; + radar->h.lons = londms.sec; + + /* Read the data portion of the file into the radar structure. */ + + if (rainbow_data_to_radar(radar, rainbow_hdr, fp) < 1) + radar = NULL; + + return radar; +} + +/**********************************************************/ +/* */ +/* rainbow_data_to_radar */ +/* */ +/**********************************************************/ + +int rainbow_data_to_radar(Radar *radar, Rainbow_hdr rainbow_hdr, FILE *fp) +{ + /* Read Rainbow data into the radar structure. Data in the file is stored + * as bytes, where each byte contains the value for one range bin. The + * data is ordered as follows: The first byte corresponds to the first bin + * of the first ray, followed by the remaining bins of that ray, followed + * by the remaining rays of the first sweep. This sequence of bins, rays, + * and sweeps continues for the remainder of sweeps in the volume scan. + */ + + int iray, isweep, nread, nsweeps, nrays, nbins, vol_index; + unsigned char *rainbow_ray; + Volume *v; + Sweep *sweep; + Ray *ray; + int i; + float azim_rate, beam_width, dz, elev_angle, prf, unam_rng; + + beam_width = 1.0; /* for now */ + + switch (rainbow_hdr.datatype) { + /* TODO: Add f and invf for each field */ + case 0: + vol_index = VR_INDEX; + f = VR_F; + invf = VR_INVF; + break; + case 1: + vol_index = DZ_INDEX; + f = DZ_F; + invf = DZ_INVF; + break; + case 2: + vol_index = SW_INDEX; + break; + case 3: + vol_index = ZT_INDEX; + break; + case 5: + vol_index = DR_INDEX; + break; + } + /* TODO: remove the following if-statement once the code for other data + * types has been implemented. Currently only handles reflectivity (DZ). + */ + if (vol_index != DZ_INDEX) { + fprintf(stderr, "RSL_rainbow_to_radar: currently only handles " + "field type DZ\n"); + fprintf(stderr,"Rainbow data type value (label F9) is %d\n", + rainbow_hdr.datatype); + fprintf(stderr,"Corresponding vol_INDEX number is %d\n", vol_index); + return 0; + } + + nsweeps = rainbow_hdr.nsweeps; + nrays = (rainbow_hdr.az_stop - rainbow_hdr.az_start + 1) / + rainbow_hdr.az_step + .5; + nbins = rainbow_hdr.nbins; + if (nrays != 360) { + fprintf(stderr,"WARNING: number of rays computed is not the number " + "expected.\n"); + fprintf(stderr,"Computed = nrays: azstart = %d, az_stop = %d, " + "az_step = %f\n"); + fprintf(stderr,"Expected 360\n"); + } + radar->v[vol_index] = RSL_new_volume(nsweeps); + v = radar->v[vol_index]; + v->h.nsweeps = nsweeps; + v->h.f = f; + v->h.invf = invf; + if (vol_index == DZ_INDEX) v->h.type_str = strdup("Reflectivity"); + rainbow_ray = (unsigned char *) malloc(nbins); + + /* Load sweeps. */ + + for (isweep = 0; isweep < nsweeps; isweep++) { + sweep = RSL_new_sweep(nrays); + prf = rainbow_hdr.elev_params[isweep]->prf_high; + unam_rng = RSL_SPEED_OF_LIGHT / (2. * prf * 1000.); + azim_rate = rainbow_hdr.elev_params[isweep]->az_rate; + elev_angle = rainbow_hdr.elev_params[isweep]->elev_angle; + + /* Load rays. */ + + for (iray = 0; iray < nrays; iray++) { + nread = fread(rainbow_ray, 1, nbins, fp); + if (nread != nbins) { + fprintf(stderr, "ERROR: Could not read enough bytes to fill " + "ray.\n"); + fprintf(stderr, "Sweep = %d, ray = %d, number read = %d\n", + isweep, iray, nread); + return 0; + } + ray = RSL_new_ray(nbins); + + /* TODO: Add code for other fields. */ + + if (vol_index == DZ_INDEX) { + for (i=0; i < ray->h.nbins; i++) { + dz = -31.5 + (rainbow_ray[i] - 1) * 0.5; + if (dz < -31.5) + ray->range[i] = invf(BADVAL); + else + ray->range[i] = invf(dz); + } + } + /* Load ray header. Note: the rainbow data file has only one time + * stamp, which is the data acquisition time at the start of the + * volume scan. For now, that is the time assigned to all rays. + */ + ray->h.month = rainbow_hdr.month; + ray->h.day = rainbow_hdr.day; + ray->h.year = rainbow_hdr.year; + ray->h.hour = rainbow_hdr.hour; + ray->h.minute = rainbow_hdr.minute; + ray->h.sec = rainbow_hdr.sec; + ray->h.f = f; + ray->h.invf = invf; + ray->h.unam_rng = unam_rng; + ray->h.prf = prf; + ray->h.azim_rate = azim_rate; + ray->h.elev = elev_angle; + ray->h.elev_num = isweep + 1; + ray->h.fix_angle = elev_angle; + ray->h.azimuth = rainbow_hdr.az_start + iray * rainbow_hdr.az_step; + ray->h.ray_num = iray + 1; + ray->h.range_bin1 = rainbow_hdr.range_start; + ray->h.gate_size = rainbow_hdr.range_step * 1000.; + ray->h.beam_width = beam_width; + sweep->ray[iray] = ray; + } /* iray */ + sweep->h.sweep_num = isweep + 1; + sweep->h.beam_width = beam_width; + sweep->h.vert_half_bw = sweep->h.beam_width * 0.5; + sweep->h.horz_half_bw = sweep->h.beam_width * 0.5; + sweep->h.nrays = nrays; + sweep->h.f = f; + sweep->h.invf = invf; + v->sweep[isweep] = sweep; + } /* isweep */ + return 1; +} diff --git a/range.c b/range.c new file mode 100644 index 0000000..4da084a --- /dev/null +++ b/range.c @@ -0,0 +1,183 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include "rsl.h" + +# define M_PI 3.14159265358979323846 +# define M_PI_2 1.57079632679489661923 +/* Earth radius in km. */ +double Re = (6374.0*4.0/3.0); + +/********************************************************************/ +/* */ +/* RSL_set_earth_rad(double new_Re) */ +/* */ +/* By: Dennis Flanigan */ +/* Applied Research Corporation */ +/* August 26, 1994 */ +/********************************************************************/ +void RSL_set_earth_radius(double new_Re) +{ + Re = new_Re; +} + +/*********************************************************************/ +/* */ +/* void RSL_get_gr_slantr_h */ +/* *gr - ground range in KM. */ +/* *slantr - slant range in KM. */ +/* *h - height in KM. */ +/* */ +/* By: John Merritt */ +/* June 7, 1995 */ +/*********************************************************************/ +void RSL_get_gr_slantr_h(Ray *ray, int i, float *gr, float *slantr, float *h) +{ + *gr = *slantr = *h = 0.0; + if (ray == NULL) return; + *slantr = i * ray->h.gate_size + ray->h.range_bin1; + *slantr /= 1000; /* meters to km */ + RSL_get_groundr_and_h(*slantr, ray->h.elev, gr, h); + return; +} + +/*********************************************************************/ +/* */ +/* RSL_get_groundr_and_h(sr, elev, &gr, &h) */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* July 23, 1994 */ +/*********************************************************************/ +void RSL_get_groundr_and_h(float slant_r, float elev, float *gr, float *h) +{ +/* Input: + * slant_r - slant range, along the beam, in km. + * elev - elevation angle, in degrees. + * + * Output: + * gr - Ground range in km. + * h - Height of data point above earth, in km. + */ + double GR; + double H; + + if (slant_r == 0.0) {*h = 0; *gr = 0; return;} + elev += 90; + H = sqrt( pow(Re,2.0) + pow(slant_r,2.0) - 2*Re*slant_r*cos(elev*M_PI/180.0)); + if (H != 0.0) { + GR = Re * acos( ( pow(Re,2.0) + pow(H,2.0) - pow(slant_r,2.0)) / (2 * Re * H)); + } else { + GR = slant_r; + H = Re; + } + H -= Re; + *h = H; + *gr = GR; + +} + + +/*********************************************************************/ +/* */ +/* RSL_get_slantr_and_elev(gr, h, &r, &e) */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* July 23, 1994 */ +/* */ +/*********************************************************************/ +void RSL_get_slantr_and_elev(float gr, float h, float *slant_r, float *elev) +{ +/* Input: + * gr - Ground range in km. + * h - Height of data point above earth, in km. + * + * Output: + * slant_r - slant range, along the beam, in km. + * elev - elevation angle, in degrees. + */ + +/* This equation lifted from Dennis Flanigan's rsph.c code. */ + + double slant_r_2; /* Slant range squared. */ + double ELEV; + double SLANTR; + + if (gr == 0) {*slant_r = 0; *elev = 0; return;} + + h += Re; + + slant_r_2 = pow(Re,2.0) + pow(h,2.0) - (2*Re*h*cos(gr/Re)); + SLANTR = sqrt(slant_r_2); + + ELEV = acos( (pow(Re,2.0) + slant_r_2 - pow(h,2.0)) / (2*Re*(SLANTR))); + ELEV *= 180.0/M_PI; + ELEV -= 90.0; + + *slant_r = SLANTR; + *elev = ELEV; +} + + +/*********************************************************************/ +/* */ +/* RSL_get_slantr_and_h(gr, elev, &sr, &h) */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* July 23, 1994 */ +/* */ +/*********************************************************************/ +void RSL_get_slantr_and_h(float gr, float elev, float *slant_r, float *h) +{ +/* Input: + * gr - Ground range in km. + * elev - elevation angle, in degrees. + * + * Output: + * slant_r - slant range, along the beam, in km. + * h - Height of data point above earth, in km. + */ + + double ELEV; + double SLANTR; + double ALPHA; + double BETA; + double GAMMA; + double A; + + if (gr == 0) {*slant_r = 0; *h = 0; return;} + + ELEV = elev*M_PI/180.0; + ALPHA = ELEV + M_PI_2; /* Elev angle + 90 */ + GAMMA = gr/Re; + BETA = M_PI - (ALPHA + GAMMA); /* Angle made by Re+h and slant */ + SLANTR = Re*(sin(GAMMA)/sin(BETA)); + A = Re*sin(ALPHA)/sin(BETA); + + *h = (float) (A - Re); + *slant_r = (float)SLANTR; +} + diff --git a/rapic-lex.l b/rapic-lex.l new file mode 100644 index 0000000..280d2cd --- /dev/null +++ b/rapic-lex.l @@ -0,0 +1,119 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997, 1998 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * 2/18/98 - John Merritt + */ +%{ + +#include +#include "rapic_routines.h" +#include "rapic.h" +#include + +/* + fprintf(stderr, "LEX len=%d text=<", yyleng);\ + binprint(yytext, yyleng);\ + fprintf(stderr, "> token=[%d]\n", x);\ +*/ +#define strreturn(x) rapiclval.token.s = calloc(yyleng+1, sizeof(char));\ + rapiclval.token.len=yyleng;\ + memcpy(rapiclval.token.s, yytext, yyleng);\ + return x; + +%} + + +%x ATMODE + +%% + +\/IMAGE: {strreturn(IMAGE);} +\/IMAGEEND: {strreturn(IMAGEEND);} +\/IMAGESCANS: {strreturn(IMAGESCANS);} +\/IMAGESIZE: {strreturn(IMAGESIZE);} +\/SCAN {strreturn(SCAN);} +"\/IMAGEHEADER END:" {strreturn(IMAGEHEADEREND);} +COUNTRY: {strreturn(COUNTRY);} +NAME: {strreturn(NAME);} +STNID: {strreturn(STNID);} +LATITUDE: {strreturn(LATITUDE);} +LONGITUDE: {strreturn(LONGITUDE);} +HEIGHT: {strreturn(HEIGHT);} +DATE: {strreturn(DATE);} +TIME: {strreturn(TIME);} +TIMESTAMP: {strreturn(TIMESTAMP);} +VERS: {strreturn(VERS);} +FREQUENCY: {strreturn(FREQUENCY);} +PRF: {strreturn(PRF);} +PULSELENGTH: {strreturn(PULSELENGTH);} +RNGRES: {strreturn(RNGRES);} +ANGRES: {strreturn(ANGRES);} +ANGLERATE: {strreturn(ANGLERATE);} +CLEARAIR: {strreturn(CLEARAIR);} +VIDRES: {strreturn(VIDRES);} +STARTRNG: {strreturn(STARTRNG);} +ENDRNG: {strreturn(ENDRNG);} +PRODUCT: {strreturn(PRODUCT);} +PASS: {strreturn(PASS);} +IMGFMT: {strreturn(IMGFMT);} +ELEV: {strreturn(ELEV);} +VIDEO: {strreturn(VIDEO);} +VELLVL: {strreturn(VELLVL);} +NYQUIST: {strreturn(NYQUIST);} +UNFOLDING: {strreturn(UNFOLDING);} +VOLUMETRIC {strreturn(VOLUMETRIC);} +NORMAL {strreturn(NORMAL);} +[Nn][Oo][Nn][Ee] {strreturn(NONE);} +[Oo][Ff] {strreturn(OF);} +[Oo][Nn] {strreturn(ON);} +[Oo][Ff][Ff] {strreturn(OFF);} +[Rr][Ee][Ff][Ll] {strreturn(REFL);} +[Vv][Ee][Ll] {strreturn(VEL);} +[Uu][Nn][Cc][Oo][Rr][Rr][Ee][Ff][Ll] {strreturn(UNCORREFL);} +[Zz][Dd][Rr] {strreturn(ZDR);} +[Ww][Ii][Dd] | +[Ww][Ii][Dd][Tt][Hh] {strreturn(WID);} + +-?[[:digit:]]+ {strreturn(NUMBER);} +-?[[:digit:]]*[\.][[:digit:]]+ | +-?[[:digit:]]+[\.][[:digit:]]* {strreturn(FLOATNUMBER);} +[[][[:digit:]]+[]] {strreturn(BRACKETNUM);} + +[[:alpha:]]+ {strreturn(ALPHA);} + +"END RADAR IMAGE" {strreturn(ENDRADARIMAGE);} + + + +"@" {BEGIN ATMODE; yymore();} +. | +\n {yymore();} +"\0\0@" | +"\0\0\x1a" {BEGIN INITIAL; yyless(yyleng-1); strreturn(RAYDATA);} + +: {return(yytext[0]);} + +. ; /* Ignore. */ +"\n" ; /* Ignore. */ + +%% diff --git a/rapic.y b/rapic.y new file mode 100644 index 0000000..0c99d12 --- /dev/null +++ b/rapic.y @@ -0,0 +1,624 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1998 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +%{ +#define USE_RSL_VARS +#include "rapic_routines.h" +#include "rsl.h" +#include +#include +#include + +int rapicerror(char *s); +int rapicwrap(char *s); +int rapicwrap(char *s); +int yywrap(char *s); +int rapiclex(void); + +int nsweep = 0; +float angres; +Radar *radar, *rapic_radar = NULL; +Volume *volume; +Sweep *sweep; +Ray *ray; + +/* Rapic format declarations. */ +Rapic_sweep_header rh; +Rapic_sweep *rs; + +unsigned char outbuf[2000000]; +int outbytes; +float azim, elev; +float save_elev; +int delta_time; +int nray = 0; +int ifield; +int ivolume, isweep, iray; +int station_id; + +int sweepcount[5]; + +extern int radar_verbose_flag; +float rapic_nyquist; + %} + +/* 2/18/98 - John Merritt + * + * This grammar parses the NT Rapic radar format. The grammar + * is not minimal, however, it is self documenting; it closely matches + * the brief documentation. + */ + +/*----------------------------------------------------------------- + * NT Rapic Volume Structure: + * NOTE: '*' marked tokens are preent only in versions > 10.0 + * + * ImageHeader: + * The header contains a set of tokens followed by data. + * Each token is seperated by '\n' and all the data is + * in ascii. + * ScanHeader: + * Scan header has the scan details like fieldname, + * date/time azimuth,elevation etc. + * The different sets of Tokens together with the data + * are seperate by '\0'. + * ScanData: + * This represents the field data in runlehgth code. + * Each Ray data contains azimuth,elevation,delta time + * since start of this scan and the actual data. + * + * Here is a brief explanation of each of the Tokens. + * + * + * ImageHeader: + * + * 1 /IMAGE: + * 4 digit number + * 10 digit number + * + * 2 /IMAGESCANS: + * Number of scans in this volume + * + * 3 /IMAGESIZE: + * Size of image in bytes + * + * 4 /SCAN + * 1 - + * seqnum as given in /IMAGE: + * yymoddhhmm + * Don't care ( I don't know ) + * Target Elevation in degrees. + * 0-4 + * 0 Reflectivity ?? Index? haven't seen this yet. ?? + * 1 Velocity Confirmed this index. + * 2 Width Confirmed. + * 3 ZDR ?? Index? haven't seen this yet. ?? + * 4 Uncorrected Reflectivity. Confirmed. + * Don't care + * Offset to start of scan header + * Size of this scan + * add offset to size to get to the next scan + * /SCAN is repeated for each scan in the volume. + * NOTE: + * Unlike other formats each scan need not represent a seperate + * elevation. + * + * 5 /IMAGEHEADER END: + * Indicates the end of Image header. + * + * ScanHeader: + * + * COUNTRY: + * is a country code number + * + * NAME: + * 8 char long station name + * + * STNID: + * A unique number indexing into station details + * + * LATITUDE: * + * Latitude in degrees + * + * LONGITUDE: * + * Longitude in degrees + * + * HEIGHT: * + * Radar height in meters + * + * DATE: + * year = datno % 100 + * if year > 80 year += 1900 + * else year += 2000 + * doy = datno / 100 + * Get the julian Number from year,1,1 and add doy -1 + * Use Julian date conversion to get calendar date. + * NOTE: As simple as remembering your partner's DOB. + * + * TIME: + * Hour and minute + * + * TIMESTAMP: * + * year,month,day,hour,min,sec + * + * VERS: + * 10.01 + * + * FREQUENCY: * + * Radar Frequency. + * + * PRF: + * Pulse repetition Frequency + * + * PULSELENGTH: * + * Pulse length + * + * RNGRES: + * Range between gates + * + * ANGRES: + * BeamWidth in degrees. + * + * CLEARAIR: ON or OFF + * + * VIDRES: + * Video Resolution can be + * 16 OR 256. + * + * STARTRNG: + * Range to First gate in meters. + * + * ENDRNG: + * Maximum range. + * + * PRODUCT: <[id]> + * Ascii text + * VOLUMETRIC + * NORMAL + * + * <[id]> + * + * PASS: of + * Number of this scan + * Max scan no. + * + * IMGFMT: + * PPI,RHI etc. + * + * ELEV: + * Elevation in degrees + * + * VIDEO: + * Field Name Vel,Refl,Vel,UnCorRefl,Zdr,Wid + * + * VELLVL: + * Velocity Level + * + * NYQUIST: + * Nyquist Velocity + * + * UNFOLDING: * + * None or x:y + * + * + * @ * + * AAA.A,EEE.E,TTT=LEN16D1D1D1NLD1D1D1NLNL + * + * AAA.A Azimuth in degrees + * EEE.E Elevation in degress + * TTT Delta time in seconds since the start of this scan + * LEN16 2 byte long length of radial + * + * D1 Run length coded Data. + * NL Null The Next Byte is count of NULL data. + * NLNL End of this Radial + * + * eg. There will be no white space in the actual radial data. + * + * @066.1,010.6,004=002082B2817F8C84830048D72D0038 + * 999C0036202D35FD2C00238A99008AFE920000 + * Azimuth = 66.1 + * Elev = 10.6 + * Dt = 4 sec since the start + * 0020 = Bytes to follow + * Data = 82,B2,81,7F,8C,84,83 + * 0048 = 48H null bytes + * Data = D7,2D + * 0038 = 38H null bytes + * Data = 99,9C + * 0036 = 36H Null bytes + * ........................ + * 0000 = End of Data. + * In versions before 10.1 + * @ + * AAALEN16D1D1D1NLD1D1D1NLNL + * + * AAA Azimuth in degrees + * LEN16 2 byte long length of radial + * + * D1 Run length coded Data. + * NL Null The Next Byte is count of NULL data. + * NLNL End of this Radial + * + * eg. There will be no white space in the actual radial data. + * + * @066002082B2817F8C84830048D72D0038 + * 999C0036202D35FD2C00238A99008AFE920000 + * Azimuth = 66 + * 0020 = Bytes to follow + * Data = 82,B2,81,7F,8C,84,83 + * 0048 = 48H null bytes + * Data = D7,2D + * 0038 = 38H null bytes + * Data = 99,9C + * 0036 = 36H Null bytes + * ........................ + * 0000 = End of Data. + * + * Please see the attached sample.vol to give a overall picture of the data. + * This is the dump of the volume with white space inserted to make it readable. + * Radial data dump is in hex. + */ + +%token IMAGE IMAGESCANS IMAGESIZE IMAGEEND +%token SCAN IMAGEHEADEREND +%token NUMBER +%token ALPHA +%token FLOATNUMBER +%token BRACKETNUM + +%token COUNTRY +%token NAME +%token STNID +%token LATITUDE +%token LONGITUDE +%token HEIGHT +%token DATE +%token TIME +%token TIMESTAMP +%token VERS +%token FREQUENCY +%token PRF +%token PULSELENGTH +%token RNGRES +%token ANGRES +%token ANGLERATE +%token CLEARAIR ON OFF +%token VIDRES +%token STARTRNG +%token ENDRNG +%token PRODUCT +%token PASS +%token IMGFMT +%token ELEV +%token VIDEO +%token VELLVL +%token NYQUIST +%token UNFOLDING +%token AT +%token VOLUMETRIC +%token NORMAL +%token OF +%token REFL VEL UNCORREFL ZDR WID +%token NONE +%token RAYDATA +%token ENDRADARIMAGE + +%union { + Charlen token; +} + +%expect 59 + +%% + +rapic_recognized : complete_header sweeps imageend +{ + if (radar_verbose_flag) fprintf(stderr, "SUCCESSFUL parse\n"); + sprintf(radar->h.name, "%s", rh.namestr); + sprintf(radar->h.radar_name, "%s", rh.namestr); + + radar = fill_header(radar); + radar = RSL_prune_radar(radar); + rapic_radar = radar; + YYACCEPT; +} + +sweeps : sweep + | sweeps sweep + +sweep : sweepheader rays ENDRADARIMAGE +{ + /* Attach the sweep to the volume. */ + if (radar_verbose_flag) fprintf(stderr, "Attach the sweep %d to the volume %d.\n", + isweep, ivolume); + radar->v[ivolume]->sweep[isweep] = sweep; + radar->v[ivolume]->h.f = sweep->h.f; + radar->v[ivolume]->h.invf = sweep->h.invf; +} + +sweepheader : scanheader +{ + /* float c = RSL_SPEED_OF_LIGHT; */ + if (rh.angle_resolution != 0) + sweep = RSL_new_sweep((int)(360.0/rh.angle_resolution+0.5)); + if (fabs(rh.elev - save_elev) > .5) { /* New sweep elevation. */ + isweep++; + save_elev = rh.elev; + } + nray = 0; + /* rapic_nyquist = c*((float)rh.prf/10.)/(4.*(float)rh.freq*100000.0); */ +} + +imageend : IMAGEEND seqno imgno + +complete_header : imageheader IMAGEHEADEREND +{ + if (radar_verbose_flag) fprintf(stderr, "sweepcount[0] = %d\n", sweepcount[0]); + if (sweepcount[0] > 0) { + radar->v[DZ_INDEX] = RSL_new_volume(sweepcount[0]); + radar->v[DZ_INDEX]->h.type_str = strdup("Reflectivity"); + } + if (radar_verbose_flag) fprintf(stderr, "sweepcount[1] = %d\n", sweepcount[1]); + if (sweepcount[1] > 0) { + volume = radar->v[VR_INDEX] = RSL_new_volume(sweepcount[1]); + volume->h.type_str = strdup("Velocity"); + volume->h.calibr_const = 0.0; + } + if (radar_verbose_flag) fprintf(stderr, "sweepcount[2] = %d\n", sweepcount[2]); + if (sweepcount[2] > 0) { + radar->v[SW_INDEX] = RSL_new_volume(sweepcount[2]); + volume->h.type_str = strdup("Spectral Width"); + volume->h.calibr_const = 0.0; + } + if (radar_verbose_flag) fprintf(stderr, "sweepcount[3] = %d\n", sweepcount[3]); + if (sweepcount[3] > 0) { + radar->v[ZD_INDEX] = RSL_new_volume(sweepcount[3]); + volume->h.type_str = strdup("Reflectivity Depolarization Ratio"); + volume->h.calibr_const = 0.0; + } + if (radar_verbose_flag) fprintf(stderr, "sweepcount[4] = %d\n", sweepcount[4]); + if (sweepcount[4] > 0) { + radar->v[ZT_INDEX] = RSL_new_volume(sweepcount[4]); + volume->h.type_str = strdup("Total Reflectivity"); + volume->h.calibr_const = 0.0; + } + isweep = -1; /* It keeps track of the sweep number across all field + * types; volumes. It is immediately bumped to 0 when + * the sweepheader is parsed. + */ + save_elev = 99999; +} + ; + +imageheader : imageheader_item + | imageheader imageheader_item + | /* Empty */ + ; + +imageheader_item : IMAGE seqno imgno +{ + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + sweepcount[0] = 0; + sweepcount[1] = 0; + sweepcount[2] = 0; + sweepcount[3] = 0; + sweepcount[4] = 0; + radar->h.number = atoi($2); +} + + | IMAGESCANS number + | IMAGESIZE number +{ + if (atoi($2) <= 0) { + fprintf(stderr, "RAPIC: /IMAGESIZE == %d. RAPIC ingest returning NULL.\n", atoi($2)); + YYERROR; + } +} + | scanlist + ; + +scanlist : SCAN scanno ':' seqno datetime dc elev fieldno dc offset size +{ + ifield = atoi($8); + sweepcount[ifield]++; +} + +/* + * Now, describe some scan header fields. + */ + +rays : ray + | rays ray + | /* EMPTY */ + ; + +ray : RAYDATA + { + + /* fprintf(stderr, "YACC len=%d text=<", yylval.token.len); */ + /* binprint(yylval.token.s, yylval.token.len); */ + /* fprintf(stderr, ">\n"); */ + + /* Quiet the compilier, because I only use the rsl_f_list and rsl_invf_list. */ + RSL_ftype[0] = RSL_ftype[0]; + + /* Use yylval.token.s and yylval.token.len */ + memset(outbuf, sizeof(outbuf), '\0'); + rapic_decode((unsigned char *)yylval.token.s, yylval.token.len, outbuf, &outbytes, + &azim, &elev, &delta_time); + /* fprintf(stderr, "RAYDATA: ray %d, ivol %d, isweep %d, azim %f, elev %f, dtime %d, size=%d\n", nray, ivolume, isweep, azim, elev, delta_time, outbytes); */ + + ray = RSL_new_ray(outbytes); + rapic_load_ray_header(rh, nray, isweep, elev, azim, &ray->h); /* Mostly from the scanheader (rh). */ + ray->h.azimuth = azim; + /* if (39h.elev = elev; + ray->h.sec += delta_time; + ray->h.f = RSL_f_list[ivolume]; /* Data conversion function. f(x). */ + ray->h.invf = RSL_invf_list[ivolume]; /* invf(x). */ + + rapic_fix_time(ray); + rapic_load_ray_data(outbuf, outbytes, ivolume, ray); +#define DODO +#undef DODO +#ifdef DODO + if (ray->h.ray_num == 0 && ivolume == 1 && isweep == 0) + { int i; + fprintf(stderr, "RAYDATA: ray %d, ivol %d, isweep %d, azim %f, elev %f, dtime %d, size=%d\n", nray, ivolume, isweep, azim, elev, delta_time, outbytes); + for (i=0; ih.nbins; i++) { + fprintf(stderr,"YACCray->range[%d] = %d %f\n", i, (int)ray->range[i], + ray->h.f(ray->range[i])); + } + } +#endif + /* Attach the ray to the sweep. */ + sweep->ray[nray] = ray; + sweep->h.beam_width = ray->h.beam_width; + sweep->h.vert_half_bw = sweep->h.beam_width / 2.0; + sweep->h.horz_half_bw = sweep->h.beam_width / 2.0; + sweep->h.sweep_num = isweep; + sweep->h.elev = ray->h.elev; + sweep->h.f = ray->h.f; + sweep->h.invf = ray->h.invf; + nray++; + /* } */ +} + +scanheader : scanheaditem + | scanheader scanheaditem + | /* EMPTY */ + ; + +/* Each of these items are the header for a sweep. */ + +scanheaditem +: NAME namestr { memmove(rh.namestr,$2,$2); } +| COUNTRY code { rh.country = atoi($2); } +| STNID idno { rh.station_id_no = atoi($2); } +| LATITUDE lat { rh.lat = atof($2); } +| LONGITUDE lon { rh.lon = atof($2); } +| HEIGHT alt { rh.height = atof($2); } +| DATE datno { rh.datno = atoi($2); } +| TIME hhmm { rh.hhmm = atof($2); } +| TIMESTAMP yyyymoddhhmmss { memmove(rh.yyyymoddhhmmss,$2,$2); } +| VERS versionNumber { rh.versionNumber = atof($2); } +| FREQUENCY freq { rh.freq = atoi($2); } +| PRF prf { rh.prf = atoi($2); } +| PULSELENGTH len { rh.pulselen = atof($2); } +| RNGRES gatewidth { rh.range_resolution = atoi($2); } +| ANGLERATE anglerate { rh.anglerate = atof($2); } +| CLEARAIR clearair { memmove(rh.clearair,$2,$2);} +| ANGRES angle { rh.angle_resolution = atof($2); } +| VIDRES res { rh.video_resolution = atoi($2); } +| STARTRNG rng { rh.start_range = atoi($2); } +| ENDRNG rng { rh.end_range = atoi($2); } +| PRODUCT typeid BRACKETNUM { memmove(rh.product_type,$2,$2); } +| PRODUCT +| PASS noofnscans +| ELEV elev { rh.elev = atof($2); } +| VELLVL level { rh.vellvl = atof($2); } +| NYQUIST nyq +{ + rh.nyquist = atof($2); + rapic_nyquist = rh.nyquist; +} +| VIDEO field { memmove(rh.video,$2,$2); } +| IMGFMT type { memmove(rh.imgfmt,$2,$2); } +| UNFOLDING ratio /* Already loaded: rh.ratio1, rh.ratio2 */ +; + +real : number + | FLOATNUMBER + +number : NUMBER + +seqno : number +scanno : number +imgno : number +datetime : number +dc : real + | ALPHA +elev : real +fieldno : number +offset : number +size : number +datno : number + +code : number +namestr : ALPHA +idno : number +lat : real +lon : real +alt : real +hhmm : real + +yyyymoddhhmmss : number +versionNumber : real + +freq : number +prf : number +len : real +gatewidth : number +angle : real +anglerate : real +clearair : ON + | OFF +res : number +rng : number +typeid : VOLUMETRIC + | NORMAL + +noofnscans : no OF nscans +no : number {rh.scannum = atoi($1);} +nscans : number {rh.ofscans = atoi($1);} +type : ALPHA + +field : REFL {ivolume = DZ_INDEX; volume = radar->v[ivolume];} + | VEL {ivolume = VR_INDEX; volume = radar->v[ivolume];} + | UNCORREFL {ivolume = ZT_INDEX; volume = radar->v[ivolume];} + | ZDR {ivolume = ZD_INDEX; volume = radar->v[ivolume];} + | WID {ivolume = SW_INDEX; volume = radar->v[ivolume];} + +level : real +nyq : real + +ratio : NONE {rh.ratio1 = 0; rh.ratio2 = 0;} +| number ':' number {rh.ratio1 = atoi($1); rh.ratio2 = atoi($3);} + + + +%% + +int rapicerror(char *s) +{ + fprintf(stderr, "RAPIC ERROR: <%s> on token <", s); + binprint(yylval.token.s, yylval.token.len); + fprintf(stderr, ">\n"); + return 1; +} + +int rapicwrap(char *s) +{ + yywrap(s); + return 1; +} diff --git a/rapic_routines.c b/rapic_routines.c new file mode 100644 index 0000000..2ae3faf --- /dev/null +++ b/rapic_routines.c @@ -0,0 +1,323 @@ +#include +#include "rapic_routines.h" +#include + +#include +void rapic_decode(unsigned char *inbuf, int inbytes, unsigned char *outbuf, int *outbytes, + float *azim, float *elev, int *delta_time) +{ + /* Decode RLE rapic buffer. + * + * Output to 'outbuf' and indicate the size w/ 'nout'. + */ + + /* There is some risidual parsing to do: + * + * @ * + * AAA.A,EEE.E,TTT=LEN16D1D1D1NLD1D1D1NLNL + * + * AAA.A Azimuth in degrees + * EEE.E Elevation in degress + * TTT Delta time in seconds since the start of this scan + * LEN16 2 byte long length of radial + * + * D1 Run length coded Data. + * NL Null The Next Byte is count of NULL data. + * NLNL End of this Radial + * + * eg. There will be no white space in the actual radial data. + * + * @066.1,010.6,004=002082B2817F8C84830048D72D0038 + * 999C0036202D35FD2C00238A99008AFE920000 + * Azimuth = 66.1 + * Elev = 10.6 + * Dt = 4 sec since the start + * 0020 = Bytes to follow + * Data = 82,B2,81,7F,8C,84,83 + * 0048 = 48H null bytes + * Data = D7,2D + * 0038 = 38H null bytes + * Data = 99,9C + * 0036 = 36H Null bytes + * ........................ + * 0000 = End of Data. + * In versions before 10.1 + * @ + * AAALEN16D1D1D1NLD1D1D1NLNL + * + * AAA Azimuth in degrees + * LEN16 2 byte long length of radial + * + * D1 Run length coded Data. + * NL Null The Next Byte is count of NULL data. + * NLNL End of this Radial + * + * eg. There will be no white space in the actual radial data. + * + * @066002082B2817F8C84830048D72D0038 + * 999C0036202D35FD2C00238A99008AFE920000 + * Azimuth = 66 + * 0020 = Bytes to follow + * Data = 82,B2,81,7F,8C,84,83 + * 0048 = 48H null bytes + * Data = D7,2D + * 0038 = 38H null bytes + * Data = 99,9C + * 0036 = 36H Null bytes + * ........................ + * 0000 = End of Data. + * + */ + + + /* The parser won't give us a line w/o '@' at the begining nor '\0\0' + * at the end. So we can be sure of that. + */ + + int i; + char prefix[16]; + unsigned short nnulls; + short i16; + + /* Find the '=' and start RLE decode from there. */ + *outbytes = 0; + memset(prefix, '\0', sizeof(prefix)); + memcpy(prefix, &inbuf[1], 15); + + sscanf(prefix, "%f,%f,%d", azim, elev, delta_time); + /* fprintf(stderr, "AZIM=%f, ELEV=%f, TTT=%d\n", *azim, *elev, *delta_time); */ + + /* Now, decode RLE. Don't care about 17,18 (they are the RLE buf size) */ + memcpy(&i16, &inbuf[17], 2); + i16 = ntohs(i16); + /* fprintf(stderr, "Expecting %d bins\n", (int)i16); */ + i = 19; + while (i\n"); */ +} + + + +/*---------------------------------------------------------*/ +/* */ +/* binprint */ +/* */ +/*---------------------------------------------------------*/ +void binprint(char *s, int n) +{ +int i; + +for (i=0; i +void rapic_fix_time (Ray *ray) +{ + struct tm the_time; + float fsec; + /* Fixes possible overflow values in month, day, year, hh, mm, ss */ + /* Normally, ss should be the overflow. This code ensures end of + * month, year and century are handled correctly by using the Unix + * time functions. + */ + if (ray == NULL) return; + memset(&the_time, 0, sizeof(struct tm)); + the_time.tm_sec = ray->h.sec; + fsec = ray->h.sec - the_time.tm_sec; + the_time.tm_min = ray->h.minute; + the_time.tm_hour = ray->h.hour; + the_time.tm_mon = ray->h.month - 1; + the_time.tm_year = ray->h.year - 1900; + the_time.tm_mday = ray->h.day; + the_time.tm_isdst = -1; + (void) mktime(&the_time); + /* The time is fixed. */ + ray->h.sec = the_time.tm_sec; + ray->h.sec += fsec; + ray->h.minute = the_time.tm_min; + ray->h.hour = the_time.tm_hour; + ray->h.month = the_time.tm_mon + 1; + ray->h.year = the_time.tm_year + 1900; + ray->h.day = the_time.tm_mday; + return; +} + +void rapic_load_ray_header(Rapic_sweep_header rh, int iray, int isweep, float elev, float azim, Ray_header *h) +{ + sscanf(rh.yyyymoddhhmmss,"%4d%2d%2d%2d%2d%2f", + &h->year,&h->month,&h->day, + &h->hour, &h->minute, &h->sec); + + h->unam_rng = rh.end_range/1000.0; /* Unambiguous range. (KM). */ + h->azimuth = azim; /* Azimuth angle. (degrees). Must be positive + * 0=North, 90=east, -90/270=west. + * This angle is the mean azimuth for the whole ray. + * Eg. for NSIG the beginning and end azimuths are + * averaged. + */ + h->ray_num = iray; /* Ray no. within elevation scan. */ + h->elev = rh.elev; /* Elevation angle. (degrees). */ + h->elev_num = isweep; /* Elevation no. within volume scan. */ + + h->range_bin1 = rh.start_range; /* Range to first gate.(meters) */ + h->gate_size = rh.range_resolution; /* Data gate size (meters)*/ + + h->vel_res = rh.range_resolution; /* Doppler velocity resolution */ + h->sweep_rate = rh.anglerate/6.0; /* Sweep rate. Full sweeps/min. */ + + h->prf = rh.prf; /* Pulse repetition frequency, in Hz. */ + h->azim_rate = rh.anglerate; /* degrees/sec */ + h->fix_angle = elev; + h->pitch = 0; /* Pitch angle. */ + h->roll = 0; /* Roll angle. */ + h->heading = 0; /* Heading. */ + h->pitch_rate = 0; /* (angle/sec) */ + h->roll_rate = 0; /* (angle/sec) */ + h->heading_rate = 0; /* (angle/sec) */ + h->lat = rh.lat; /* Latitude (degrees) */ + h->lon = rh.lon; /* Longitude (degrees) */ + h->alt = rh.height; /* Altitude (m) */ + h->rvc = 0; /* Radial velocity correction (m/sec) */ + h->vel_east = 0; /* Platform velocity to the east (m/sec) */ + h->vel_north = 0; /* Platform velocity to the north (m/sec) */ + h->vel_up = 0; /* Platform velocity toward up (m/sec) */ + h->pulse_count = 0; /* Pulses used in a single dwell time. */ + h->pulse_width = rh.pulselen; /* Pulse width (micro-sec). */ + h->beam_width = rh.angle_resolution; /* Beamwidth in degrees. */ + h->frequency = rh.freq/1000.0; /* Carrier freq. GHz. */ + h->wavelength = 0; /* Wavelength. Meters. */ + h->nyq_vel = rh.nyquist; /* Nyquist velocity. m/s */ + + return; +} + +extern float rapic_nyquist; + +float RAPIC_DZ_F(unsigned char x) { + if (x == 0) return NOECHO; + return (((float)x-64)/2.0); /* rapic -> float */ +} + +float RAPIC_VR_F(unsigned char x) { + if (x == 0) return BADVAL; + return (((float)((int)x-128))/128.0*rapic_nyquist); /* rapic -> float */ +} + +float RAPIC_SW_F(unsigned char x) { + if (x == 0) return NOECHO; + return (((float)x)/256.0*rapic_nyquist); /* rapic -> float */ +} + +float RAPIC_ZT_F(unsigned char x) { + return RAPIC_DZ_F(x); +} + +float RAPIC_ZD_F(unsigned char x) { + if (x == 0) return NOECHO; + return (((float)x-128)/16.0); /* rapic -> float */ +} + +/* USE RSL INDEXING! */ +static float (*RAPIC_f_list[])(unsigned char x) = {RAPIC_DZ_F, + RAPIC_VR_F, + RAPIC_SW_F, + NULL, + RAPIC_ZT_F, + NULL, + NULL, + RAPIC_ZD_F}; + + +void rapic_load_ray_data(unsigned char *buf, int bufsize, int ifield, Ray *ray) +{ + /* ifield is the RSL numbering scheme for field types. The conversion + * is done in rapic.y. In other words, we've already converted rapic + * index to RSL indexes. + */ + int i; + for (i=0; irange[i] = ray->h.invf(RAPIC_f_list[ifield](buf[i])); + /* fprintf(stderr,"i=%d ifield=%d, buf[%d]=%2.2x, ray->range[%d]=%4.4x value=%f\n", i,ifield,i,buf[i],i,ray->range[i], RAPIC_f_list[ifield](buf[i]) ); */ + } + ray->h.nbins = bufsize; +} + +Radar *fill_header(Radar *radar) +{ + /* Learn as much as possible from the Ray headers. Place this + * information into radar->h.xxxxxx + */ + Ray *ray; + Volume *volume; + int i; + float tmp; + + volume = NULL; + if (radar == NULL) return NULL; + for (i=0; ih.nvolumes && !(volume = radar->v[i]); i++) + ; + if (volume == NULL) return NULL; + + ray = RSL_get_first_ray_of_volume(volume); + if (ray == NULL) return NULL; + + radar->h.month = ray->h.month; + radar->h.day = ray->h.day; + radar->h.year = ray->h.year; + radar->h.hour = ray->h.hour; + radar->h.minute= ray->h.minute; + radar->h.sec = ray->h.sec; /* Second plus fractional part. */ + sprintf(radar->h.radar_type, "rapic"); /* Type of radar. */ + /* nvolumes is already filled in YACC. */ + /* number is already filled in YACC. */ + /* name is already filled in YACC. */ + /* radar_name is already filled in YACC. */ + /* radar->h.city[15]; */ /* Not available from RAPIC. */ + /* radar->h.state[3]; */ /* Not available from RAPIC. */ + /* radar->h.country[15]; */ /* Not available from RAPIC. */ + + /** Latitude deg, min, sec **/ + radar->h.latd = (int)ray->h.lat; + tmp = (ray->h.lat - radar->h.latd) * 60.0; + radar->h.latm = (int)tmp; + radar->h.lats = (int)((tmp - radar->h.latm) * 60.0); + /** Longitude deg, min, sec **/ + radar->h.lond = (int)ray->h.lon; + tmp = (ray->h.lon - radar->h.lond) * 60.0; + radar->h.lonm = (int)tmp; + radar->h.lons = (int)((tmp - radar->h.lonm) * 60.0); + + radar->h.height = ray->h.alt; /* height of site in meters above sea level*/ + radar->h.spulse = 0; /* length of short pulse (ns)*/ + radar->h.lpulse = 0; /* length of long pulse (ns) */ + + return radar; +} diff --git a/rapic_routines.h b/rapic_routines.h new file mode 100644 index 0000000..2c4f3b9 --- /dev/null +++ b/rapic_routines.h @@ -0,0 +1,115 @@ +#include "rsl.h" + +typedef struct { + char *s; + int len; +} Charlen; + +typedef struct { + int country; /* 000 */ + char namestr[20]; /* Berrima */ + int station_id_no; /* 63 */ + float lat; /* 12.457 */ + float lon; /* 130.925 */ + float height; /* 40 (meters) */ + int datno; /* 02798 (jjjyy) */ + float hhmm; /* 05.00 */ + char yyyymoddhhmmss[20]; /* 1998012705001 */ + float versionNumber; /* 10.01 */ + int freq; /* 5645 */ + int prf; /* 740 */ + float pulselen; /* 0.9 */ + int range_resolution; /* 500 (meters) */ + float anglerate; /* 15.0 */ + char clearair[4]; /* "ON" or "OFF" */ + float angle_resolution; /* 1.0 (degrees) */ + int video_resolution; /* 256 */ + int start_range; /* 1000 (meters) */ + int end_range; /* 256000 (meters) */ + char product_type[10]; /* VOLUMETRIC */ + int scannum; /* Scan n of m */ + int ofscans; /* m */ + char imgfmt[20]; /* PPI, RHI, etc. */ + float elev; /* 0.5 (degrees) */ + char video[20]; /* Vel, Wid, ... */ + float vellvl; /* 9.8 */ + float nyquist; /* 9.8 */ + float ratio1, ratio2; /* x:y, None */ + + int nbins; /* Number of values in Rapic_range vector. */ +} Rapic_sweep_header; + +typedef struct { + float x; /* Dummy. */ +} Rapic_range; + +typedef struct { + Rapic_sweep_header h; + Rapic_range *r; +} Rapic_sweep; + +void binprint(char *s, int n); +void rapic_decode(unsigned char *inbuf, int inbytes, unsigned char *outbuf, int *outbytes, + float *azim, float *elev, int *delta_time); +void rapic_fix_time (Ray *ray); +void rapic_load_ray_header(Rapic_sweep_header rh, int iray, int isweep, float elev, float azim, Ray_header *h); +void rapic_load_ray_data(unsigned char *buf, int bufsize, int ifield, Ray *ray); +Radar *fill_header(Radar *radar); + +/* I want to have the rapic prefix in the yacc parser. + * This hack is required. + * I got this list from automake.html. + */ +/* +#define yymaxdepth rapicmaxdepth +#define yyparse rapicparse +#define yylex rapiclex +#define yyerror rapicerror +#define yylval rapiclval +#define yychar rapicchar +#define yydebug rapicdebug +#define yypact rapicpact +#define yyr1 rapicr1 +#define yyr2 rapicr2 +#define yydef rapicdef +#define yychk rapicchk +#define yypgo rapicpgo +#define yyact rapicact +#define yyexca rapicexca +#define yyerrflag rapicerrflag +#define yynerrs rapicnerrs +#define yyps rapicps +#define yypv rapicpv +#define yys rapics +#define yy_yys rapicyys +#define yystate rapicstate +#define yytmp rapictmp +#define yyv rapicv +#define yy_yyv rapicyyv +#define yyval rapicval +#define yylloc rapiclloc +#define yyreds rapicreds +#define yytoks rapictoks +#define yylhs rapiclhs +#define yylen rapiclen +#define yydefred rapicdefred +#define yydgoto rapicdgoto +#define yysindex rapicsindex +#define yyrindex rapicrindex +#define yygindex rapicgindex +#define yytable rapictable +#define yycheck rapiccheck + +#define yyin rapicin +#define yyout rapicout +#define yy_create_buffer rapic_create_buffer +#define yy_load_buffer_state rapic_load_buffer_state +#define yyrestart rapicrestart +#define yy_init_buffer rapic_init_buffer +#define yy_switch_to_buffer rapic_switch_to_buffer +#define yy_delete_buffer rapic_delete_buffer +#define yy_flush_buffer rapic_flush_buffer +#define yy_scan_buffer rapic_scan_buffer +#define yy_scan_string rapic_scan_string +#define yy_scan_bytes rapic_scan_bytes +*/ diff --git a/rapic_to_radar.c b/rapic_to_radar.c new file mode 100644 index 0000000..36a1afa --- /dev/null +++ b/rapic_to_radar.c @@ -0,0 +1,34 @@ +#include "rsl.h" +#include + +extern Radar *rapic_radar; +extern int rapicparse(void); + +Radar *RSL_rapic_to_radar(char *infile) +{ + /* Attach infile to stdin and call the parser. */ + + FILE *fp; + Radar *radar; + int save_fd; + + radar = NULL; + if (infile == NULL) { + save_fd = dup(0); + fp = fdopen(save_fd, "r"); + } else { + if ((fp = fopen(infile, "r")) == NULL) { + perror(infile); + return radar; + } + } + fp = uncompress_pipe(fp); /* Transparently gunzip. */ + close(0); dup(fileno(fp)); /* Redirect stdin. */ + + rapicparse(); + radar = rapic_radar; + + rsl_pclose(fp); + + return radar; +} diff --git a/ray_indexes.c b/ray_indexes.c new file mode 100644 index 0000000..d4b1198 --- /dev/null +++ b/ray_indexes.c @@ -0,0 +1,241 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * Creates an array that is located in each sweep structure that is + * a hash for quick azimuth angle lookups. These routines in concert + * with rewrites of the 'RSL_get_value...' routines dramatically speed + * up the RSL. + * + * The following routines are affected by this change. Just so you don't + * think I'm absentminded, I list what might be affected and illustrate that + * they're not. + * + * Routine Affected? + * --------------- ------------ + * RSL_copy_sweep No. + * RSL_clear_sweep No. + * RSL_read_radar No. + * RSL_write_radar No. + * RSL_uf_to_radar No. + * RSL_nsig_to_radar No. + * RSL_toga_to_radar No. + * RSL_lassen_to_radar No. + * RSL_new_sweep Yes. + * RSL_get_value_from_ray Yes. + * RSL_get... No. + + * + * By: John Merritt + * Space Applications Corporation + * October 10, 1995 + * + */ + +#include +#include +#include +#include "rsl.h" +extern int radar_verbose_flag; + +/*********************************************************************/ +/* */ +/* set_high_and_low_pointers */ +/* */ +/* By Dennis Flanigan */ +/* 5/2/95 */ +/*********************************************************************/ +static void set_high_and_low_pointers(Hash_table *table) + { + /* This function modifies its argument. */ + + Azimuth_hash *last,*current,*ray_prev_ind; + Azimuth_hash *one,*two,*three,*four,*very_first,*very_last; + int not_sorted_flag; + int i; + + /* Set ray_high,ray_low pointers in hash data structures. + */ + if (table == NULL) return; + very_first = NULL; + very_last = NULL; + last = NULL; + current = NULL; + ray_prev_ind = NULL; + for(i = 0; i < table->nindexes;i++) + { + if(table->indexes[i] != NULL) + { + if(ray_prev_ind != NULL) + { + /* Connect last ray in last index to first ray in + * this index. + */ + ray_prev_ind->ray_high = table->indexes[i]; + table->indexes[i]->ray_low = ray_prev_ind; + } + + /* Connect all entries in this indexes. Don't worry + * about ray angle order right now. + */ + current = table->indexes[i]; + while(current->next) + { + last = current; + current = current->next; + + last->ray_high = current; + current->ray_low = last; + } + + /* Set ray_high and ray_low so that entries are "sorted" */ + not_sorted_flag = 1; /* TRUE */ + while(not_sorted_flag) + { + current = table->indexes[i]; + not_sorted_flag = 0; /* FALSE */ + while(current->next) + { + /* last = current; */ + current = current->next; + + if(current->ray_low != NULL) + { + /* Someday want to test ray_angle */ + if(current->ray_low->ray->h.azimuth > current->ray->h.azimuth) + { + /* Need to switch the ray_high and ray_low + * pointers so that order is one three two four. + */ + not_sorted_flag = 1; /* TRUE */ + one = current->ray_low->ray_low; + two = current->ray_low; + three = current; + four = current->ray_high; + + if(one != NULL) one->ray_high = three; + two->ray_low = three; + two->ray_high = four; + three->ray_low = one; + three->ray_high = two; + if(four != NULL) four->ray_low = two; + } + } + } + } + + /* Save highest ray angle entry in index so that it may + * be connected to first entry of next index. The + * very_last pointer will be used to set very_first + * pointer. + */ + current = table->indexes[i]; + while(current->ray_high) current = current->ray_high; + ray_prev_ind = current; + very_last = current; + + /* If this is first non-NULL hash index, save lowest + * ray angle. + */ + if(very_first == NULL) + { + current = table->indexes[i]; + while(current->ray_low) current = current->ray_low; + very_first = current; + } + } + } + + /* Tie the first and last azimuth_hash's together. + * (Future If PPI_SWEEP statement....) + */ + very_first->ray_low = very_last; + very_last->ray_high = very_first; + } + + + +static Azimuth_hash *hash_add_node(Azimuth_hash *node, void *ray) +{ + Azimuth_hash *new_node; + + new_node = (Azimuth_hash *)calloc(1, sizeof(Azimuth_hash)); + if (new_node == NULL) perror("hash_add_node"); + else { + new_node->ray = ray; + new_node->next = node; + } + return new_node; +} + +Hash_table *construct_sweep_hash_table(Sweep *s) +{ + Hash_table *hash_table; + int i, iazim; + Ray *ray; + float res; + + if (s == NULL) return NULL; + hash_table = (Hash_table *) calloc(1, sizeof(Hash_table)); + hash_table->nindexes = s->h.nrays; + if (hash_table->nindexes < 0) { + fprintf(stderr, "Unable to construct sweep hash table because nrays = %d\n", s->h.nrays); + fprintf(stderr, "FATAL error... unable to continue.\n"); + exit(-1); + } + + res = 360.0 / hash_table->nindexes; + /* Check that this makes sense with beam width. */ + if ((res > 2*s->h.beam_width) && (s->h.beam_width != 0)) { + /* Problem. Too few rays so force a + * reasonable hash table size + */ + hash_table->nindexes = 360.0 / s->h.beam_width; + res = s->h.beam_width; + } + hash_table->indexes = (Azimuth_hash **)calloc(hash_table->nindexes, sizeof(Azimuth_hash *)); + if (hash_table->indexes == NULL) { + if (radar_verbose_flag) perror("construct_sweep_hash_table"); + return hash_table; + } + + for (i=0; ih.nrays; i++) { + ray = s->ray[i]; + if (ray == NULL) continue; + iazim = (int)(ray->h.azimuth/res + res/2.0); /* Centered on bin. */ + if (iazim >= hash_table->nindexes) iazim -= hash_table->nindexes ; + /* fprintf(stderr,"ray# %d, azim %f, iazim %d\n", ray->h.ray_num, ray->h.azimuth, iazim); */ + if (iazim > hash_table->nindexes || iazim < 0) { + if (radar_verbose_flag){ + fprintf(stderr,"ERROR: "); + fprintf(stderr,"ray# %d, azim %f, iazim %d, nrays %d, nindexes %d\n", ray->h.ray_num, ray->h.azimuth, iazim, s->h.nrays, hash_table->nindexes); + } + } else + hash_table->indexes[iazim] = hash_add_node(hash_table->indexes[iazim], ray); + + } + + set_high_and_low_pointers(hash_table); + return hash_table; +} + + diff --git a/read_write.c b/read_write.c new file mode 100644 index 0000000..644a7b2 --- /dev/null +++ b/read_write.c @@ -0,0 +1,382 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/**********************************************************************/ +/* */ +/* RSL_read_ray */ +/* RSL_read_sweep */ +/* RSL_read_volume */ +/* RSL_read_radar */ +/* */ +/* RSL_write_ray */ +/* RSL_write_sweep */ +/* RSL_write_volume */ +/* RSL_write_radar */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* April 7, 1994 */ +/**********************************************************************/ +#include +#include +#include "rsl.h" + +extern int radar_verbose_flag; +/**********************************************************************/ +/**********************************************************************/ +/* */ +/* I N P U T */ +/* */ +/**********************************************************************/ +/**********************************************************************/ + +Ray *RSL_read_ray(FILE *fp) +{ + char header_buf[512]; + Ray_header ray_h; + Ray *r; + int nbins; + + (void)fread(header_buf, sizeof(char), sizeof(header_buf), fp); + (void)fread(&nbins, sizeof(int), 1, fp); + if (nbins == 0) return NULL; + + memcpy(&ray_h, header_buf, sizeof(Ray_header)); + + r = RSL_new_ray(ray_h.nbins); + r->h = ray_h; + + (void)fread(r->range, sizeof(Range), r->h.nbins, fp); + return r; +} +Sweep *RSL_read_sweep(FILE *fp) +{ + char header_buf[512]; + Sweep_header sweep_h; + int i; + Sweep *s; + int nrays; + + (void)fread(header_buf, sizeof(char), sizeof(header_buf), fp); + + (void)fread(&nrays, sizeof(int), 1, fp); + if (nrays == 0) return NULL; + + if (radar_verbose_flag) + fprintf(stderr,"Reading %d rays. ", nrays); + memcpy(&sweep_h, header_buf, sizeof(Sweep_header)); + if (radar_verbose_flag) + fprintf(stderr,"From header info nrays = %d\n", sweep_h.nrays); + s = RSL_new_sweep(sweep_h.nrays); + s->h = sweep_h; + for (i=0; ih.nrays; i++) { + s->ray[i] = RSL_read_ray(fp); + } + return s; +} +Volume *RSL_read_volume(FILE *fp) +{ + char header_buf[512]; + Volume_header vol_h; + int i; + Volume *v; + int nsweeps; + + + + (void)fread(header_buf, sizeof(char), sizeof(header_buf), fp); + (void)fread(&nsweeps, sizeof(int), 1, fp); + if (nsweeps == 0) return NULL; + + if (radar_verbose_flag) + fprintf(stderr,"Reading %d sweeps. ", nsweeps); + memcpy(&vol_h, header_buf, sizeof(Volume_header)); + if (radar_verbose_flag) + fprintf(stderr,"From header info nsweeps = %d\n", vol_h.nsweeps); + v = RSL_new_volume(vol_h.nsweeps); + v->h = vol_h; + for (i=0; ih.nsweeps; i++) { + if (radar_verbose_flag) + fprintf(stderr,"RSL_read_sweep %d ", i); + v->sweep[i] = RSL_read_sweep(fp); + } + return v; +} + +Radar *set_default_function_pointers(Radar *radar) +{ + int i,j,k; + Volume *v; + Sweep *s; + Ray *r; + float (*f[MAX_RADAR_VOLUMES])(Range x); + Range (*invf[MAX_RADAR_VOLUMES])(float x); + f[DZ_INDEX] = DZ_F; + f[VR_INDEX] = VR_F; + f[SW_INDEX] = SW_F; + f[CZ_INDEX] = CZ_F; + f[ZT_INDEX] = ZT_F; + f[DR_INDEX] = DR_F; + f[LR_INDEX] = LR_F; + + invf[DZ_INDEX] = DZ_INVF; + invf[VR_INDEX] = VR_INVF; + invf[SW_INDEX] = SW_INVF; + invf[CZ_INDEX] = CZ_INVF; + invf[ZT_INDEX] = ZT_INVF; + invf[DR_INDEX] = DR_INVF; + invf[LR_INDEX] = LR_INVF; + + if (radar == NULL) return NULL; + for (i=0; ih.nvolumes; i++) { + v = radar->v[i]; + if (v) { + for (j=0; jh.nsweeps; j++) { + s = v->sweep[j]; + if (s) { + for (k=0; kh.nrays; k++) { + r = s->ray[k]; + if (r) { + r->h.f = f[i]; + r->h.invf = invf[i]; + } + } + s->h.f = f[i]; + s->h.invf = invf[i]; + } + } + v->h.f = f[i]; + v->h.invf = invf[i]; + } + } + return radar; +} + +Radar *RSL_read_radar(char *infile) +{ + /* On disk each header buffer size is this big to reserve space for + * any new members. This will make older radar files readable as + * development proceeds. + */ + char header_buf[512]; + Radar_header radar_h; + Radar *radar; + FILE *fp; + int i; + int nradar; + char title[100]; + + if ((fp = fopen(infile, "r")) == NULL) { + perror(infile); + return NULL; + } + fp = uncompress_pipe(fp); + (void)fread(title, sizeof(char), sizeof(title), fp); + if (strncmp(title, "RSL", 3) != 0) return NULL; + + (void)fread(header_buf, sizeof(char), sizeof(header_buf), fp); + memcpy(&radar_h, header_buf, sizeof(Radar_header)); + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + radar->h = radar_h; + + (void)fread(&nradar, sizeof(int), 1, fp); + if (radar_verbose_flag) + fprintf(stderr,"Reading %d volumes.\n", nradar); + + for (i=0; iv[i] = RSL_read_volume(fp); + } + + rsl_pclose(fp); + radar = set_default_function_pointers(radar); + return radar; +} + + +/**********************************************************************/ +/**********************************************************************/ +/* */ +/* O U T P U T */ +/* */ +/**********************************************************************/ +/**********************************************************************/ + +int RSL_write_ray(Ray *r, FILE *fp) +{ + char header_buf[512]; + int n = 0; + int zero = 0; + + memset(header_buf, 0, sizeof(header_buf)); + if (r == NULL) { + n += fwrite(header_buf, sizeof(header_buf), 1, fp) * sizeof(header_buf); + n += fwrite(&zero, sizeof(int), 1, fp) * sizeof(int); + return n; + } + memcpy(header_buf, &r->h, sizeof(r->h)); + n += fwrite(header_buf, sizeof(char), sizeof(header_buf), fp); + n += fwrite(&r->h.nbins, sizeof(int), 1, fp) * sizeof(int); + n += fwrite(r->range, sizeof(Range), r->h.nbins, fp) * sizeof(Range); + return n; +} +int RSL_write_sweep(Sweep *s, FILE *fp) +{ + char header_buf[512]; + int i; + int n = 0; + int zero = 0; + + + memset(header_buf, 0, sizeof(header_buf)); + if (s == NULL) { + n += fwrite(header_buf, sizeof(header_buf), 1, fp) * sizeof(header_buf); + n += fwrite(&zero, sizeof(int), 1, fp) * sizeof(int); + return n; + } + memcpy(header_buf, &s->h, sizeof(s->h)); + n += fwrite(header_buf, sizeof(char), sizeof(header_buf), fp); + if (radar_verbose_flag) + fprintf(stderr,"Expect to output %d rays.\n", s->h.nrays); + n += fwrite(&s->h.nrays, sizeof(int), 1, fp) * sizeof(int); + for (i=0; ih.nrays; i++) { + n += RSL_write_ray(s->ray[i], fp); + } + return n; +} +int RSL_write_volume(Volume *v, FILE *fp) +{ + char header_buf[512]; + int i; + int n = 0; + int zero = 0; + + memset(header_buf, 0, sizeof(header_buf)); + if (v == NULL) { /* Special case for missing volume. Volume type + * is identified by it ordinal within the array. + * See DZ_INDEX, VR_INDEX, and SW_INDEX in volume.h + */ + /* Write a place holder volume. Just an empty header will do since + * the reading code is data driven. + */ + n += fwrite(header_buf, sizeof(header_buf), 1, fp) * sizeof(header_buf); + n += fwrite(&zero, sizeof(int), 1, fp) * sizeof(int); + return n; + } + + memcpy(header_buf, &v->h, sizeof(v->h)); + n += fwrite(header_buf, sizeof(char), sizeof(header_buf), fp); + + if (radar_verbose_flag) + fprintf(stderr,"Expect to output %d sweeps.\n", v->h.nsweeps); + n += fwrite(&v->h.nsweeps, sizeof(int), 1, fp) * sizeof(int); + + for (i=0; ih.nsweeps; i++) { + if (radar_verbose_flag) + fprintf(stderr,"write_sweep %d ", i); + n += RSL_write_sweep(v->sweep[i], fp); + } + return n; +} + +int RSL_write_radar_fp(Radar *radar, FILE *fp) +{ + /* On disk each header buffer size is this big to reserve space for + * any new members. This will make older radar files readable as + * development proceeds. + */ + char header_buf[512]; + int i; + int n = 0; + int nradar; + char title[100]; + + if (radar == NULL) return 0; + + memset(title, 0, sizeof(title)); + (void)sprintf(title, "RSL v%s. sizeof(Range) %d", RSL_VERSION_STR, sizeof(Range)); + n += fwrite(title, sizeof(char), sizeof(title), fp); + + memset(header_buf, 0, sizeof(header_buf)); + memcpy(header_buf, &radar->h, sizeof(radar->h)); + n += fwrite(header_buf, sizeof(char), sizeof(header_buf), fp); + + nradar = radar->h.nvolumes; + n += fwrite(&nradar, sizeof(int), 1, fp) * sizeof(int); + if (radar_verbose_flag) + fprintf(stderr,"Number of volumes to write: %d\n", nradar); + + for (i=0; iv[i], fp); + + } + + if (radar_verbose_flag) + fprintf(stderr,"write_radar done. Wrote %d bytes.\n", n); + return n; +} +int RSL_write_radar(Radar *radar, char *outfile) +{ + /* On disk each header buffer size is this big to reserve space for + * any new members. This will make older radar files readable as + * development proceeds. + */ + FILE *fp; + int n; + + if (radar == NULL) return 0; + + if ((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + return -1; + } + n = RSL_write_radar_fp(radar, fp); + + (void)fclose(fp); + + return n; +} +int RSL_write_radar_gzip(Radar *radar, char *outfile) +{ + /* On disk each header buffer size is this big to reserve space for + * any new members. This will make older radar files readable as + * development proceeds. + */ + FILE *fp; + int n; + if (radar == NULL) return 0; + + if ((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + return -1; + } + fp = compress_pipe(fp); + n = RSL_write_radar_fp(radar, fp); + + rsl_pclose(fp); + + return n; +} + diff --git a/reverse.c b/reverse.c new file mode 100644 index 0000000..751047d --- /dev/null +++ b/reverse.c @@ -0,0 +1,48 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "rsl.h" +/*********************************************************************/ +/* */ +/* RSL_reverse_sweep_order */ +/* */ +/*********************************************************************/ +Volume *RSL_reverse_sweep_order(Volume *v) +{ +/* + * Reverse the order of the sweeps within the volume. + * This routine modifies the argument and does not allocate memory. + */ + + int i, j; + Sweep *s_tmp; + + if (v == NULL) return v; + /* Yes, the follwing is integer divide by 2. */ + for (i=0, j=v->h.nsweeps-1; ih.nsweeps/2; i++, j--) { + s_tmp = v->sweep[i]; + v->sweep[i] = v->sweep[j]; + v->sweep[j] = s_tmp; + } + + return v; +} diff --git a/rsl.h b/rsl.h new file mode 100644 index 0000000..358072c --- /dev/null +++ b/rsl.h @@ -0,0 +1,819 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996 John H. Merritt + Space Applications Corporation + Vienna, Virginia, a NASA/GSFC on-site contractor. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifndef _rsl_h +#define _rsl_h + +/* Are we building the library? */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define RSL_VERSION_STR "v1.40" + +/**********************************************************************/ +/* Configure: Define USE_TWO_BYTE_PRECISION to have RSL store internal*/ +/* values with two bytes. Otherwise, use one byte. */ +/* It is a good idea to use two byte precision. */ +/* See 'makefile' for an additional explaination. */ +/* */ +/**********************************************************************/ +#define USE_TWO_BYTE_PRECISION + + +/**********************************************************************/ +/* Configure: Define the file name of the red,green, and blue color */ +/* color tables. This maps reflectance to color. */ +/* This should be $(LIBDIR)/colors, from the makefile */ +/* so you shouldn't have to modify anything here. */ +/**********************************************************************/ +#ifndef COLORDIR +#define COLORDIR "/usr/local/trmm/GVBOX/lib/colors" +#endif + +/* These are the color table indexes. See RSL_set/get_color_table. */ +#define RSL_RED_TABLE 0 +#define RSL_GREEN_TABLE 1 +#define RSL_BLUE_TABLE 2 + +/* The default color tables for reflectivity, velocity, spectral width, + * height, rainfall, and zdr. + */ +#define REFL_RED_FILE COLORDIR "/red_reflectivity.clr" +#define REFL_GREEN_FILE COLORDIR "/grn_reflectivity.clr" +#define REFL_BLUE_FILE COLORDIR "/blu_reflectivity.clr" +#define VEL_RED_FILE COLORDIR "/red_velocity.clr" +#define VEL_GREEN_FILE COLORDIR "/grn_velocity.clr" +#define VEL_BLUE_FILE COLORDIR "/blu_velocity.clr" +#define SW_RED_FILE COLORDIR "/red_spectral_width.clr" +#define SW_GREEN_FILE COLORDIR "/grn_spectral_width.clr" +#define SW_BLUE_FILE COLORDIR "/blu_spectral_width.clr" +#define HEIGHT_RED_FILE COLORDIR "/red_height.clr" +#define HEIGHT_GREEN_FILE COLORDIR "/grn_height.clr" +#define HEIGHT_BLUE_FILE COLORDIR "/blu_height.clr" +#define RAINFALL_RED_FILE COLORDIR "/red_rainfall.clr" +#define RAINFALL_GREEN_FILE COLORDIR "/grn_rainfall.clr" +#define RAINFALL_BLUE_FILE COLORDIR "/blu_rainfall.clr" + +/* Added by D. Wolff 07/31/97 */ +#define ZDR_RED_FILE COLORDIR "/red_zdr.clr" +#define ZDR_GREEN_FILE COLORDIR "/grn_zdr.clr" +#define ZDR_BLUE_FILE COLORDIR "/blu_zdr.clr" + +/*************************************************************************/ +/* You should not have to change anything below this line. + * The rest is my fault. + */ +/*************************************************************************/ +#include + +/* + * Magic numbers. These are used to uniquely identify the type of + * values present in a particular structure: Volume, Sweep, Ray. + * The magic numbers V_DZ, V_VR, V_SW, etc. represent Volume magic + * numbers for the field types DZ, VR, SW, etc. Similiar magic numbers + * are implimented for Sweep, and Ray. The magic number is the first word + * of the data structure. These magic number may determine which conversion + * function is used, see volume.c and the end of this file for the + * conversion functions. (As of v0.39 -- NOT YET IMPLEMENTED.) + */ +enum Rsl_magic_num { + V_DZ, V_VR, V_SW, V_CZ, V_ZT, V_DR, V_LR, + S_DZ, S_VR, S_SW, S_CZ, S_ZT, S_DR, S_LR, + R_DZ, R_VR, R_SW, R_CZ, R_ZT, R_DR, R_LR +}; + +/* File format types recognized by RSL. */ +enum File_type {UNKNOWN, WSR88D_FILE, UF_FILE, LASSEN_FILE, + TOGA_FILE, NSIG_FILE_V1, NSIG_FILE_V2, + RSL_FILE, MCGILL_FILE, HDF_FILE, RAPIC_FILE, + RADTEC_FILE, EDGE_FILE, DORADE_FILE, RAINBOW_FILE}; + +/* Pick a BADVAL that is out of range. That is, the range + * of the conversion cannot include these reserved values. + * Typically, pick a number that cannot be stored in the Range data type. + */ +#ifdef USE_TWO_BYTE_PRECISION + typedef unsigned short Range; +#define BADVAL (float)0x20000 +#else + typedef unsigned char Range; +#define BADVAL (float)0500 /* non-meaningful value (500 octal) */ +#endif + +#define RFVAL (BADVAL-1) /* Range folded value. See rfival. */ +#define APFLAG (BADVAL-2) +#define NOTFOUND_H (BADVAL-3) +#define NOTFOUND_V (BADVAL-4) +#define NOECHO (BADVAL-5) /* For nsig and UF -32, for kwaj -30 */ +#define RSL_SPEED_OF_LIGHT 299792458.0 /* m/s */ + +typedef struct { + int month; /* Time for this ray; month (1-12). */ + int day; /* Time for this ray; day (1-31). */ + int year; /* Time for this ray; year (eg. 1993). */ + int hour; /* Date for this ray; hour (0-23). */ + int minute;/* Date for this ray; minute (0-59).*/ + float sec; /* Date for this ray; second + fraction of second. */ + float unam_rng; /* Unambiguous range. (KM). */ + float azimuth; /* Azimuth angle. (degrees). Must be positive + * 0=North, 90=east, -90/270=west. + * This angle is the mean azimuth for the whole ray. + * Eg. for NSIG the beginning and end azimuths are + * averaged. + */ + int ray_num; /* Ray no. within elevation scan. */ + float elev; /* Elevation angle. (degrees). */ + int elev_num; /* Elevation no. within volume scan. */ + + int range_bin1; /* Range to first gate.(meters) */ + int gate_size; /* Data gate size (meters)*/ + + float vel_res; /* Doppler velocity resolution */ + float sweep_rate; /* Sweep rate. Full sweeps/min. */ + + int prf; /* Pulse repetition frequency, in Hz. */ + float azim_rate; /* Sweep rate in degrees/sec. */ + float fix_angle; /* Elevation angle for the sweep. (degrees). */ + float pitch; /* Pitch angle. */ + float roll; /* Roll angle. */ + float heading; /* Heading. */ + float pitch_rate; /* (angle/sec) */ + float roll_rate; /* (angle/sec) */ + float heading_rate; /* (angle/sec) */ + float lat; /* Latitude (degrees) */ + float lon; /* Longitude (degrees) */ + int alt; /* Altitude (m) */ + float rvc; /* Radial velocity correction (m/sec) */ + float vel_east; /* Platform velocity to the east (m/sec) */ + float vel_north; /* Platform velocity to the north (m/sec) */ + float vel_up; /* Platform velocity toward up (m/sec) */ + int pulse_count; /* Pulses used in a single dwell time. */ + float pulse_width; /* Pulse width (micro-sec). */ + float beam_width; /* Beamwidth in degrees. */ + float frequency; /* Carrier freq. GHz. */ + float wavelength; /* Wavelength. Meters. */ + float nyq_vel; /* Nyquist velocity. m/s */ + float (*f)(Range x); /* Data conversion function. f(x). */ + Range (*invf)(float x); /* Data conversion function. invf(x). */ + int nbins; /* Number of array elements for 'Range'. */ +} Ray_header; + + +typedef struct { + Ray_header h; + Range *range; /* range[0..nbins-1] + * For wsr88d file: + * 0..460 for reflectivity, 0..920 for velocity and + * spectrum width. + */ + } Ray; + + +typedef struct _azimuth_hash { + Ray *ray; + struct _azimuth_hash *next, *ray_high, *ray_low; +} Azimuth_hash; + +typedef struct { + Azimuth_hash **indexes; + int nindexes; +} Hash_table; + + +typedef struct { + int sweep_num; /* Integer sweep number. This may be redundant, since + * this will be the same as the Volume.sweep array index.*/ + float elev; /* Elevation angle (mean) for the sweep. */ + float beam_width; /* This is in the ray header too. */ + float vert_half_bw; /* Vertical beam width divided by 2 */ + float horz_half_bw; /* Horizontal beam width divided by 2 */ + + int nrays; + float (*f)(Range x); /* Data conversion function. f(x). */ + Range (*invf)(float x); /* Data conversion function. invf(x). */ +} Sweep_header; + +typedef struct { + Sweep_header h; + Ray **ray; /* ray[0..nrays-1]. */ +} Sweep; + +typedef struct { + char *type_str; /* One of:'Reflectivity', 'Velocity' or 'Spectrum width' */ + int nsweeps; + float calibr_const; /* Calibration constant. HDF specific. */ + float (*f)(Range x); /* Data conversion function. f(x). */ + Range (*invf)(float x); /* Data conversion function. invf(x). */ +} Volume_header; + +typedef struct { + Volume_header h; /* Specific info for each elev. */ + /* Includes resolution: km/bin. */ + Sweep **sweep; /* sweep[0..nsweeps-1]. */ +} Volume; + + + +typedef Range Carpi_value; +typedef Range Cappi_value; + +typedef struct { + int month; /* (1-12). */ + int day; /* (1-31). */ + int year; /* (eg. 1993). */ + int hour; /* (0-23). */ + int minute; /* (0-59).*/ + float sec; /* second + fraction of second. */ + float dx, dy; /* Size of cell in km. */ + int nx, ny; /* Number of cells. */ + int radar_x, radar_y; /* Location of center of radar. */ + float height; /* Height of this Carpi. */ + float lat, lon; /* Lat/lon of lower left corner of Carpi. */ + char radar_type[50]; /* Radar types. */ + int field_type; /* Same as for Radar. */ + int interp_method; /* ??? string describing interpolation method. */ + float (*f)(Carpi_value x); /* Data conversion function. f(x). */ + Carpi_value (*invf)(float x); /* Data conversion function. invf(x). */ + Carpi_value **data; /* data[ny][nx] */ +} Carpi; + +/** Cappi data structure info **/ +/* Paul A. Kucera **/ + +/* Element in location array of Cappi data structure. + * Each element is elvation and range to data value. + */ +typedef struct + { + float elev; /* elevation angle */ + float srange; /* slant range !!! */ + } +Er_loc; + +/* Cappi data structure. + */ +typedef struct { + int month; /* Begin time for this Cappi; month (1-12). */ + int day; /* Begin time for this Cappi; day (1-31). */ + int year; /* Begin time for this Cappi; year (eg. 1993). */ + int hour; /* Begin date for this Cappi; hour (0-23). */ + int minute; /* Begin date for this Cappi; minute (0-59).*/ + float sec; /* Begin date for this Cappi; second + frac. of second.*/ + float height; /* Height for this Cappi in m */ + float lat; + float lon; + int field_type; /* Value of Constant ??_INDEX */ + char radar_type[50]; /* Value of Constant radar->h.radar_type */ + int interp_method; /* ??? string describing interpolation method. */ + Er_loc *loc; /* elevation and range coordinate array */ + Sweep *sweep; /* Pointers to rays of data */ +} Cappi; + +/* The Cube data type. */ + +typedef Range Cube_value; +typedef Range Slice_value; + +typedef struct +{ + float lat, lon; + float dx, dy, dz; + int nx, ny, nz; + char *data_type; + Carpi **carpi; /* Pointers to carpi[0] thru carpi[nz-1] */ +} Cube; + +typedef struct +{ + float dx, dy; + int nx, ny; + char *data_type; + float (*f)(Slice_value x); /* Data conversion function. f(x). */ + Slice_value (*invf)(float x); /* Data conversion function. invf(x). */ + Slice_value **data; /* data[ny][nx]. */ +} Slice; + +typedef struct { + int nbins; + int low; + int hi; + int ucount; + int ccount; + int *data; +} Histogram; + +typedef struct { + int month, day, year; + int hour, minute; + float sec; /* Second plus fractional part. */ + char radar_type[50]; /* Type of radar. Use for QC-ing the data. + * Supported types are: + * "wsr88d", "lassen", "uf", + * "nsig", "mcgill", + * "kwajalein", "rsl", "toga", + * "rapic", (rapic is Berrimah Austrailia) + * "radtec", (SPANDAR radar at Wallops Is, VA) + * "EDGE", + * "dorade", + * "south_africa". + * Set by appropriate ingest routine. + */ + int nvolumes; + + int number; /* arbitrary number of this radar site */ + char name[8]; /* Nexrad site name */ + char radar_name[8]; /* Radar name. */ + char project[24]; /* Project identifier. */ + char city[15]; /* nearest city to radar site */ + char state[3]; /* state of radar site */ + char country[15]; + int latd; /* degrees of latitude of site */ + int latm; /* minutes of latitude of site */ + int lats; /* seconds of latitude of site */ + int lond; /* degrees of longitude of site */ + int lonm; /* minutes of longitude of site */ + int lons; /* seconds of longitude of site */ + int height; /* height of site in meters above sea level*/ + int spulse; /* length of short pulse (ns)*/ + int lpulse; /* length of long pulse (ns) */ + int vcp; /* Volume Coverage Pattern (for WSR-88D only) */ +} Radar_header; + + +typedef struct { + Radar_header h; + Volume **v; /* Array 0..nvolumes-1 of pointers to Volumes. + * 0 = DZ_INDEX = reflectivity. + * 1 = VR_INDEX = velocity. + * 2 = SW_INDEX = spectrum_width. + * 3 = CZ_INDEX = corrected reflectivity. + * 4 = ZT_INDEX = uncorrected reflectivity. + * 5 = DR_INDEX = differential refl. + * 6 = LR_INDEX = another differential refl. + * 7 = ZD_INDEX = another differential refl. + * 8 = DM_INDEX = received power. + * 9 = RH_INDEX = RhoHV: Horz-Vert power corr coeff + *10 = PH_INDEX = PhiDP: Differential phase angle + *11 = XZ_INDEX = X-band reflectivity. + *12 = CR_INDEX = Corrected DR. + *13 = MZ_INDEX = DZ mask for 1C-51 HDF. + *14 = MR_INDEX = DR mask for 1C-51 HDF. + *15 = ZE_INDEX = Edited reflectivity. + *16 = VE_INDEX = Edited velocity. + *17 = KD_INDEX = KDP: Specific differential phase, deg/km. + *18 = TI_INDEX = TIME (unknown) for MCTEX data. + *19 = DX_INDEX + *20 = CH_INDEX + *21 = AH_INDEX + *22 = CV_INDEX + *23 = AV_INDEX + *24 = SQ_INDEX = Signal Quality Index (Sigmet) + */ + +} Radar; + +/* + * DZ Reflectivity (dBZ), may contain some DZ_INDEX + * signal-processor level QC and/or + * filters. This field would contain + * Darwin's CZ, or WSR88D's standard + * reflectivity. In other words, unless + * the field is described otherwise, it + * should always go here. In essence, this + * is the "cleanest" reflectivity field + * for a radar. + * + * VR Radial Velocity (m/s) VR_INDEX + * + * SW Spectral Width (m2/s2) SW_INDEX + * + * CZ QC Reflectivity (dBZ), contains + * post-processed QC'd data CZ_INDEX + * + * ZT Total Reflectivity (dBZ) ZT_INDEX + * Reflectivity unfiltered for clutter... + * This is UZ in UF files. + * + * DR Differential reflectivity DR_INDEX + * DR and LR are for dual-polarization + * radars only. Unitless or in dB. + * + * LR Another form of differential ref LR_INDEX + * called LDR, not sure of units + * + * ZD ZDR: Reflectivity Depolarization Ratio ZD_INDEX + * ZDR = 10log(ZH/ZV) (dB) + * + * DM Received power measured by the radar. DM_INDEX + * Units are dBm. + * + * RH RhoHV: Horz-Vert power correlation RH_INDEX + * coefficient. (0 to 1) See volume.c + * + * PH PhiDP: Differential phase angle. PH_INDEX + * (0 to 180 deg in steps of 0.71) + * See volume.c + * + * XZ X-band reflectivity XZ_INDEX + * + * CD Corrected ZD reflectivity (differential) CD_INDEX + * contains QC'ed data + * + * MZ DZ mask volume for HDF 1C-51 product. MZ_INDEX + * + * MD ZD mask volume for HDF 1C-51 product. MD_INDEX + * + * ZE Edited Reflectivity. ZE_INDEX + * + * VE Edited Velocity. VE_INDEX + * + * KD KDP (deg/km) Differencial Phase KD_INDEX + * [Sigmet, Lassen] + * + * TI TIME (unknown) for MCTEX data. TI_INDEX + * SQ SQI: Signal Quality Index. [Sigmet] SQ_INDEX + * Decimal fraction from 0 to 1, where 0 + * is noise, 1 is noiseless. + */ + +/* + * The number of *_INDEX must never exceed MAX_RADAR_VOLUMES. + * Increase MAX_RADAR_VOLUMES appropriately, for new ingest formats. + */ +#define MAX_RADAR_VOLUMES 25 + +#define DZ_INDEX 0 +#define VR_INDEX 1 +#define SW_INDEX 2 +#define CZ_INDEX 3 +#define ZT_INDEX 4 +#define DR_INDEX 5 +#define LR_INDEX 6 +#define ZD_INDEX 7 +#define DM_INDEX 8 +#define RH_INDEX 9 +#define PH_INDEX 10 +#define XZ_INDEX 11 +#define CD_INDEX 12 +#define MZ_INDEX 13 +#define MD_INDEX 14 +#define ZE_INDEX 15 +#define VE_INDEX 16 +#define KD_INDEX 17 +#define TI_INDEX 18 +#define DX_INDEX 19 +#define CH_INDEX 20 +#define AH_INDEX 21 +#define CV_INDEX 22 +#define AV_INDEX 23 +#define SQ_INDEX 24 + + +/* Prototypes for functions. */ +/* Alphabetical and grouped by object returned. */ + + +Radar *RSL_africa_to_radar(char *infile); +Radar *RSL_anyformat_to_radar(char *infile, ...); +Radar *RSL_dorade_to_radar(char *infile); +Radar *RSL_EDGE_to_radar(char *infile); +Radar *RSL_fix_radar_header(Radar *radar); +Radar *RSL_get_window_from_radar(Radar *r, float min_range, float max_range,float low_azim, float hi_azim); +Radar *RSL_hdf_to_radar(char *infile); +Radar *RSL_hdf_to_radar_unQC(char *infile); +Radar *RSL_kwaj_to_radar(char *infile); +Radar *RSL_lassen_to_radar(char *infile); +Radar *RSL_mcgill_to_radar(char *infile); +Radar *RSL_new_radar(int nvolumes); +Radar *RSL_nsig_to_radar(char *infile); +Radar *RSL_nsig2_to_radar(char *infile); +Radar *RSL_prune_radar(Radar *radar); +Radar *RSL_radtec_to_radar(char *infile); +Radar *RSL_rainbow_to_radar(char *infile); +Radar *RSL_rapic_to_radar(char *infile); +Radar *RSL_read_radar(char *infile); +Radar *RSL_sort_radar(Radar *r); +Radar *RSL_toga_to_radar(char *infile); +Radar *RSL_uf_to_radar(char *infile); +Radar *RSL_uf_to_radar_fp(FILE *fp); +Radar *RSL_wsr88d_to_radar(char *infile, char *call_or_first_tape_file); + +Volume *RSL_clear_volume(Volume *v); +Volume *RSL_copy_volume(Volume *v); +Volume *RSL_fix_volume_header(Volume *v); +Volume *RSL_get_volume(Radar *r, int type_wanted); +Volume *RSL_get_window_from_volume(Volume *v, float min_range, float max_range, float low_azim, float hi_azim); +Volume *RSL_new_volume(int max_sweeps); +Volume *RSL_prune_volume(Volume *v); +Volume *RSL_read_volume(FILE *fp); +Volume *RSL_reverse_sweep_order(Volume *v); +Volume *RSL_sort_rays_in_volume(Volume *v); +Volume *RSL_sort_sweeps_in_volume(Volume *v); +Volume *RSL_sort_volume(Volume *v); +Volume *RSL_volume_z_to_r(Volume *z_volume, float k, float a); + +Sweep *RSL_clear_sweep(Sweep *s); +Sweep *RSL_copy_sweep(Sweep *s); +Sweep *RSL_fix_sweep_header(Sweep *sweep); +Sweep *RSL_get_closest_sweep(Volume *v,float sweep_angle,float limit); +Sweep *RSL_get_eth_sweep(Volume *v,float et_point,float max_range); +Sweep *RSL_get_first_sweep_of_volume(Volume *v); +Sweep *RSL_get_sweep(Volume *v, float elev); +Sweep *RSL_get_window_from_sweep(Sweep *s, float min_range, float max_range, float low_azim, float hi_azim); + +Sweep *RSL_new_sweep(int max_rays); +Sweep *RSL_prune_sweep(Sweep *s); +Sweep *RSL_read_sweep (FILE *fp); +Sweep *RSL_sort_rays_in_sweep(Sweep *s); +Sweep *RSL_sort_rays_by_time(Sweep *s); +Sweep *RSL_sweep_z_to_r(Sweep *z_sweep, float k, float a); + +Ray *RSL_clear_ray(Ray *r); +Ray *RSL_copy_ray(Ray *r); +Ray *RSL_get_closest_ray_from_sweep(Sweep *s,float ray_angle,float limit); +Ray *RSL_get_first_ray_of_sweep(Sweep *s); +Ray *RSL_get_first_ray_of_volume(Volume *v); +Ray *RSL_get_closest_ray_from_sweep(Sweep *s,float ray_angle,float limit); +Ray *RSL_get_next_ccwise_ray(Sweep *s, Ray *ray); +Ray *RSL_get_next_cwise_ray(Sweep *s, Ray *ray); +Ray *RSL_get_ray(Volume *v, float elev, float azimuth); +Ray *RSL_get_ray_above(Volume *v, Ray *current_ray); +Ray *RSL_get_ray_below(Volume *v, Ray *current_ray); +Ray *RSL_get_ray_from_sweep(Sweep *s, float azim); +Ray *RSL_get_window_from_ray(Ray *r, float min_range, float max_range, float low_azim, float hi_azim); +Ray *RSL_new_ray(int max_bins); +Ray *RSL_prune_ray(Ray *ray); +Ray *RSL_ray_z_to_r(Ray *z_ray, float k, float a); +Ray *RSL_read_ray (FILE *fp); + + +float RSL_area_of_ray(Ray *r, float lo, float hi, float min_range, float max_range); +float RSL_fraction_of_ray(Ray *r, float lo, float hi, float range); +float RSL_fraction_of_sweep(Sweep *s, float lo, float hi, float range); +float RSL_fraction_of_volume(Volume *v, float lo, float hi, float range); +float RSL_fractional_area_of_sweep(Sweep *s, float lo, float hi, float min_rng, float max_rng); +float RSL_get_echo_top_height(Volume *v,float azim,float grange, float et_point); +float RSL_get_linear_value(Volume *v,float srange,float azim,float elev,float limit); +float RSL_get_nyquist_from_radar(Radar *radar); +float RSL_get_range_of_range_index(Ray *ray, int index); +float RSL_get_value(Volume *v, float elev, float azimuth, float range); +float RSL_get_value_at_h(Volume *v, float azim, float grnd_r, float h); +float RSL_get_value_from_cappi(Cappi *cappi, float rng, float azm); +float RSL_get_value_from_ray(Ray *ray, float r); +float RSL_get_value_from_sweep(Sweep *s, float azim, float r); +float RSL_z_to_r(float z, float k, float a); + +int RSL_fill_cappi(Volume *v, Cappi *cap, int method); +int RSL_get_ray_index_from_sweep(Sweep *s, float azim,int *next_closest); +int RSL_get_sweep_index_from_volume(Volume *v, float elev,int *next_closest); +int RSL_radar_to_hdf(Radar *radar, char *outfile); +int RSL_write_histogram(Histogram *histogram, char *outfile); +int RSL_write_ray(Ray *r, FILE *fp); +int RSL_write_sweep(Sweep *s, FILE *fp); +int RSL_write_radar(Radar *radar, char *outfile); +int RSL_write_radar_gzip(Radar *radar, char *outfile); +int RSL_write_volume(Volume *v, FILE *fp); + +unsigned char *RSL_rhi_sweep_to_cart(Sweep *s, int xdim, int ydim, float range, + int vert_scale); +unsigned char *RSL_sweep_to_cart(Sweep *s, int xdim, int ydim, float range); + +void RSL_add_dbz_offset_to_ray(Ray *r, float dbz_offset); +void RSL_add_dbz_offset_to_sweep(Sweep *s, float dbz_offset); +void RSL_add_dbz_offset_to_volume(Volume *v, float dbz_offset); +void RSL_bscan_ray(Ray *r, FILE *fp); +void RSL_bscan_sweep(Sweep *s, char *outfile); +void RSL_bscan_volume(Volume *v, char *basename); +void RSL_find_rng_azm(float *r, float *ang, float x, float y); +void RSL_fix_time (Ray *ray); +void RSL_float_to_char(float *x, Range *c, int n); + +void RSL_free_cappi(Cappi *c); +void RSL_free_carpi(Carpi *carpi); +void RSL_free_cube(Cube *cube); +void RSL_free_histogram(Histogram *histogram); +void RSL_free_ray(Ray *r); +void RSL_free_slice(Slice *slice); +void RSL_free_sweep(Sweep *s); +void RSL_free_radar(Radar *r); +void RSL_free_volume(Volume *v); +void RSL_get_color_table(int icolor, char buffer[256], int *ncolors); +void RSL_get_groundr_and_h(float slant_r, float elev, float *gr, float *h); +void RSL_get_slantr_and_elev(float gr, float h, float *slant_r, float *elev); +void RSL_get_slantr_and_h(float gr, float elev, float *slant_r, float *h); +void RSL_load_color_table(char *infile, char buffer[256], int *ncolors); +void RSL_load_height_color_table(); +void RSL_load_rainfall_color_table(); +void RSL_load_refl_color_table(); +void RSL_load_vel_color_table(); +void RSL_load_sw_color_table(); +void RSL_load_zdr_color_table(); +void RSL_load_red_table(char *infile); +void RSL_load_green_table(char *infile); +void RSL_load_blue_table(char *infile); +void RSL_print_histogram(Histogram *histogram, int min_range, int max_range, + char *filename); +void RSL_print_version(); +void RSL_radar_to_uf(Radar *r, char *outfile); +void RSL_radar_to_uf_gzip(Radar *r, char *outfile); +void RSL_radar_verbose_off(void); +void RSL_radar_verbose_on(void); +void RSL_read_these_sweeps(char *csweep, ...); +void RSL_rebin_velocity_ray(Ray *r); +void RSL_rebin_velocity_sweep(Sweep *s); +void RSL_rebin_velocity_volume(Volume *v); +void RSL_rebin_zdr_ray(Ray *r); +void RSL_rebin_zdr_sweep(Sweep *s); +void RSL_rebin_zdr_volume(Volume *v); +void RSL_rhi_sweep_to_gif(Sweep *s, char *outfile, int xdim, int ydim, float range, + int vert_scale); +void RSL_select_fields(char *field_type, ...); +void RSL_set_color_table(int icolor, char buffer[256], int ncolors); +void RSL_sweep_to_gif(Sweep *s, char *outfile, int xdim, int ydim, float range); +void RSL_sweep_to_pgm(Sweep *s, char *outfile, int xdim, int ydim, float range); +void RSL_sweep_to_pict(Sweep *s, char *outfile, int xdim, int ydim, float range); +void RSL_sweep_to_ppm(Sweep *s, char *outfile, int xdim, int ydim, float range); +void RSL_volume_to_gif(Volume *v, char *basename, int xdim, int ydim, float range); +void RSL_volume_to_pgm(Volume *v, char *basename, int xdim, int ydim, float range); +void RSL_volume_to_pict(Volume *v, char *basename, int xdim, int ydim, float range); +void RSL_volume_to_ppm(Volume *v, char *basename, int xdim, int ydim, float range); +void RSL_write_gif(char *outfile, unsigned char *image, + int xdim, int ydim, char c_table[256][3]); +void RSL_write_pgm(char *outfile, unsigned char *image, + int xdim, int ydim); +void RSL_write_pict(char *outfile, unsigned char *image, + int xdim, int ydim, char c_table[256][3]); +void RSL_write_ppm(char *outfile, unsigned char *image, + int xdim, int ydim, char c_table[256][3]); + + +Cappi *RSL_new_cappi(Sweep *sweep, float height); +Cappi *RSL_cappi_at_h(Volume *v, float height, float max_range); + +Carpi *RSL_cappi_to_carpi(Cappi *cappi, float dx, float dy, + float lat, float lon, + int nx, int ny, int radar_x, int radar_y); +Carpi *RSL_new_carpi(int nrows, int ncols); +Carpi *RSL_volume_to_carpi(Volume *v, float h, float grnd_r, + float dx, float dy, int nx, int ny, + int radar_x, int radar_y, float lat, float lon); + +Cube *RSL_new_cube(int ncarpi); +Cube *RSL_volume_to_cube(Volume *v, float dx, float dy, float dz, + int nx, int ny, int nz, float grnd_r, + int radar_x, int radar_y, int radar_z); + +Slice *RSL_new_slice(int nrows, int ncols); +Slice *RSL_get_slice_from_cube(Cube *cube, int x, int y, int z); + + +Histogram *RSL_allocate_histogram(int low, int hi); +Histogram *RSL_get_histogram_from_ray(Ray *ray, Histogram *histogram, + int low, int hi, int min_range, + int max_range); +Histogram *RSL_get_histogram_from_sweep(Sweep *sweep, Histogram *histogram, + int low, int hi, int min_range, + int max_range); +Histogram *RSL_get_histogram_from_volume(Volume *volume, Histogram *histogram, + int low, int hi, int min_range, + int max_range); +Histogram *RSL_read_histogram(char *infile); + +int no_command (char *cmd); +FILE *uncompress_pipe (FILE *fp); +FILE *compress_pipe (FILE *fp); +int rsl_pclose(FILE *fp); + +/* Carpi image generation functions. These are modified clones of the + corresponding sweep image generation functions. +*/ +unsigned char *RSL_carpi_to_cart(Carpi *carpi, int xdim, int ydim, + float range); +void RSL_carpi_to_gif(Carpi *carpi, char *outfile, int xdim, int ydim, + float range); +void RSL_carpi_to_pict(Carpi *carpi, char *outfile, int xdim, int ydim, + float range); +void RSL_carpi_to_ppm(Carpi *carpi, char *outfile, int xdim, int ydim, + float range); +void RSL_carpi_to_pgm(Carpi *carpi, char *outfile, int xdim, int ydim, + float range); + +/* Internal storage conversion functions. These may be any conversion and + * may be dynamically defined; based on the input data conversion. + */ +float DZ_F(Range x); +float VR_F(Range x); +float SW_F(Range x); +float CZ_F(Range x); +float ZT_F(Range x); +float DR_F(Range x); +float LR_F(Range x); +float ZD_F(Range x); +float DM_F(Range x); +float RH_F(Range x); +float PH_F(Range x); +float XZ_F(Range x); +float CD_F(Range x); +float MZ_F(Range x); +float MD_F(Range x); +float ZE_F(Range x); +float VE_F(Range x); +float KD_F(Range x); +float TI_F(Range x); +float DX_F(Range x); +float CH_F(Range x); +float AH_F(Range x); +float CV_F(Range x); +float AV_F(Range x); +float SQ_F(Range x); + +Range DZ_INVF(float x); +Range VR_INVF(float x); +Range SW_INVF(float x); +Range CZ_INVF(float x); +Range ZT_INVF(float x); +Range DR_INVF(float x); +Range LR_INVF(float x); +Range ZD_INVF(float x); +Range DM_INVF(float x); +Range RH_INVF(float x); +Range PH_INVF(float x); +Range XZ_INVF(float x); +Range CD_INVF(float x); +Range MZ_INVF(float x); +Range MD_INVF(float x); +Range ZE_INVF(float x); +Range VE_INVF(float x); +Range KD_INVF(float x); +Range TI_INVF(float x); +Range DX_INVF(float x); +Range CH_INVF(float x); +Range AH_INVF(float x); +Range CV_INVF(float x); +Range AV_INVF(float x); +Range SQ_INVF(float x); + + +/* If you like these variables, you can use them in your application + * by defining USE_RSL_VARS before #include "rsl.h" + */ +#ifdef USE_RSL_VARS +static char *RSL_ftype[] = {"DZ", "VR", "SW", "CZ", "ZT", "DR", + "LR", "ZD", "DM", "RH", "PH", "XZ", + "CD", "MZ", "MD", "ZE", "VE", "KD", + "TI", "DX", "CH", "AH", "CV", "AV", + "SQ"}; + +static float (*RSL_f_list[])(Range x) = {DZ_F, VR_F, SW_F, CZ_F, ZT_F, DR_F, + LR_F, ZD_F, DM_F, RH_F, PH_F, XZ_F, + CD_F, MZ_F, MD_F, ZE_F, VE_F, KD_F, + TI_F, DX_F, CH_F, AH_F, CV_F, AV_F, + SQ_F}; + +static Range (*RSL_invf_list[])(float x) + = {DZ_INVF, VR_INVF, SW_INVF, CZ_INVF, ZT_INVF, DR_INVF, + LR_INVF, ZD_INVF, DM_INVF, RH_INVF, PH_INVF, XZ_INVF, + CD_INVF, MZ_INVF, MD_INVF, ZE_INVF, VE_INVF, KD_INVF, + TI_INVF, DX_INVF, CH_INVF, AH_INVF, CV_INVF, AV_INVF, + SQ_INVF}; +#endif +/* Secret routines that are quite useful and useful to developers. */ +void radar_load_date_time(Radar *radar); +int big_endian(void); +int little_endian(void); +void swap_4_bytes(void *word); +void swap_2_bytes(void *word); +Hash_table *hash_table_for_sweep(Sweep *s); +int hash_bin(Hash_table *table,float angle); +Azimuth_hash *the_closest_hash(Azimuth_hash *hash, float ray_angle); +Hash_table *construct_sweep_hash_table(Sweep *s); +double angle_diff(float x, float y); +int rsl_query_field(char *c_field); + + +/* Debugging prototypes. */ +void poke_around_volume(Volume *v); + +/* SYSTEM: left out prototypes? */ +extern int pclose (FILE *f); /* From stdio.h */ + +#endif diff --git a/sort_rays.c b/sort_rays.c new file mode 100644 index 0000000..0c24531 --- /dev/null +++ b/sort_rays.c @@ -0,0 +1,235 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/*-----------------------------------------------------------------*/ +/* */ +/* ray_sort_compare */ +/* RSL_sort_rays_in_sweep */ +/* RSL_sort_rays_in_volume */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* August 26, 1994 */ +/* + * Update and Revisions: + * + * New Routines: + * int ray_sort_compare_by_time(Ray **r1,Ray **r2); + * int sweep_sort_compare(Sweep **s1, Sweep **s2) + * Sweep *RSL_sort_rays_by_time(Sweep *s); + * Volume *RSL_sort_sweeps_in_volume(Volume *v) + * Volume *RSL_sort_volume(Volume *v) + * Radar *RSL_sort_radar(Radar *r) + * + * Modifications: + * Routines that sort data structures now set the + * number of structures in the parent data structure. + * + * Routines set the enum sorted variable in the + * appropriate data structure. + * + * Dennis Flanigan,Jr. + * 3/23/95 + */ +/*-----------------------------------------------------------------*/ + +#include +#include "rsl.h" + +static int ray_sort_compare(Ray **r1, Ray **r2) + { + /* Compare azim values. Return -1, 0, 1 for <, =, > comparison. */ + if (*r1 == NULL) return 1; + if (*r2 == NULL) return -1; + + if ((*r1)->h.azimuth < (*r2)->h.azimuth) return -1; + if ((*r1)->h.azimuth > (*r2)->h.azimuth) return 1; + return 0; + } + + +static int ray_sort_compare_by_time(Ray **r1, Ray **r2) + { + /* Compare time values. Return -1, 0, 1 for <, =, > comparison. */ + + if (*r1 == NULL) return 1; + if (*r2 == NULL) return -1; + + /* Compare year value */ + if ((*r1)->h.year < (*r2)->h.year) return -1; + if ((*r1)->h.year > (*r2)->h.year) return 1; + + /* Compare month value */ + if ((*r1)->h.month < (*r2)->h.month) return -1; + if ((*r1)->h.month > (*r2)->h.month) return 1; + + /* Compare day value */ + if ((*r1)->h.day < (*r2)->h.day) return -1; + if ((*r1)->h.day > (*r2)->h.day) return 1; + + /* Compare hour value */ + if ((*r1)->h.hour < (*r2)->h.hour) return -1; + if ((*r1)->h.hour > (*r2)->h.hour) return 1; + + /* Compare minute value */ + if ((*r1)->h.minute < (*r2)->h.minute) return -1; + if ((*r1)->h.minute > (*r2)->h.minute) return 1; + + /* Compare second value */ + if ((*r1)->h.sec < (*r2)->h.sec) return -1; + if ((*r1)->h.sec > (*r2)->h.sec) return 1; + + return 0; + } + +static int sweep_sort_compare(Sweep **s1, Sweep **s2) + { + /* Compare elevation values. Return -1, 0, 1 for <, =, > comparison. */ + if (*s1 == NULL) return 1; + if (*s2 == NULL) return -1; + + if ((*s1)->h.elev < (*s2)->h.elev) return -1; + if ((*s1)->h.elev > (*s2)->h.elev) return 1; + return 0; + } + +Sweep *RSL_sort_rays_in_sweep(Sweep *s) + { + /* Sort rays by azimuth in passed sweep */ + int a; + + if (s == NULL) return NULL; + + qsort((void *)s->ray, s->h.nrays, sizeof(Ray *), + (int (*)(const void *, const void *))ray_sort_compare); + + /* Set nrays values to number of non-NULL indexes. + * After sorting this is highest useable index. + */ + for(a=s->h.nrays-1; a>=0 ;a--) { + if(s->ray[a] != NULL) { + s->h.nrays = a+1; + break; + } + } + + return s; + } + +Sweep *RSL_sort_rays_by_time(Sweep *s) + { + /* Set rays in passed sweep by time */ + int a; + + if (s == NULL) return NULL; + + qsort((void *)s->ray, s->h.nrays, sizeof(Ray *), + (int (*)(const void *, const void *))ray_sort_compare_by_time); + + /* Set nrays values to number of non-NULL indexes. + * After sorting this is highest useable index. + */ + for(a=s->h.nrays-1; a>=0 ;a--) { + if(s->ray[a] != NULL) { + s->h.nrays = a+1; + break; + } + } + + return s; + } + + +Volume *RSL_sort_rays_in_volume(Volume *v) + { + /* Sort rays in the sweeps pointed to by the volume . + * (Does not sort the sweeps pointers) + */ + int i; + if (v == NULL) return NULL; + + for (i=0; ih.nsweeps; i++) + v->sweep[i] = RSL_sort_rays_in_sweep(v->sweep[i]); + + return v; + } + +Volume *RSL_sort_sweeps_in_volume(Volume *v) + { + /* Sort sweeps pointers in passed volume data structure. + * (Does not sort rays in sweeps.) + */ + int a; + + if (v == NULL) return NULL; + + qsort((void *)v->sweep,v->h.nsweeps,sizeof(Sweep *), + (int (*)(const void *, const void *))sweep_sort_compare); + + /* Set nsweeps value to number of non-NULL indexes. + * After sorting, this is the highest usable index. + */ + for(a=0;ah.nsweeps;a++) + { + if(v->sweep[a] == NULL) + { + v->h.nsweeps = a; + break; + } + } + + return v; + } + +Volume *RSL_sort_volume(Volume *v) + { + /* Sort sweeps and rays by angle in the Volume data structure + * passed. + */ + + if(v == NULL) return NULL; + + v = RSL_sort_sweeps_in_volume(v); + v = RSL_sort_rays_in_volume(v); + + return v; + } + + +Radar *RSL_sort_radar(Radar *r) + { + /* Sort sweeps and rays in all Volumes of the passed Radar data + * structure. + */ + int a; + + if(r == NULL) return NULL; + + for(a=0; ah.nvolumes;a++) + { + r->v[a] = RSL_sort_volume(r->v[a]); + } + + return r; + } + + diff --git a/toga.c b/toga.c new file mode 100644 index 0000000..38edd6b --- /dev/null +++ b/toga.c @@ -0,0 +1,808 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1992 Dennis F. Flanigan Jr. of Applied Research Corporation, + Landover, Maryland, a NASA/GSFC on-site contractor. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* toga/old sigmet/Darwin access routines + * V1.0 12/15/93 by John Merritt. + * + * 1. Use CFLAGS = -DUSE_PLOG if you want to use the PLOG library. + *---------------------------------------------------------------------- + * + * Dennis Flanigan, Jr. + * Applied Research Corp. + * NASA GSFC Code 910.1 + * + * + * 15 Jul 93 + * Added tg_prt_head function + * + * 28 Jun 93 + * tg_file_str added + * + * 09 Jun 93 + * Added tg_open function ...Mike + * + * 5/10/93 + * Modified tg_read_ray and created tg_decode_ray_data . + * tg_read_ray now returns decoded real-valued ray data in a + * tg_ray_data structure instead of toga-format-encoded ray data + * in a rp_ray structure. Mike + * + * 8/13/92 + * Made changes so that code can be generated in library routines. + * Library will be called libtg.a + * + * 7/10/92 + * Routines to access toga data from Darwin. These routines work + * with the old sigmet data format that was used in Darwin from 87 + * to 91. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "toga.h" + +#ifdef USE_PLOG +#include "plog.h" +#endif + +#if defined(__linux) +void swab(const void *from, void *to, size_t n); +#endif +int tg_open(char *,tg_file_str *); +int tg_read_map_head(tg_file_str *); +float tg_make_ang(unsigned short); +int tg_read_map_bytes(tg_file_str *,void *,int); +int tg_read_rec_bytes(tg_file_str *,char *,int); +int tg_read_map_rec(tg_file_str *); +void tg_decode_ray_data(tg_file_str *,short *); +int tg_read_ray(tg_file_str *); +void tg_prt_head(tg_map_head_str *,int); + +FILE *uncompress_pipe (FILE *fp); + + +int tg_open(char *filename,tg_file_str *tg_file) + { + /* open the toga data file */ + if (filename == NULL) tg_file->fd = STDIN_FILENO; /* Stdin */ + else + if ((tg_file->fd=open(filename,O_RDONLY)) == -1) + { +#ifdef USE_PLOG + plog("tg_open: Error opening toga data file\n",PLOG_P); +#endif + return(TG_SYS_ERR); + } + /* Unfortunately, there is no tg_close to modularize the following + * pipe close. Shouldn't be any problems anyway. + */ + (void) uncompress_pipe(fdopen(tg_file->fd, "r")); /* Redirect through gunzip. */ + /* initialize buffer pointers, flags */ + tg_file->buf_ind = 32769; + tg_file->buf_end = 32769; + tg_file->first_rec = TRUE; + tg_file->data_ind = 2044; + + /* read the map header from the toga file into the tg_file + map_head str */ + if (tg_read_map_head(tg_file) < 0) + { + return(-1); /* Can't read toga map header */ + } + + return(TG_OK); + } + + + +int tg_read_map_head(tg_file_str *tg_file) + { + int n; + tg_map_head_str buf; + + if((n = read(tg_file->fd,&buf,TG_HDSIZE)) != TG_HDSIZE) + { + if (n < 0) + { + fprintf(stderr,"tg_read_map_head: (%d)%s \n",errno,strerror(errno)); + } + else + { + fprintf(stderr,"tg_read_map_head: Didn't read entire file header.\n\007"); + fprintf(stderr,"tg_read_map_head: Bytes read: %d \n",n); + } + return (-1); + } + + /* Do we need to swap bytes ? + * Test for byte swapping is done by checking the storm year. + * If less then 2050 then bytes are in correct order, otherwise + * swap bytes. + */ + if((buf.strm_year < 2050) && (buf.strm_year > 1960)) + { + memcpy(&(tg_file->map_head),&buf,sizeof(tg_map_head_str)); + tg_file->swap_bytes = FALSE; + } + else + { + swab(&buf,&(tg_file->map_head),sizeof(tg_map_head_str)); + tg_file->swap_bytes = TRUE; + } + + /* The file header has now been written into tg_file->map_head . + Check for reasonable strm_year and strm_mon. If not reasonable, + we assume the file is garbled beyond legibility, or perhaps this + is not a TOGA format data file. */ + if ((tg_file->map_head.strm_year < 2050) && + (tg_file->map_head.strm_year > 1960)) + { + if ((tg_file->map_head.strm_mon > 0) && + (tg_file->map_head.strm_mon < 13)) + { + /* file header OK, reset pointers into buffer */ + tg_file->buf_ind = 32769; + tg_file->buf_end = 32769; + return(0); + } + } + + /* If we've reached this point, we can't read the file header. */ +#ifdef USE_PLOG + plog("tg_read_map_head: Can't read TOGA file header\n",PLOG_P); +#endif + return(-1); + + } + +float tg_make_ang(unsigned short binang) + { + float maxval = 65536.0; + + return(360.0 * ((float)binang/maxval)); + } + +int tg_read_map_bytes(tg_file_str *tg_file,void *buf,int size) + { + int m,n,wsize; + short dec_key; + int ret_val = 0; + char *wbuf; + + /* Copy the pointer to buf to wbuf. wbuf stands for working buf */ + wbuf = buf; + + /* size is size in bytes. wsize is size in words. */ + wsize = size / 2; + + while(wsize > 0) + { + /* Do we need to decompress more data? */ + if((tg_file->buf_ind + wsize - 1) > tg_file->buf_end) + { + /* Yes we do, but first make sure that we don't need any data + * already in buffer. + */ + if((tg_file->buf_end - tg_file->buf_ind) > 0) + { + /* There is data in buffer that we need, before we decompress + * next string of data. + */ + memcpy(wbuf,&(tg_file->dec_buf[tg_file->buf_ind]), + (tg_file->buf_end - tg_file->buf_ind + 1) * 2); + wsize = wsize - (tg_file->buf_end - tg_file->buf_ind + 1); + wbuf = (wbuf + ((tg_file->buf_end - tg_file->buf_ind + 1) * 2)); + ret_val = ret_val + ((tg_file->buf_end - tg_file->buf_ind + 1)*2); + } + + /* Is this data or is this length of zeros */ + if((n = tg_read_rec_bytes(tg_file,(char *)&dec_key,2)) <= 0) + { + tg_file->buf_ind = tg_file->buf_end; + return(n); + } + + n = (0x1 & (dec_key >> 15)); + if (n == 1) + { + /* No, it is not length of zeros. + */ + n = dec_key & 0x7FFF; + + if((m = tg_read_rec_bytes(tg_file,(char *)&(tg_file->dec_buf), + n*2)) <= 0) + { + return(m); + } + tg_file->buf_ind = 0; + tg_file->buf_end = n - 1; + } + else + { + /* Is this end of data ? */ + if(dec_key == 0) + { + /* End of Data */ + tg_file->buf_ind = 32769; + tg_file->buf_end = 32769; + return(TG_END_DATA); + } + /* Is this end of ray? */ + else if(dec_key == 1) + { + /* plog("End of ray\n",LOG); */ + tg_file->buf_ind = tg_file->buf_end; + return(TG_END_RAY); + } + /* Fill decompress buffer with 0's */ + else + { + memset(&(tg_file->dec_buf),(char)0,dec_key * 2); + tg_file->buf_ind = 0; + tg_file->buf_end = dec_key - 1; + } + } + } + + /* Is decompressed data enough to fill request ? */ + if((tg_file->buf_end - tg_file->buf_ind + 1) < wsize) + { + /* Will need to decompress more data */ + memcpy(wbuf,&(tg_file->dec_buf[tg_file->buf_ind]), + (tg_file->buf_end - tg_file->buf_ind + 1) * 2); + wsize = wsize - (tg_file->buf_end - tg_file->buf_ind + 1); + + wbuf = (wbuf + ((tg_file->buf_end - tg_file->buf_ind + 1) * 2)); + + ret_val = ret_val + ((tg_file->buf_end - tg_file->buf_ind + 1) * 2); + tg_file->buf_ind = tg_file->buf_end; + } + else + { + /* There is enough decompressed data for request */ + memcpy(wbuf,&(tg_file->dec_buf[tg_file->buf_ind]),wsize * 2); + tg_file->buf_ind = tg_file->buf_ind + wsize; + ret_val = ret_val + (wsize * 2); + wsize = 0; + } + } + return(ret_val); + } + +int tg_read_rec_bytes(tg_file_str *tg_file,char *buf,int size) + { + /* Return size number of bytes in buf. Read in new record + * if needed. Check to make sure missing records with + * record number variable found in record header. + */ + int wsize,n; + char *wbuf; + + wsize = size/2; + wbuf = buf; + + /* Is there enough data in recbuf for request */ + if((tg_file->data_ind + wsize - 1) > 2043) + { + /* No there is not enough data for this request, but before + * we read the next buffer, we should copy what we have into + * the buffer pointed to by buf. + */ + if(tg_file->data_ind < 2044) + { + memcpy(wbuf,&(tg_file->recbuf.data[tg_file->data_ind]), + (2043 - tg_file->data_ind + 1) * 2); + wsize = wsize - (2043 - tg_file->data_ind + 1); + wbuf = (wbuf + ((2043 - tg_file->data_ind + 1) * 2)); + } + + /* New record has to be read in */ + tg_file->data_ind = 0; + if((n = tg_read_map_rec(tg_file)) < TG_RECSIZE) + { + if(n == 0) + { + return(n); + } + else + { + fprintf(stderr,"tg_read_map_rec: %d \n",n); + return(-1); + } + } + if(tg_file->first_rec) + { + tg_file->recnum = tg_file->recbuf.rec_num; + tg_file->first_rec = FALSE; + } + else + { + if((tg_file->recnum + 1) != tg_file->recbuf.rec_num) + { + tg_file->recnum = tg_file->recbuf.rec_num; + /* Set index to next ray */ + tg_file->data_ind = tg_file->recbuf.first_ray - 5; + return(TG_REC_NOSEQ); + } + else + { + tg_file->recnum = tg_file->recbuf.rec_num; + } + } + tg_file->data_ind = 0; + } + + memcpy(wbuf,&(tg_file->recbuf.data[tg_file->data_ind]),wsize*2); + tg_file->data_ind = tg_file->data_ind + wsize; + + return(size); + } + +int tg_read_map_rec(tg_file_str *tg_file) + { + int n; + static char buf[TG_RECSIZE]; + + if((n = read(tg_file->fd,buf,TG_RECSIZE)) < 0) + { + fprintf(stderr,"tg_read_map_rec: Error while reading data record.\n"); + fprintf(stderr,"tg_read_map_rec: (%d)%s\n",errno,strerror(errno)); + } + else if(n == 0) + { + /* assume end of file */ + } + else if(n != TG_RECSIZE) + { + fprintf(stderr,"tg_read_map_rec: Did not read all of data record.\n\007"); + fprintf(stderr,"tg_read_map_rec: Bytes read: %d \n",n); + } + else + { + if(tg_file->swap_bytes) + { + /* record read in correctly */ + swab(buf,&(tg_file->recbuf),TG_RECSIZE); + } + else + { + memcpy(&(tg_file->recbuf),buf,TG_RECSIZE); + } + } + + return(n); + } + + +void tg_decode_ray_data(tg_file_str *tg_file,short ray_buf[]) + { + int j,k; + short dbval,vel,temp1,temp2; + float nyq_vel; + + + k = 0; /* intialize ray->data index */ + switch (tg_file->ray_head.type) + { + case 1: + /* TOGA record type 1 contains uncorrected & corrected + reflectivity data, velocity, and spectrum width values. */ + tg_file->ray.da_inv[TG_DM_IND] = TRUE; + tg_file->ray.da_inv[TG_DZ_IND] = TRUE; + tg_file->ray.da_inv[TG_VR_IND] = TRUE; + tg_file->ray.da_inv[TG_SW_IND] = TRUE; + + tg_file->ray.num_bins[TG_DM_IND] = tg_file->ray_head.srngkill - 1; + tg_file->ray.num_bins[TG_DZ_IND] = tg_file->ray_head.srngkill - 1; + tg_file->ray.num_bins[TG_VR_IND] = tg_file->ray_head.srngkill - 1; + tg_file->ray.num_bins[TG_SW_IND] = tg_file->ray_head.srngkill - 1; + + tg_file->ray.start_km[TG_DM_IND] = tg_file->ray_head.strt_rng/40.0; + tg_file->ray.start_km[TG_DZ_IND] = tg_file->ray_head.strt_rng/40.0; + tg_file->ray.start_km[TG_VR_IND] = tg_file->ray_head.strt_rng/40.0; + tg_file->ray.start_km[TG_SW_IND] = tg_file->ray_head.strt_rng/40.0; + + tg_file->ray.interval_km[TG_DM_IND] = tg_file->map_head.rnginc/1000.0; + tg_file->ray.interval_km[TG_DZ_IND] = tg_file->map_head.rnginc/1000.0; + tg_file->ray.interval_km[TG_VR_IND] = tg_file->map_head.rnginc/1000.0; + tg_file->ray.interval_km[TG_SW_IND] = tg_file->map_head.rnginc/1000.0; + + for (j=0; jray.num_bins[TG_DM_IND]; j++) + { + /* check OK flag bit to see if this is valid data */ + if ((ray_buf[j*3] & 0x8000) == 0) + { + /* bad data, store no_data flag into each field */ + tg_file->ray.data[TG_DM_IND][k] = TG_NO_DATA; + tg_file->ray.data[TG_DZ_IND][k] = TG_NO_DATA; + tg_file->ray.data[TG_VR_IND][k] = TG_NO_DATA; + tg_file->ray.data[TG_SW_IND][k] = TG_NO_DATA; + } + else /* good data, uncode and store into tg_ray_data struct */ + { + /******* do corrected dbz value *********/ + dbval = ray_buf[j*3 + 1] & 0x0FFF; + /* The dbz data are signed 12 bit values. Check sign bit + of dbz value */ + if ((dbval & 0x0800) == 0) + { + /* store unscaled positive dbz value */ + tg_file->ray.data[TG_DZ_IND][k] = dbval/16.0; + } + else /* 12 bit negative value */ + { + /* make 12 bit value a 16 bit word by extending sign bit */ + dbval = (dbval | ~0x0FFF); + if (dbval == -2048) /* -2048 indicates bad data */ + { + tg_file->ray.data[TG_DZ_IND][k] = TG_NO_DATA; /* bad data */ + } + else + { + /* store unscaled negative dbz value */ + tg_file->ray.data[TG_DZ_IND][k] = dbval/16.0; + } + } + + + /******* do uncorrected dbz value *********/ + dbval = ray_buf[j*3 + 2] & 0x0FFF; + /* The dbz data are signed 12 bit values. Check sign bit + of dbz value */ + if ((dbval & 0x0800) == 0) + { + /* store unscaled positive dbz value */ + tg_file->ray.data[TG_DM_IND][k] = dbval/16.0; + } + else /* 12 bit negative value */ + { + /* make 12 bit value a 16 bit word by extending sign bit */ + dbval = (dbval | ~0x0FFF); + if (dbval == -2048) /* -2048 indicates bad data */ + { + tg_file->ray.data[TG_DM_IND][k] = TG_NO_DATA; /* bad data */ + } + else + { + /* store unscaled negative dbz value */ + tg_file->ray.data[TG_DM_IND][k] = dbval/16.0; + } + } + + /* compute the nyquist velocity for subsequent scaling + of velocity and spectrum width values. */ + /* nyquist velocity = wavelength/(4*pulse repetition period) */ + nyq_vel = (tg_file->map_head.wavelen/10000.0) / + (4.0*(1.0/tg_file->map_head.prf)); /*m/s*/ + + /******** do velocity value **********/ + /* toga velocity values are 10 bits long and range from + -512 to 511 */ + vel = ray_buf[j*3] & 0x03FF; /* strip off leading 6 bits */ + /* This is a signed 10 bit value. Check sign bit */ + if ((vel & 0x0200) == 0) /* sign bit set? */ + { + /* no, store positive velocity value */ + tg_file->ray.data[TG_VR_IND][k] = vel/511.0*nyq_vel; + } + else /* 10 bit negative value */ + { + /* make 10 bit value a 16 bit word by extending sign bit */ + vel = vel | ~0x03FF; + /* store negative velocity value */ + tg_file->ray.data[TG_VR_IND][k] = vel/512.0*nyq_vel; + } + + /******** do spectrum width ***********/ + /* toga spectrum width values are 8 bits and range from + zero to 1/2 . see toga documentation */ + /* get the low order 4 bits into their correct positions */ + temp1 = (ray_buf[j*3 + 1] >> 12) & 0x000F; + /* get the high order 4 bits into correct positions */ + temp2 = (ray_buf[j*3 + 2] >> 8) & 0x00F0; + /* store the spectrum width value into tg_ray_data struct */ + tg_file->ray.data[TG_SW_IND][k] = ((temp1 | temp2)/512.0)*nyq_vel; + + } + k += 1; + } /* end for */ + break; /* case 1: */ + + case 19: /* uncorrected reflectivity data */ + /* TOGA record type 19 contains only uncorrected reflectivity values */ + tg_file->ray.da_inv[TG_DM_IND] = TRUE; + tg_file->ray.da_inv[TG_DZ_IND] = FALSE; + tg_file->ray.da_inv[TG_VR_IND] = FALSE; + tg_file->ray.da_inv[TG_SW_IND] = FALSE; + tg_file->ray.num_bins[TG_DM_IND] = tg_file->ray_head.srngkill - 1; + tg_file->ray.start_km[TG_DM_IND] = tg_file->ray_head.strt_rng/40.0; + tg_file->ray.interval_km[TG_DM_IND] = tg_file->map_head.rnginc/1000.0; + + for (j=0; jray.num_bins[TG_DM_IND]; j++) + { + /* check OK flag bit to see if this is valid data */ + if ((ray_buf[j] & 0x8000) == 0) + { + tg_file->ray.data[TG_DM_IND][k] = TG_NO_DATA; /* bad data, store flag */ + } + else /* good data, uncode it and store into ray->data */ + { + dbval = ray_buf[j] & 0x7FFF; /* strip off OK flag */ + /* This is a signed 15 bit dbz value. Check sign bit */ + if ((dbval & 0x4000) == 0) /* sign bit set? */ + { + /* no, positive db value. Unscale by factor of 16 and store */ + tg_file->ray.data[TG_DM_IND][k] = dbval/16.0; + } + else /* 15 bit negative value */ + { + /* make 15 bit value a 16 bit word by extending sign bit, + unscale by factor of 16 and store. */ + tg_file->ray.data[TG_DM_IND][k] = (dbval | ~0x7FFF)/16.0; + } + } + + k += 1; + } /* end for */ + break; /* case 19: */ + + default: + fprintf(stderr,"tg_decode_ray_data: found unknown toga data type\n"); + fprintf(stderr,"tg_decode_ray_data: ignore this ray\n"); + /* return TG_RAY_NOTYPE; */ + break; + + } /* end switch */ + + } + + + +int tg_read_ray(tg_file_str *tg_file) + { + int n,a,o; + int bin_size; + short ray_buf[1800]; + + /* bin_size is size in bytes of data from one bin */ + + n = tg_read_map_bytes(tg_file,&(tg_file->ray_head),sizeof(tg_ray_head_str)); + switch(n) + { + case TG_END_DATA: + /* plog("tg_read_ray: TG_END_DATA for ray_head\n",LOG); */ + break; + case TG_REC_NOSEQ: + /* plog("tg_read_ray: TG_REC_NOSEQ for ray_head\n",LOG); */ + break; + case 0: + n = TG_RAY_READ_ERR; + /* plog("tg_read_ray: zero bytes for ray_head\n",LOG); */ + break; + case -1: + /* plog("tg_read_ray: error for ray_head\n",LOG); */ + break; + default: + tg_file->ray.azm = tg_make_ang(tg_file->ray_head.azm); + tg_file->ray.elev = tg_make_ang(tg_file->ray_head.elev); + + switch(tg_file->ray_head.type) + { + case 1: + /* plog("tg_read_ray:doppler data\n",LOG); */ + bin_size = 6 * (tg_file->map_head.numbin); + break; + case 19: + /* plog("tg_read_ray:reflectivity data\n",LOG); */ + bin_size = 2 * (tg_file->map_head.numbin); + break; + default: + /* plog("tg_read_ray:undefined data type\n",PRINT); */ + return TG_RAY_NOTYPE; + break; + } + + /* read ray contents from disk file into ray_buf */ + if((o = tg_read_map_bytes(tg_file,ray_buf,bin_size)) == bin_size) + { + /* decode the raw ray data in ray_buf[] and place into + the tg_file ray structure */ + tg_decode_ray_data(tg_file,ray_buf); + } + else + { + fprintf(stderr,"*** wrong number of bytes read from ray ***\n"); + fprintf(stderr,"\n,number_bytes read:%d\n",o); + return TG_RAY_READ_ERR; + } + + /* read end_of_ray flag from disk file */ + o = 0; + a = 0; + while((o != TG_END_RAY) && (a < 100)) + { + o=tg_read_map_bytes(tg_file,ray_buf,2); + a++; + } + if(a >= 100) + { + fprintf(stderr,"tg_read_ray: Could not find TG_END_RAY\n"); + return TG_RAY_READ_ERR; + } + } + return n; + } + + + +void tg_prt_head(tg_map_head_str *head,int verbose) + { + /* print out the contents of a file map header */ + + +#ifdef USE_PLOG + plog("strm_year: %d\n",PLOG_L,head->strm_year); + plog("strm_mon: %d\n",PLOG_L,head->strm_mon); + plog("strm_day: %d\n",PLOG_L,head->strm_day); + plog("strm_num: %d\n",PLOG_L,head->strm_num); + plog("map_num: %d\n",PLOG_L,head->map_num); + plog("\n",PLOG_L); + plog("scan_year: %d\n",PLOG_L,head->scan_year); + plog("scan_mon: %d\n",PLOG_L,head->scan_mon); + plog("scan_day: %d\n",PLOG_L,head->scan_day); + plog("scan_hour: %d\n",PLOG_L,head->scan_hour); + plog("scan_min: %d\n",PLOG_L,head->scan_min); + plog("scan_sec: %d\n",PLOG_L,head->scan_sec); + plog("data_set: %d\n",PLOG_L,head->data_set); + plog("\n",PLOG_L); + if(verbose) + { + plog("tp1_ar: %d\n",PLOG_L,head->tp1_ar); + plog("tp1_occw: %d\n",PLOG_L,head->tp1_occw); + plog("tp1_dibit: %d\n",PLOG_L,head->tp1_dibit); + plog("tp1_debit: %d\n",PLOG_L,head->tp1_debit); + plog("\n",PLOG_L); + plog("tp2_ar: %d\n",PLOG_L,head->tp2_ar); + plog("tp2_occw: %d\n",PLOG_L,head->tp2_occw); + plog("tp2_dibit: %d\n",PLOG_L,head->tp2_dibit); + plog("tp2_debit: %d\n",PLOG_L,head->tp2_debit); + plog("\n",PLOG_L); + plog("status: %d\n",PLOG_L,head->status); + plog("strng: %d\n",PLOG_L,head->strng); + plog("numbin: %d\n",PLOG_L,head->numbin); + plog("rnginc: %d\n",PLOG_L,head->rnginc); + plog("rngjit: %d\n",PLOG_L,head->rngjit); + plog("numcbin: %d\n",PLOG_L,head->numcbin); + plog("\n",PLOG_L); + plog("strtcal1: %d\n",PLOG_L,head->strtcal1); + plog("strtcal2: %d\n",PLOG_L,head->strtcal2); + plog("stepcal: %d\n",PLOG_L,head->stepcal); + } + plog("azmleft: %d\n",PLOG_L,head->azmleft); + plog("azmrght: %d\n",PLOG_L,head->azmrght); + plog("elev_low: %d\n",PLOG_L,head->elev_low); + plog("elev_hgh: %d\n",PLOG_L,head->elev_hgh); + plog("\n",PLOG_L); + plog("at_angres: %d\n",PLOG_L,head->at_angres); + plog("numfix_ang: %d\n",PLOG_L,head->numfix_ang); + if(verbose) + { + for(a=0;a<20;a++) + { + plog("angfix[%2d]: %d\n",PLOG_L,a,head->angfix[a]); + } + plog("\n",PLOG_L); + plog("rlparm: %d\n",PLOG_L,head->rlparm); + plog("signois: %d\n",PLOG_L,head->signois); + plog("sigcltr: %d\n",PLOG_L,head->sigcltr); + plog("thrsh_flg: %d\n",PLOG_L,head->thrsh_flg); + plog("\n",PLOG_L); + plog("numdsp: %d\n",PLOG_L,head->numdsp); + plog("numwrd: %d\n",PLOG_L,head->numwrd); + plog("\n",PLOG_L); + plog("scanmod: %d\n",PLOG_L,head->scanmod); + plog("filename: %s\n",PLOG_L,head->filename); + plog("\n",PLOG_L); + plog("prf: %d\n",PLOG_L,head->prf); + plog("transiz: %d\n",PLOG_L,head->transiz); + plog("spconf: %d\n",PLOG_L,head->spconf); + plog("sufchar: %d\n",PLOG_L,head->sufchar); + plog("recsat1: %d\n",PLOG_L,head->recsat1); + plog("recsat2: %d\n",PLOG_L,head->recsat2); + plog("\n",PLOG_L); + plog("dsp1cor_log: %d\n",PLOG_L,head->dsp1cor_log); + plog("dsp1cor_iad: %d\n",PLOG_L,head->dsp1cor_iad); + plog("dsp1cor_qad: %d\n",PLOG_L,head->dsp1cor_qad); + plog("dsp1crr_log: %d\n",PLOG_L,head->dsp1crr_log); + plog("dsp1crr_iad: %d\n",PLOG_L,head->dsp1crr_iad); + plog("dsp1crr_qad: %d\n",PLOG_L,head->dsp1crr_qad); + plog("\n",PLOG_L); + plog("dsp2cor_log: %d\n",PLOG_L,head->dsp2cor_log); + plog("dsp2cor_iad: %d\n",PLOG_L,head->dsp2cor_iad); + plog("dsp2cor_qad: %d\n",PLOG_L,head->dsp2cor_qad); + plog("dsp2crr_log: %d\n",PLOG_L,head->dsp2crr_log); + plog("dsp2crr_iad: %d\n",PLOG_L,head->dsp2crr_iad); + plog("dsp2crr_qad: %d\n",PLOG_L,head->dsp2crr_qad); + plog("\n",PLOG_L); + } + plog("wavelen: %d\n",PLOG_L,head->wavelen); + plog("pulsewd: %d\n",PLOG_L,head->pulsewd); + plog("hortran_pow: %d\n",PLOG_L,head->hortran_pow); + plog("vertran_pow: %d\n",PLOG_L,head->vertran_pow); + plog("\n",PLOG_L); + if(verbose) + { + plog("high_zero: %d\n",PLOG_L,head->high_zero); + } + plog("sitelat: %d\n",PLOG_L,head->sitelat); + plog("sitelong: %d\n",PLOG_L,head->sitelong); + plog("time_zone: %d\n",PLOG_L,head->time_zone); + plog("\n",PLOG_L); + if(verbose) + { + plog("zm_dsp1_mas: %d\n",PLOG_L,head->zm_dsp1_mas); + plog("zm_dsp1_slv: %d\n",PLOG_L,head->zm_dsp1_slv); + plog("zm_dsp2_mas: %d\n",PLOG_L,head->zm_dsp2_mas); + plog("zm_dsp2_slv: %d\n",PLOG_L,head->zm_dsp2_slv); + plog("\n",PLOG_L); + plog("minz_dsp1_mas: %d\n",PLOG_L,head->minz_dsp1_mas); + plog("minz_dsp1_slv: %d\n",PLOG_L,head->minz_dsp1_slv); + plog("minz_dsp2_mas: %d\n",PLOG_L,head->minz_dsp2_mas); + plog("minz_dsp2_slv: %d\n",PLOG_L,head->minz_dsp2_slv); + plog("\n",PLOG_L); + plog("num_pol: %d\n",PLOG_L,head->num_pol); + plog("exinfo_rayhd: %d\n",PLOG_L,head->exinfo_rayhd); + plog("len_exhd: %d\n",PLOG_L,head->len_exhd); + plog("\n",PLOG_L); + } + plog("lat_deg: %d\n",PLOG_L,head->lat_deg); + plog("lat_hun_min: %d\n",PLOG_L,head->lat_hun_min); + plog("lon_deg: %d\n",PLOG_L,head->lon_deg); + plog("lon_hun_min: %d\n",PLOG_L,head->lon_hun_min); + plog("\n",PLOG_L); + if(verbose) + { + plog("alt_atn: %d\n",PLOG_L,head->alt_atn); + plog("alt_grn: %d\n",PLOG_L,head->alt_grn); + plog("\n",PLOG_L); + plog("vel_plat: %d\n",PLOG_L,head->vel_plat); + plog("vel_cor: %d\n",PLOG_L,head->vel_cor); + plog("head_plat: %d\n",PLOG_L,head->head_plat); + plog("head_dsp: %d\n",PLOG_L,head->head_dsp); + plog("\n",PLOG_L); + plog("set_plat: %d\n",PLOG_L,head->set_plat); + plog("drift_plat: %d\n",PLOG_L,head->drift_plat); + plog("ok_plat: %d\n",PLOG_L,head->ok_plat); + plog("\n",PLOG_L); + plog("comments: %s\n",PLOG_L,head->comments); + } +#else + fprintf(stderr, "You must link with -lplog and compile the toga library with -DUSE_PLOG to get a printout of the header.\n"); +#endif + } diff --git a/toga.h b/toga.h new file mode 100644 index 0000000..98d4359 --- /dev/null +++ b/toga.h @@ -0,0 +1,346 @@ + +/* Darwin data structures and parameters + * + * Dennis Flanigan, Jr. + * Applied Research Corp. + * NASA GSFC Code 910.1 + * + * + * added tg_file_str structure 09 Jun 93 ...Mike + * + * updated with new tg_ray_data structure 5/6/93 ...Mike + * This structure is intended to supercede rp_ray + * + * updated for use with libtg 8/13/92 + * + * updated 7/13/92 + * + * 12/31/91 + * + * + */ + +#define TG_OK 0 +#define TG_SYS_ERR -1 +#define TG_END_RAY -2 +#define TG_END_DATA -3 +#define TG_REC_NOSEQ -4 +#define TG_RAY_NOTYPE -5 +#define TG_RAY_READ_ERR -6 + +#define TG_HDSIZE 1280 +#define TG_RECSIZE 4096 + +#define TG_ANT_PPI 1 +#define TG_ANT_RHI 2 +#define TG_ANT_MAN 3 +#define TG_ANT_FIL 4 + +/* field indices for tg_ray_data.da_inv */ +#define TG_DM_IND 0 /* uncorrected reflectivity */ +#define TG_DZ_IND 1 /* corrected reflectivity */ +#define TG_VR_IND 2 /* radial velocity */ +#define TG_SW_IND 3 /* spectral width */ + +/* missing data flag */ +#define TG_NO_DATA 0x1000 + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/****** rp_ray is the old, outdated structure in which to + store (toga format-encoded) ray data. I have removed references + to it in the toga library libtg.a . + Use instead the tg_ray_data structure below, in which decoded + ray data is stored....Mike */ +typedef struct + { + float elev; + float azm; + short bin[1800]; /* raw (encoded) ray data in toga format */ + } +rp_ray; + +typedef struct + { + float azm; /* azimuth angle */ + float elev; /* elevation angle */ + /* time */ /* time of some sort (not done yet) */ + int da_inv[4]; /* data inventory */ + short num_bins[4]; /* number of bins */ + float start_km[4]; /* start range of data in km*/ + float interval_km[4]; /* interval of range bins in km */ + float data[4][1024]; /* real value data */ + } +tg_ray_data; + + +typedef struct + { + short axrat; /* axial ratio in signed hundredths */ + short ort_hor; /* orientation ccw of horizontal in degrees */ + short pw_div_bits; /* power divider bits (A) in low 7 bits */ + short delay_bits; /* delay bits (P) in low 7 bits */ + } +tg_tran_pol_str; + + +typedef struct + { + /* storm id : word 1*/ + short strm_year; + short strm_mon; + short strm_day; + short strm_num; + short map_num; + + /* time of start of scan : word 6*/ + short scan_year; + short scan_mon; + short scan_day; + short scan_hour; + short scan_min; + short scan_sec; + + /* word 12 */ + short data_set; + + /* transmit polarization 1.1 : word 13*/ + short tp1_ar; + short tp1_occw; + short tp1_dibit; + short tp1_debit; + + /* transmit polarization 1.2 : word 17*/ + short tp2_ar; + short tp2_occw; + short tp2_dibit; + short tp2_debit; + + /* status bits : word 21*/ + short status; + + /* word 22 */ + short strng; /* start range */ + short numbin; /* number of data bins */ + short rnginc; /* range increment between bins */ + short rngjit; /* range jitter boollean */ + short numcbin; /* number of range cal bins */ + short strtcal1; /* start range of cal bins #1 */ + short strtcal2; /* start range if cak bubs #2 */ + short stepcal; /* step between cal bins 1 & 3 and 2 & 4 */ + short azmleft; /* azimuth left, min azimuth */ + short azmrght; /* azimuth right, max azimuth */ + short elev_low; /* elevation low */ + short elev_hgh; /* elevation high */ + + /* word 34 */ + short at_angres; /* attempted angular res */ + short numfix_ang; /* num fixed angles used */ + short angfix[20]; /* angles used for fixed coordinate */ + + /* word 56 */ + short rlparm; /* real time display parameters */ + short signois; /* signal to noise threshold */ + short sigcltr; /* signal to clutter threshold */ + short thrsh_flg; /* threshold flags */ + + /* word 60 */ + short numdsp; /* number of doppler signal processors working */ + short numwrd; /* number of words which are difined in ray header */ + + /* word 62 */ + short scanmod; /* scan mode */ + char filename[16]; /* file name if scan mode is file (value 4)*/ + + /* word 71 */ + short prf; /* prf */ + short transiz; /* number of samp per proc interval (transform size) */ + short spconf; /* signal processor configuration */ + + /* word 74 */ + short sufchar; /* suffix character of data base directory */ + + /* word 75 */ + short recsat1; /* receiver saturation or */ + short recsat2; /* 0 if standard rang-dependent STC was used */ + + /*words 77 to 88 : bias levels set to zeor if not applicable */ + + /* word 77 */ + short dsp1cor_log; /* co rec dsp 1, log rec noise level */ + short dsp1cor_iad; /* co rec dsp 1, "I" a/d offset */ + short dsp1cor_qad; /* co rec dsp 1, "Q" a/d offset */ + + /* word 80 */ + short dsp1crr_log; /* cross rec dsp 1, log rec noise level */ + short dsp1crr_iad; /* cross rec dsp 1, "I" a/d offset */ + short dsp1crr_qad; /* cross rec dsp 1, "Q" a/d offset */ + + /* word 83 */ + short dsp2cor_log; /* co rec dsp 2, log rec noise level */ + short dsp2cor_iad; /* co rec dsp 2, "I" a/d offset */ + short dsp2cor_qad; /* co rec dsp 2, "Q" a/d offset */ + + /* word 86 */ + short dsp2crr_log; /* cross rec dsp 2, log rec noise level */ + short dsp2crr_iad; /* cross rec dsp 2, "I" a/d offset */ + short dsp2crr_qad; /* cross rec dsp 2, "Q" a/d offset */ + + /* word 89 */ + short wavelen; /* wavelength in hundredths of cm */ + short pulsewd; /* pulse width in hundredths of microsec. */ + short hortran_pow; /* horizontal transmit power */ + short vertran_pow; /* vertical transmit power */ + + /* word 93 */ + short high_zero; /* height of zeroing in kilomiters */ + short sitelat; /* latitude in .01 deg (if zero see words 108-111)*/ + short sitelong; /* longitude in .01 deg (if zero see words 108-111)*/ + short time_zone; /* time zone of rec time, minutes ahead of GMT */ + + /* word 97 */ + short zm_dsp1_mas; /* Z slope, dsp 1, master board */ + short zm_dsp1_slv; /* Z slope, dsp 1, slave board */ + short zm_dsp2_mas; /* Z slope, dsp 2, master board */ + short zm_dsp2_slv; /* Z slope, dsp 2, slave board */ + + /* word 101 */ + short minz_dsp1_mas; /* minimum detectable Z, dsp 1, master */ + short minz_dsp1_slv; /* minimum detectable Z, dsp 1, slave */ + short minz_dsp2_mas; /* minimum detectable Z, dsp 2, master */ + short minz_dsp2_slv; /* minimum detectable Z, dsp 2, slave */ + + /* word 105 */ + short num_pol; /* number of polarization pairs used above 1 */ + + /* word 106 */ + short exinfo_rayhd; /* extra information in ray header */ + /* bit 0 : IFF data available */ + /* bit 1 : roll available */ + /* bit 2 : pitch available */ + /* bit 3 : heading available */ + + /* word 107 */ + short len_exhd; /* length of extended ray header ( 0 means 20 words) */ + + /* word 108 */ + short lat_deg; /* latitude degrees */ + short lat_hun_min; /* latitude in .01 minutes */ + short lon_deg; /* longitude degrees */ + short lon_hun_min; /* longitude in .01 minutes */ + + /* word 112 */ + short alt_atn; /* altitude of antenna in meters above sea level*/ + short alt_grn; /* altitude of ground at radar site in meters */ + + /* word 114 */ + short vel_plat; /* speed of platform from senser in .01 meters/sec */ + short vel_cor; /* velocity value loaded into dsp for vel correction */ + short head_plat; /* heading of platform from sensor in .1 degrees */ + short head_dsp; /* heading loaded into dsp */ + + /* word 118 */ + short set_plat; /* set of platform (signed 1/10 degrees) */ + short drift_plat; /* drift of platform (1/100 meters per sec */ + short ok_plat; /* ok flags for words 108 to 120 */ + /* bit 0: navigator input ok */ + /* bit 1: navigator used for lat, long */ + /* bit 2: navigator used for altitude */ + /* bit 3: navigator used for speed and heading */ + /* bit 4: mavigator used for set and drift */ + + + /* word 121 */ + short spare121[79]; + + /* word 200 */ + tg_tran_pol_str tp21; /* transmit polarization 2.1 */ + tg_tran_pol_str tp22; /* transmit polarization 2.2 */ + + /* word 208 */ + tg_tran_pol_str tp31; /* transmit polarization 3.1 */ + tg_tran_pol_str tp32; /* transmit polarization 3.2 */ + + /* word 216 */ + tg_tran_pol_str tp41; /* transmit polarization 4.1 */ + tg_tran_pol_str tp42; /* transmit polarization 4.2 */ + + /* word 224 */ + tg_tran_pol_str tp51; /* transmit polarization 5.1 */ + tg_tran_pol_str tp52; /* transmit polarization 5.2 */ + + /* word 232 */ + tg_tran_pol_str tp61; /* transmit polarization 6.1 */ + tg_tran_pol_str tp62; /* transmit polarization 6.2 */ + + /* word 240 */ + tg_tran_pol_str tp71; /* transmit polarization 7.1 */ + tg_tran_pol_str tp72; /* transmit polarization 7.2 */ + + /* word 248 */ + tg_tran_pol_str tp81; /* transmit polarization 8.1 */ + tg_tran_pol_str tp82; /* transmit polarization 8.2 */ + + /* word 255 */ + short spare255[55]; + + /* word 301 */ + char comments[680]; + } +tg_map_head_str; + + +typedef struct + { + short first_ray; + short rec_num; + short rec_bol; + short res1; + short data[2044]; + } +tg_data_rec_str; + +typedef struct + { + short azm; + short elev; + short year; + short mon; + short day; + short hour; + short min; + short hunsec; + short tilt; + short step; + short type; + short strt_rng; + short srngkill; + short erngkill; + short spare[6]; + } +tg_ray_head_str; + +/* tg_file_str contains all info relevant to one open toga data file */ +typedef struct + { + int fd; + int ray_num; + int swap_bytes; + short dec_buf[32768]; /*** Buffer and pointers for tg_read_map_bytes. */ + int buf_ind; + int buf_end; /****************/ + tg_data_rec_str recbuf; /*** buffer and indices for tg_read_rec_bytes. */ + int first_rec; + int data_ind; + int recnum; /*************/ + tg_map_head_str map_head; + tg_ray_head_str ray_head; + tg_ray_data ray; + } +tg_file_str; diff --git a/toga_to_radar.c b/toga_to_radar.c new file mode 100644 index 0000000..1573068 --- /dev/null +++ b/toga_to_radar.c @@ -0,0 +1,478 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * Ingest a Darwin_Toga file and fill a Radar structure with the data. + * Darwin Type 1 data contains 4 fields: corrected & uncorrected refl, + * velocity, and spectrum width. + * Darwin type 19 data contains 1 field: uncorrected reflectivity. + * Ignore all other Darwin data types. + * Handle only PPI scans; ignore RHI scans. + * + * Object code from this file must be linked with the following + * libraries: + * -ltg -lradar + * + * "libtg.a" handles the reading and decompression of Darwin TOGA + * data records from the input toga file. + * + * + * Kolander + * Applied Research Corp. + * NASA/GSFC + * + */ + +#include +#include +#include "toga.h" +#include "rsl.h" + +#define MAX_RAYS 512 +#define MAX_SWEEPS 20 +#define MISSING_VAL 0 + +extern int radar_verbose_flag; +int tg_open(char *infile, tg_file_str *tg_file); +int tg_read_ray(tg_file_str *tg_file); + +/* Toga radar routines */ +void fill_ray(Ray *, tg_file_str *, int); +void fill_ray_header(Ray *, tg_file_str *, int, int); +void fill_sweep_header(Radar *, tg_map_head_str *, int, int); +void fill_volume_header(Radar *, tg_map_head_str *); +void fill_radar_header(Radar *, tg_map_head_str *); + + + + +/********************************************************************/ +void fill_ray(Ray *ray, tg_file_str *tg_file, int datatype) + /* transfer ray data values from the toga ray structure + to the radar ray */ + { + int j; + + if (ray == NULL) return; + for (j=0; jray.num_bins[datatype]; j++) + { + /* check to see if this is valid data */ + if (tg_file->ray.data[datatype][j] == TG_NO_DATA) + ray->range[j] = ray->h.invf(BADVAL); /* bad data, store flag */ + else /* good data, store into radar ray */ + ray->range[j] = ray->h.invf(tg_file->ray.data[datatype][j]); + } /* end for */ + } + + + +void fill_ray_header(Ray *ray, tg_file_str *tg_file, int elev_num, + int datatype) + /* Unresolved: Many of the following values */ + { + if (ray == NULL) return; + ray->h.month = tg_file->ray_head.mon; + ray->h.day = tg_file->ray_head.day; + ray->h.year = tg_file->ray_head.year; + ray->h.hour = tg_file->ray_head.hour; + ray->h.minute = tg_file->ray_head.min; + ray->h.sec = tg_file->ray_head.hunsec/100.0; + ray->h.unam_rng = MISSING_VAL; /* ?? */ + ray->h.azimuth = tg_file->ray.azm; + ray->h.ray_num = tg_file->ray_num; + ray->h.elev = tg_file->ray.elev; + ray->h.elev_num = elev_num; + ray->h.range_bin1 = (int)(tg_file->ray.start_km[datatype]*1000.0); + ray->h.gate_size = (int)(tg_file->ray.interval_km[datatype]*1000.0); + + ray->h.vel_res = MISSING_VAL; /* ?? */ + ray->h.sweep_rate = MISSING_VAL; /* ?? */ + ray->h.prf = tg_file->map_head.prf; + ray->h.azim_rate = MISSING_VAL; /* ?? */ + ray->h.fix_angle = MISSING_VAL; /* ?? */ + ray->h.pulse_count = MISSING_VAL; /* ?? */ + ray->h.pulse_width = tg_file->map_head.pulsewd/100.0; + ray->h.beam_width = 1.65; + ray->h.frequency = 5625; + ray->h.wavelength = (tg_file->map_head.wavelen/100.0)/100.0; /* m */ + ray->h.nyq_vel = (ray->h.wavelength * ray->h.prf)/4.0; /* m/s */ + ray->h.nbins = tg_file->ray.num_bins[datatype]; + + if (datatype == TG_DM_IND) + { + ray->h.f = DZ_F; + ray->h.invf = DZ_INVF; + } + else if (datatype == TG_DZ_IND) + { + ray->h.f = DZ_F; + ray->h.invf = DZ_INVF; + } + else if (datatype == TG_VR_IND) + { + ray->h.f = VR_F; + ray->h.invf = VR_INVF; + } + else if (datatype == TG_SW_IND) + { + ray->h.f = SW_F; + ray->h.invf = SW_INVF; + } + } + + + +void fill_sweep_header(Radar *radar, tg_map_head_str *map_head, + int sweep_num, int nrays) + /* Arrive here _after_ sweep ray data has been filled in. */ + { + if (radar_verbose_flag) + fprintf(stderr,"sweep_num:%02d num_rays:%d\n",sweep_num, nrays); + + if (map_head->data_set == 1) + { + radar->v[DZ_INDEX]->sweep[sweep_num]->h.f = DZ_F; + radar->v[DZ_INDEX]->sweep[sweep_num]->h.invf = DZ_INVF; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.f = DZ_F; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.invf = DZ_INVF; + radar->v[VR_INDEX]->sweep[sweep_num]->h.f = VR_F; + radar->v[VR_INDEX]->sweep[sweep_num]->h.invf = VR_INVF; + radar->v[SW_INDEX]->sweep[sweep_num]->h.f = SW_F; + radar->v[SW_INDEX]->sweep[sweep_num]->h.invf = SW_INVF; + + radar->v[DZ_INDEX]->sweep[sweep_num]->h.sweep_num = sweep_num; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.sweep_num = sweep_num; + radar->v[VR_INDEX]->sweep[sweep_num]->h.sweep_num = sweep_num; + radar->v[SW_INDEX]->sweep[sweep_num]->h.sweep_num = sweep_num; + + radar->v[DZ_INDEX]->sweep[sweep_num]->h.elev = + map_head->angfix[sweep_num]/10.0; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.elev = + map_head->angfix[sweep_num]/10.0; + radar->v[VR_INDEX]->sweep[sweep_num]->h.elev = + map_head->angfix[sweep_num]/10.0; + radar->v[SW_INDEX]->sweep[sweep_num]->h.elev = + map_head->angfix[sweep_num]/10.0; + + radar->v[DZ_INDEX]->sweep[sweep_num]->h.beam_width = 1.65; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.beam_width = 1.65; + radar->v[VR_INDEX]->sweep[sweep_num]->h.beam_width = 1.65; + radar->v[SW_INDEX]->sweep[sweep_num]->h.beam_width = 1.65; + + radar->v[DZ_INDEX]->sweep[sweep_num]->h.horz_half_bw = 0.85; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.horz_half_bw = 0.85; + radar->v[VR_INDEX]->sweep[sweep_num]->h.horz_half_bw = 0.85; + radar->v[SW_INDEX]->sweep[sweep_num]->h.horz_half_bw = 0.85; + + radar->v[DZ_INDEX]->sweep[sweep_num]->h.vert_half_bw = 0.85; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.vert_half_bw = 0.85; + radar->v[VR_INDEX]->sweep[sweep_num]->h.vert_half_bw = 0.85; + radar->v[SW_INDEX]->sweep[sweep_num]->h.vert_half_bw = 0.85; + + radar->v[DZ_INDEX]->sweep[sweep_num]->h.nrays = nrays; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.nrays = nrays; + radar->v[VR_INDEX]->sweep[sweep_num]->h.nrays = nrays; + radar->v[SW_INDEX]->sweep[sweep_num]->h.nrays = nrays; + } + else if (map_head->data_set == 19) + { + radar->v[ZT_INDEX]->sweep[sweep_num]->h.sweep_num = sweep_num; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.elev = + map_head->angfix[sweep_num]/10.0; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.beam_width = 1.65; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.horz_half_bw = 0.825; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.vert_half_bw = 0.825; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.nrays = nrays; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.f = DZ_F; + radar->v[ZT_INDEX]->sweep[sweep_num]->h.invf = DZ_INVF; + } + else /* Another data type? */ + { + } + } + + + +void fill_volume_header(Radar *radar, tg_map_head_str *map_head) + { + if (map_head->data_set == 1) + { + radar->v[DZ_INDEX] = RSL_new_volume(MAX_SWEEPS); + radar->v[ZT_INDEX] = RSL_new_volume(MAX_SWEEPS); + radar->v[VR_INDEX] = RSL_new_volume(MAX_SWEEPS); + radar->v[SW_INDEX] = RSL_new_volume(MAX_SWEEPS); + radar->v[DZ_INDEX]->h.type_str = strdup("Reflectivity"); + radar->v[ZT_INDEX]->h.type_str = strdup("Reflectivity"); + radar->v[VR_INDEX]->h.type_str = strdup("Velocity"); + radar->v[SW_INDEX]->h.type_str = strdup("Spectrum width"); + radar->v[DZ_INDEX]->h.nsweeps = map_head->numfix_ang; + radar->v[ZT_INDEX]->h.nsweeps = map_head->numfix_ang; + radar->v[VR_INDEX]->h.nsweeps = map_head->numfix_ang; + radar->v[SW_INDEX]->h.nsweeps = map_head->numfix_ang; + radar->v[DZ_INDEX]->h.f = DZ_F; + radar->v[DZ_INDEX]->h.invf = DZ_INVF; + radar->v[ZT_INDEX]->h.f = DZ_F; + radar->v[ZT_INDEX]->h.invf = DZ_INVF; + radar->v[VR_INDEX]->h.f = VR_F; + radar->v[VR_INDEX]->h.invf = VR_INVF; + radar->v[SW_INDEX]->h.f = SW_F; + radar->v[SW_INDEX]->h.invf = SW_INVF; + } + else if (map_head->data_set == 19) + { + radar->v[ZT_INDEX] = RSL_new_volume(MAX_SWEEPS); + radar->v[ZT_INDEX]->h.type_str = strdup("Reflectivity"); + radar->v[ZT_INDEX]->h.nsweeps = map_head->numfix_ang; + radar->v[ZT_INDEX]->h.f = DZ_F; + radar->v[ZT_INDEX]->h.invf = DZ_INVF; + } + else /* Another data type? */ + { + } + } + + +void fill_radar_header(Radar *radar, tg_map_head_str *map_head) + { + radar->h.month = map_head->scan_mon; + radar->h.day = map_head->scan_day; + radar->h.year = map_head->scan_year; + radar->h.hour = map_head->scan_hour; + radar->h.minute = map_head->scan_min; + radar->h.sec = map_head->scan_sec/100.0; + strcpy(radar->h.radar_type, "toga"); + radar->h.number = 0; + strcpy(radar->h.name, ""); + strcpy(radar->h.radar_name, "TOGA"); + strcpy(radar->h.city, "Darwin"); + strcpy(radar->h.state, ""); + /* The following lat, lon coordinates obtained from Dave Wolff */ + radar->h.latd = -12; + radar->h.latm = -27; + radar->h.lats = -26; + radar->h.lond = 130; + radar->h.lonm = 55; + radar->h.lons = 31; + radar->h.height = 37; + radar->h.spulse = 500; /* ns */ + radar->h.lpulse = 2000; /* ns */ + } + + + + +Radar *RSL_toga_to_radar(char *infile) + /* Ingest a Darwin_Toga file and fill a Radar structure with the data. + Darwin Type 1 data contains 4 fields: corrected & uncorrected refl, + velocity, and spectrum width. + Darwin type 19 data contains 1 field: uncorrected reflectivity. + Ignore all other Darwin data types. + Handle only PPI scans; ignore RHI scans. */ + { + int m, swp_num, num_bins; + Radar *radar; + Ray *new_ray; + tg_file_str tg_file; + extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */ + extern int rsl_qsweep_max; + + /* open the toga data file and read toga file header into the + tg_file map_head_structure */ + if (tg_open(infile,&tg_file) < 0) /* Understands NULL 'infile' as stdin. */ + { + if (radar_verbose_flag) + fprintf(stderr,"Error opening/reading data file\n"); + close(tg_file.fd); + return NULL; + } + if (radar_verbose_flag) + { + fprintf(stderr,"Input file: %s\n",infile); + fprintf(stderr,"Scan_date: %.2d/%.2d/%d\n",tg_file.map_head.scan_mon, + tg_file.map_head.scan_day,tg_file.map_head.scan_year); + fprintf(stderr,"Scan_time: %.2d:%.2d\n",tg_file.map_head.scan_hour, + tg_file.map_head.scan_min); + } + /* If this toga file does not contain a PPI (constant elevation) + scan, do not bother with it. Just quit. */ + if (tg_file.map_head.scanmod != 1) + { + if (radar_verbose_flag) + fprintf(stderr,"Darwtoga file %s does not contain a PPI scan.\n",infile); + close(tg_file.fd); + return NULL; + } + /* Can handle only datatypes 1 and 19 */ + if ((tg_file.map_head.data_set != 1) && + (tg_file.map_head.data_set != 19)) + { + if (radar_verbose_flag) + fprintf(stderr,"File %s does not contain Doppler or refl data\n",infile); + close(tg_file.fd); + return NULL; + } + if (radar_verbose_flag) + { + if (tg_file.map_head.data_set == 1) fprintf(stderr,"Type 1 data\n"); + else if (tg_file.map_head.data_set == 19) fprintf(stderr,"Type 19 data\n"); + else fprintf(stderr,"Unknown data type\n"); + } + + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + fill_radar_header(radar, &tg_file.map_head); + fill_volume_header(radar, &tg_file.map_head); + + /* initialize counters */ + tg_file.ray_num = -1; + swp_num = -1; + + /* Main loop to read in a toga ray from the toga + data file and store into radar structure */ + while ((m=tg_read_ray(&tg_file)) > 0) + { + /* check for end_of_sweep. Fill the sweep header _after_ we've + read in the sweep */ + if (swp_num < tg_file.ray_head.tilt - 1) /* new sweep? */ + { + if (swp_num >= 0) + { + /* fill the sweep header for the previous sweep */ + fill_sweep_header(radar, &tg_file.map_head, swp_num, + tg_file.ray_num+1); + } + tg_file.ray_num = -1; /* Reset ray_num. */ + swp_num += 1; /* increment sweep count */ + if (rsl_qsweep != NULL) { + if (swp_num > rsl_qsweep_max) break; + if (rsl_qsweep[swp_num] == 0) continue; + } + /* Check for too many sweeps. */ + if ((tg_file.map_head.numfix_ang < swp_num + 1) || + (MAX_SWEEPS < swp_num + 1)) + { + perror("toga_to_radar: Exceeded expected no. of sweeps"); + close(tg_file.fd); + RSL_free_radar(radar); + return NULL; + } + /* Create new sweep structures. */ + if (tg_file.map_head.data_set == 1) + { + radar->v[DZ_INDEX]->sweep[swp_num] = RSL_new_sweep(MAX_RAYS); + radar->v[ZT_INDEX]->sweep[swp_num] = RSL_new_sweep(MAX_RAYS); + radar->v[VR_INDEX]->sweep[swp_num] = RSL_new_sweep(MAX_RAYS); + radar->v[SW_INDEX]->sweep[swp_num] = RSL_new_sweep(MAX_RAYS); + } + else if (tg_file.map_head.data_set == 19) + { + radar->v[ZT_INDEX]->sweep[swp_num] = RSL_new_sweep(MAX_RAYS); + } + } /* end if new sweep */ + + num_bins = tg_file.ray.num_bins[TG_DM_IND] + 4; /* types 1,19 data*/ + tg_file.ray_num += 1; + /* Check for too many rays. */ + if (tg_file.ray_num > MAX_RAYS) + { + perror("toga_to_radar: Exceeded maximal no. of rays"); + close(tg_file.fd); + RSL_free_radar(radar); + return NULL; + } + /* check for uncorrected reflectivity data */ + if (tg_file.ray.da_inv[TG_DM_IND] == TRUE) + { + new_ray = RSL_new_ray(num_bins); + radar->v[ZT_INDEX]->sweep[swp_num]->ray[tg_file.ray_num] = new_ray; + fill_ray_header(new_ray, &tg_file, swp_num, TG_DM_IND); + fill_ray(new_ray, &tg_file, TG_DM_IND); + } + /* check for corrected reflectivity data */ + if (tg_file.ray.da_inv[TG_DZ_IND] == TRUE) + { + new_ray = RSL_new_ray(num_bins); + radar->v[DZ_INDEX]->sweep[swp_num]->ray[tg_file.ray_num] = new_ray; + fill_ray_header(new_ray, &tg_file, swp_num, TG_DZ_IND); + fill_ray(new_ray, &tg_file, TG_DZ_IND); + } + /* check for velocity data */ + if (tg_file.ray.da_inv[TG_VR_IND] == TRUE) + { + new_ray = RSL_new_ray(num_bins); + radar->v[VR_INDEX]->sweep[swp_num]->ray[tg_file.ray_num] = new_ray; + fill_ray_header(new_ray, &tg_file, swp_num, TG_VR_IND); + fill_ray(new_ray, &tg_file, TG_VR_IND); + } + /* check for spectrum width data */ + if (tg_file.ray.da_inv[TG_SW_IND] == TRUE) + { + new_ray = RSL_new_ray(num_bins); + radar->v[SW_INDEX]->sweep[swp_num]->ray[tg_file.ray_num] = new_ray; + fill_ray_header(new_ray, &tg_file, swp_num, TG_SW_IND); + fill_ray(new_ray, &tg_file, TG_SW_IND); + } + } /* end while */ + + /* At this point, we are finished reading toga data records. + Fill in the last sweep header. */ + fill_sweep_header(radar, &tg_file.map_head, swp_num, + tg_file.ray_num+1); + + /* Check which flag the TOGA read_record routines returned, and + print appropriate terminating message */ + if (radar_verbose_flag) + { + switch (m) + { + case TG_END_DATA: + fprintf(stderr,"Reached end of data file\n"); + break; + case TG_RAY_READ_ERR: + fprintf(stderr,"Error reading toga ray\n"); + break; + case TG_RAY_NOTYPE: + fprintf(stderr,"Found unrecognized toga ray type\n"); + fprintf(stderr,"ray_type: %d\n",tg_file.ray_head.type); + break; + case TG_REC_NOSEQ: + fprintf(stderr,"found out-of-sequence toga record \n"); + break; + case -1: + fprintf(stderr,"Error reading toga ray_header \n"); + break; + default: + fprintf(stderr,"Error reading toga file \n"); + break; + } + } /* end if (radar_verbose_flag) */ + + close(tg_file.fd); + if (m == TG_END_DATA) { + radar = RSL_prune_radar(radar); + return radar; + } else + { + RSL_free_radar(radar); + return NULL; + } + + } diff --git a/toolkit_1BC-51_appl.h b/toolkit_1BC-51_appl.h new file mode 100644 index 0000000..1589f27 --- /dev/null +++ b/toolkit_1BC-51_appl.h @@ -0,0 +1,97 @@ +/* + Parameter definitions for 1B-51 and 1C-51 HDF + file handling applications using the TSDIS toolkit. + + Mike Kolander +*/ + +#define SCALE_FACTOR 100.0 /* Most data values placed into HDF file + are scaled by this factor. */ +#define X 200.0 /* Used to create 1C-51 reflectivity + values: + 1C-51_val = dBz_val - X * MaskValue, + where MaskValue = 0 or 1 . + */ + +/* For missing HDF header values. From TSDIS specs. */ +#define NOVAL_INT16 -9999 +#define NOVAL_INT32 -9999 +#define NOVAL_FLOAT -9999.9 + +/* HDF cell value flags. */ +#define NO_VALUE -32767 /* No value recorded in bin by radar site. */ +#define RNG_AMBIG_VALUE -32766 /* Range-ambiguous flag */ +#define NOECHO_VALUE -32765 /* Value too low for SNR */ +#define AP_VALUE -32764 /* Anomalous propagation flag */ + + +#define MAX_RANGE_1B51 230.0 /* Max range (km) for 1B-51. */ +#define MAX_RANGE_1C51 200.0 /* Max range (km) for 1C-51. */ +#define TK_MAX_FILENAME 256 /* 256 bytes for filename storage. */ + +/* ----------- Function return codes -------------- + See RSL files: radar_to_hdf_1.c, radar_to_hdf_2.c, hdf_to_radar.c + See application files: level_1.c, hdf_to_uf.c */ +#define OK 0 /* Nominal termination with product produced. */ +#define ABORT -1 /* PANIC exit -> No product produced. */ +#define INTER -2 /* Abort execution. Received signal INT, KILL, or STOP */ +#define QUIT -3 /* Anomalous_condition exit -> No product produced. */ +#define SHUTDOWN -4 /* Shut down all processing, including scripts. */ + +/* TSDIS toolkit parameter definitions. */ +#include "IO_GV.h" + + +/* VOS dimensions w.r.t toolkit. The toolkit L1 structure is logically + organized as a sequence of physical sweeps. */ +typedef struct +{ +int nparm; /* No. of toolkit parameters (ie, volumes) for this VOS. */ +int nsweep; +int nray[MAX_SWEEP]; +int ncell[MAX_SWEEP][MAX_PARM]; /* ncell[tk_sindex][pindex] */ +} tkVosSize; + + +/* VOS dimensions w.r.t RSL. RSL is logically organized as a sequence + of "volumes".*/ +typedef struct +{ +int maxNsweep; +int maxNray; /* Max(nray[sweep0] ... nray[nsweep-1]) */ +int nsweep[MAX_PARM]; +int nray[MAX_PARM][MAX_SWEEP]; +int ncell[MAX_PARM][MAX_SWEEP]; +/* Arrays of pointers mapping toolkit objects back to the + corresponding rsl objects. */ +Volume *v[MAX_PARM]; /* Maps each tk volume to a rsl volume. */ +Sweep *sweep[MAX_SWEEP]; /* Maps each tk sweep to a rsl sweep. */ +} rslVosSize; + + +typedef struct +{ +int vos_num; /* 0...MAX_VOS-1 : Position no. of this VOS in HDF file. */ +rslVosSize rsl; /* Dimensions of rsl radar structure. */ +tkVosSize tk; /* Dimensions of toolkit structure. */ +} VosSize; + +#define NUMBER_QC_PARAMS 10 +enum QC_parameters +{ + HTHRESH1, HTHRESH2, HTHRESH3, + ZTHRESH0, ZTHRESH1, ZTHRESH2, ZTHRESH3, + HFREEZE, DBZNOISE, ZCAL +}; + +/*************************************************************/ +/* */ +/* Function Prototypes */ +/* */ +/*************************************************************/ +/* Toolkit memory management functions in file: toolkit_memory_mgt.c */ +void TKfreeGVL1(L1B_1C_GV *gvl1); +int8 ***TKnewParmData1byte(int nsweep, int nray, int ncell); +int16 ***TKnewParmData2byte(int nsweep, int nray, int ncell); +PARAMETER *TKnewGVL1parm(void); +L1B_1C_GV *TKnewGVL1(void); diff --git a/toolkit_memory_mgt.c b/toolkit_memory_mgt.c new file mode 100644 index 0000000..dc6fdcd --- /dev/null +++ b/toolkit_memory_mgt.c @@ -0,0 +1,189 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + Mike Kolander + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIBTSDISTK +/****************************************************************** + + Memory management functions used for the dynamic allocation/ + deallocation of TSDIS Toolkit GV_Level_1 structures, created when + reading/writing to an HDF file. + + Functions herein are called by RSL_radar_to_hdf() and RSL_hdf_to_radar(). + +*******************************************************************/ + +/* TSDIS toolkit function and structure definitions. */ +#include "IO.h" +#include "IO_GV.h" + +/* ------ Functions defined in this file. ------- */ +/* +void TKfreeGVL1(L1B_1C_GV *gvl1); +int8 ***TKnewParmData1byte(int nsweep, int nray, int ncell); +int16 ***TKnewParmData2byte(int nsweep, int nray, int ncell); +PARAMETER *TKnewGVL1parm(void); +L1B_1C_GV *TKnewGVL1(void); +*/ + +/*************************************************************/ +/* */ +/* TKfreeGVL1 */ +/* */ +/*************************************************************/ +void TKfreeGVL1(L1B_1C_GV *gvl1) +{ +/* Frees all memory which was (dynamically) allocated to the toolkit + 'L1B_1C_GV' structure, and associated substructures. +*/ + int pindex; + + for (pindex=0; pindexsensor.parm[pindex] != NULL) + { + if (gvl1->sensor.parm[pindex]->parmData1byte != NULL) + { + free(gvl1->sensor.parm[pindex]->parmData1byte[0][0]); + free(gvl1->sensor.parm[pindex]->parmData1byte[0]); + free(gvl1->sensor.parm[pindex]->parmData1byte); + } /* end if (gvl1->sensor.parm[pindex]->parmData1byte != NULL) */ + else if (gvl1->sensor.parm[pindex]->parmData2byte != NULL) + { + free(gvl1->sensor.parm[pindex]->parmData2byte[0][0]); + free(gvl1->sensor.parm[pindex]->parmData2byte[0]); + free(gvl1->sensor.parm[pindex]->parmData2byte); + } /* end if (gvl1->sensor.parm[pindex]->parmData1byte != NULL) */ + free(gvl1->sensor.parm[pindex]); + } /* end if (gvl1->sensor.parm[pindex] != NULL)*/ + } /* end for (pindex=0;*/ + + free(gvl1); +} + +/*************************************************************/ +/* */ +/* TKnewParmData1byte */ +/* */ +/*************************************************************/ +int8 ***TKnewParmData1byte(int nsweep, int nray, int ncell) +{ +/* Allocates memory for indexed storage of a 3_dimensional array + of 1_byte mask values associated with one parameter of the + toolkit 'L1B_1C_GV' structure. +*/ + int8 ***parmData1byte; + int8 **ray; + int8 *data; + int sindex, rindex; + + /* Vector for 'nsweep' sweep pointers. */ + parmData1byte = (int8 ***)calloc(nsweep, sizeof(int8 **)); + /* 2D array for 'nsweep*nray' ray pointers. */ + ray = (int8 **)calloc(nsweep*nray, sizeof(int8 *)); + /* 3D array for data. */ + data = (int8 *)calloc(nsweep*nray*ncell, sizeof(int8)); + + /* Fill all the sweep and ray pointer slots created above. */ + for (sindex=0; sindexparmData1byte = (int8 ***)NULL; + parm->parmData2byte = (int16 ***)NULL; + return(parm); +} + +/*************************************************************/ +/* */ +/* TKnewGVL1 */ +/* */ +/*************************************************************/ +L1B_1C_GV *TKnewGVL1(void) +{ +/* Allocates memory for a 'L1B_1C_GV' structure. */ + L1B_1C_GV *gvl1; + int pindex; + + gvl1 = (L1B_1C_GV *)calloc(1, sizeof(L1B_1C_GV)); + for (pindex=0; pindexsensor.parm[pindex] = (PARAMETER *)NULL; + + return(gvl1); +} + +#endif diff --git a/uf_to_radar.c b/uf_to_radar.c new file mode 100644 index 0000000..ed51f63 --- /dev/null +++ b/uf_to_radar.c @@ -0,0 +1,633 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include +#include +#include + +#include "rsl.h" + +extern int radar_verbose_flag; +typedef short UF_buffer[16384]; /* Some UF files are bigger than 4096 + * that the UF doc's specify. + */ + +#define UF_MORE 0 +#define UF_DONE 1 + +static float (*f)(Range x); +static Range (*invf)(float x); + +Volume *reset_nsweeps_in_volume(Volume *volume) +{ + int i; + if (volume == NULL) return NULL; + for (i=volume->h.nsweeps; i>0; i--) + if (volume->sweep[i-1] != NULL) { + volume->h.nsweeps = i; + break; + } + return volume; +} +Radar *reset_nsweeps_in_all_volumes(Radar *radar) +{ + int i; + if (radar == NULL) return NULL; + for (i=0; ih.nvolumes; i++) + radar->v[i] = reset_nsweeps_in_volume(radar->v[i]); + return radar; +} + +Volume *copy_sweeps_into_volume(Volume *new_volume, Volume *old_volume) +{ + int i; + int nsweeps; + if (old_volume == NULL) return new_volume; + if (new_volume == NULL) return new_volume; + nsweeps = new_volume->h.nsweeps; /* Save before copying old header. */ + new_volume->h = old_volume->h; + new_volume->h.nsweeps = nsweeps; + for (i=0; ih.nsweeps; i++) + new_volume->sweep[i] = old_volume->sweep[i]; /* Just copy pointers. */ + /* Free the old sweep array, not the pointers to sweeps. */ + free(old_volume->sweep); + return new_volume; +} + +void swap2(short *buf, int n) +{ + short *end_addr; + end_addr = buf + n; + while (buf < end_addr) { + swap_2_bytes(buf); + buf++; + } +} + + +/********************************************************************/ +/*********************************************************************/ +/* */ +/* uf_into_radar */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* August 26, 1994 */ +/*********************************************************************/ +int uf_into_radar(UF_buffer uf, Radar **the_radar) +{ + +/* Missing data flag : -32768 when a signed short. */ +#define UF_NO_DATA 0X8000 + + /* Any convensions may be observed, however, Radial Velocity must be VE. */ + /* Typically: + * DM = Reflectivity (dB(mW)). + * DZ = Reflectivity (dBZ). + * VR = Radial Velocity. + * CZ = Corrected Reflectivity. (Quality controlled: AP removed, etc.) + * SW = Spectrum Width. + * DR = Differential Reflectivity. + * XZ = X-band Reflectivity. + * + * These fields may appear in any order in the UF file. + * + * RETURN: + * UF_DONE if we're done with the UF ingest. + * UF_MORE if we need more UF data. + */ + + /* These are pointers to various locations within the UF buffer 'uf'. + * They are used to index the different components of the UF structure in + * a manor consistant with the UF documentation. For instance, uf_ma[1] + * will be equivalenced to the second word (2 bytes/each) of the UF + * buffer. + */ + short *uf_ma; /* Mandatory header block. */ + short *uf_lu; /* Local Use header block. */ + short *uf_dh; /* Data header. */ + short *uf_fh; /* Field header. */ + short *uf_data; /* Data. */ + + /* The length of each header. */ + int len_data, len_lu; + + int current_fh_index; + float scale_factor; + + int nfields, isweep, ifield, iray, i, m; + static int pulled_time_from_first_ray = 0; + char *field_type; /* For printing the field type upon error. */ + short proj_name[4]; + Ray *ray; + Sweep *sweep; + Radar *radar; + float x; + short missing_data; + Volume *new_volume; + int nbins; + extern int rsl_qfield[]; + extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */ + extern int rsl_qsweep_max; + + radar = *the_radar; + +/* + * The organization of the Radar structure is by volumes, then sweeps, then + * rays, then gates. This is different from the UF file organization. + * The UF format is sweeps, rays, then gates for all field types (volumes). + */ + + +/* Set up all the UF pointers. */ + uf_ma = uf; + uf_lu = uf + uf_ma[3] - 1; + uf_dh = uf + uf_ma[4] - 1; + + nfields = uf_dh[0]; + isweep = uf_ma[9] - 1; + + if (rsl_qsweep != NULL) { + if (isweep > rsl_qsweep_max) return UF_DONE; + if (rsl_qsweep[isweep] == 0) return UF_MORE; + } + + +/* Here is a sticky part. We must make sure that if we encounter any + * additional fields that were not previously present, that we are able + * to load them. This will require us to copy the entire radar structure + * and whack off the old one. But, we must be sure that it really is a + * new field. This is not so trivial as a couple of lines of code; I will + * have to think about this a little bit more. See STICKYSOLVED below. + */ +#ifdef STICKYSOLVED + if (radar == NULL) radar = RSL_new_radar(nfields); + /* Sticky solution here. */ +#else + if (radar == NULL) { + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + *the_radar = radar; + pulled_time_from_first_ray = 0; + for (i=0; iv[i] = RSL_new_volume(20); + } + +#endif +/* For LITTLE ENDIAN: + * WE "UNSWAP" character strings. Because there are so few of them, + * it is easier to catch them here. The entire UF buffer is swapped prior + * to entry to here, therefore, undo-ing these swaps; sets the + * character strings right. + */ + + for (i=0; iv[ifield] == NULL) continue; /* Nope. */ + + if (isweep >= radar->v[ifield]->h.nsweeps) { /* Exceeded sweep limit. + * Allocate more sweeps. + * Copy all previous sweeps. + */ + if (radar_verbose_flag) + fprintf(stderr,"Exceeded sweep allocation of %d. Adding 20 more.\n", isweep); + new_volume = RSL_new_volume(radar->v[ifield]->h.nsweeps+20); + new_volume = copy_sweeps_into_volume(new_volume, radar->v[ifield]); + radar->v[ifield] = new_volume; + } + + if (radar->v[ifield]->sweep[isweep] == NULL) { + if (radar_verbose_flag) + fprintf(stderr,"Allocating new sweep for field %d, isweep %d\n", ifield, isweep); + radar->v[ifield]->sweep[isweep] = RSL_new_sweep(1000); + radar->v[ifield]->sweep[isweep]->h.nrays = 0; /* Increment this for each + * ray encountered. + */ + radar->v[ifield]->h.f = f; + radar->v[ifield]->h.invf = invf; + radar->v[ifield]->sweep[isweep]->h.f = f; + radar->v[ifield]->sweep[isweep]->h.invf = invf; + radar->v[ifield]->sweep[isweep]->h.sweep_num = uf_ma[9]; + radar->v[ifield]->sweep[isweep]->h.elev = uf_ma[35] / 64.0; + } + + + + current_fh_index = uf_dh[4+2*i]; + uf_fh = uf + current_fh_index - 1; + sweep = radar->v[ifield]->sweep[isweep]; + iray = sweep->h.nrays; + nbins = uf_fh[5]; + radar->v[ifield]->sweep[isweep]->ray[iray] = RSL_new_ray(nbins); + ray = radar->v[ifield]->sweep[isweep]->ray[iray]; + sweep->h.nrays += 1; + + + if (ray) { + /* + * ---- Beginning of MANDATORY HEADER BLOCK. + */ + ray->h.ray_num = uf_ma[7]; + if (little_endian()) swap2(&uf_ma[10], 8); + memcpy(radar->h.radar_name, &uf_ma[10], 8); + if (little_endian()) swap2(&uf_ma[10], 8/2); + memcpy(radar->h.name, &uf_ma[14], 8); + if (little_endian()) swap2(&uf_ma[14], 8/2); + + /* All components of lat/lon are the same sign. If not, then + * what ever wrote the UF was in error. A simple RSL program + * can repair the damage, however, not here. + */ + ray->h.lat = uf_ma[18] + uf_ma[19]/60.0 + uf_ma[20]/64.0/3600; + ray->h.lon = uf_ma[21] + uf_ma[22]/60.0 + uf_ma[23]/64.0/3600; + ray->h.alt = uf_ma[24]; + ray->h.year = uf_ma[25]; + if (ray->h.year < 1900) { + ray->h.year += 1900; + if (ray->h.year < 1980) ray->h.year += 100; /* Year >= 2000. */ + } + ray->h.month = uf_ma[26]; + ray->h.day = uf_ma[27]; + ray->h.hour = uf_ma[28]; + ray->h.minute = uf_ma[29]; + ray->h.sec = uf_ma[30]; + ray->h.azimuth = uf_ma[32] / 64.0; + + /* If Local Use Header is present and contains azimuth, use that + * azimuth for VR and SW. This is for WSR-88D, which runs separate + * scans for DZ and VR/SW at the lower elevations, which means DZ + * VR/SW and have different azimuths in the "same" ray. + */ + len_lu = uf_ma[4] - uf_ma[3]; + if (len_lu == 2 && (ifield == VR_INDEX || ifield == SW_INDEX)) { + if (strncmp((char *)uf_lu,"ZA",2) == 0 || + strncmp((char *)uf_lu,"AZ",2) == 0) + ray->h.azimuth = uf_lu[1] / 64.0; + } + if (ray->h.azimuth < 0.) ray->h.azimuth += 360.; /* make it 0 to 360. */ + ray->h.elev = uf_ma[33] / 64.0; + ray->h.elev_num = sweep->h.sweep_num; + ray->h.fix_angle = sweep->h.elev = uf_ma[35] / 64.0; + ray->h.azim_rate = uf_ma[36] / 64.0; + ray->h.sweep_rate = ray->h.azim_rate * (60.0/360.0); + missing_data = uf_ma[44]; + + if (pulled_time_from_first_ray == 0) { + radar->h.height = uf_ma[24]; + radar->h.latd = uf_ma[18]; + radar->h.latm = uf_ma[19]; + radar->h.lats = uf_ma[20] / 64.0; + radar->h.lond = uf_ma[21]; + radar->h.lonm = uf_ma[22]; + radar->h.lons = uf_ma[23] / 64.0; + radar->h.year = ray->h.year; + radar->h.month = ray->h.month; + radar->h.day = ray->h.day; + radar->h.hour = ray->h.hour; + radar->h.minute = ray->h.minute; + radar->h.sec = ray->h.sec; + strcpy(radar->h.radar_type, "uf"); + pulled_time_from_first_ray = 1; + } + /* + * ---- End of MANDATORY HEADER BLOCK. + */ + + /* ---- Optional header used for MCTEX files. */ + /* If this is a MCTEX file, the first 4 words following the + mandatory header contain the string 'MCTEX'. */ + memcpy(proj_name, (short *)(uf + uf_ma[2] - 1), 8); + if (little_endian()) swap2(proj_name, 4); + + + /* ---- Local Use Header (if present) was checked during Mandatory + * Header processing above. + */ + + /* ---- Begining of FIELD HEADER. */ + uf_fh = uf+current_fh_index - 1; + scale_factor = uf_fh[1]; + ray->h.range_bin1 = uf_fh[2] * 1000.0 + uf_fh[3]; + ray->h.gate_size = uf_fh[4]; + + ray->h.nbins = uf_fh[5]; + ray->h.pulse_width = uf_fh[6]/(RSL_SPEED_OF_LIGHT/1.0e6); + + if (strncmp((char *)proj_name, "MCTEX", 5) == 0) /* MCTEX? */ + { + /* The beamwidth values are not correct in Mctex UF files. */ + ray->h.beam_width = 1.0; + sweep->h.beam_width = ray->h.beam_width; + sweep->h.horz_half_bw = ray->h.beam_width/2.0; + sweep->h.vert_half_bw = ray->h.beam_width/2.0; + } + else /* Not MCTEX */ + { + ray->h.beam_width = uf_fh[7] / 64.0; + sweep->h.beam_width = uf_fh[7] / 64.0; + sweep->h.horz_half_bw = uf_fh[7] / 128.0; /* DFF 4/4/95 */ + sweep->h.vert_half_bw = uf_fh[8] / 128.0; /* DFF 4/4/95 */ + } + /* fprintf (stderr, "uf_fh[7] = %d, [8] = %d\n", (int)uf_fh[7], (int)uf_fh[8]); */ + if((int)uf_fh[7] == -32768) { + ray->h.beam_width = 1; + sweep->h.beam_width = 1; + sweep->h.horz_half_bw = .5; + sweep->h.vert_half_bw = .5; + } + + ray->h.frequency = uf_fh[9] / 64.0; + ray->h.wavelength = uf_fh[11] / 64.0 / 100.0; /* cm to m. */ + ray->h.pulse_count = uf_fh[12]; + if (ifield == DZ_INDEX || ifield == ZT_INDEX) { + radar->v[ifield]->h.calibr_const = uf_fh[16] / 100.0; + /* uf value scaled by 100 */ + } + else { + radar->v[ifield]->h.calibr_const = 0.0; + } + if (uf_fh[17] == (short)UF_NO_DATA) x = 0; + else x = uf_fh[17] / 1000000.0; /* PRT in seconds. */ + if (x != 0) { + ray->h.prf = 1/x; + ray->h.unam_rng = RSL_SPEED_OF_LIGHT / (2.0 * ray->h.prf * 1000.0); + } + else { + ray->h.prf = 0.0; + ray->h.unam_rng = 0.0; + } + + if (VR_INDEX == ifield || VE_INDEX == ifield) { + ray->h.nyq_vel = uf_fh[19] / scale_factor; + } + + /* ---- End of FIELD HEADER. */ + + ray->h.f = f; + ray->h.invf = invf; + + /* ---- Begining of FIELD DATA. */ + uf_data = uf+uf_fh[0] - 1; + + len_data = ray->h.nbins; /* Known because of RSL_new_ray. */ + for (m=0; mrange[m] = invf(BADVAL); /* BADVAL */ + else { + if(uf_data[m] == missing_data) + ray->range[m] = invf(NOECHO); /* NOECHO */ + else + ray->range[m] = invf((float)uf_data[m]/scale_factor); + } + } + } + } + return UF_MORE; +} + + +/*********************************************************************/ +/* */ +/* swap_uf_buffer */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* October 4, 1994 */ +/*********************************************************************/ +void swap_uf_buffer(UF_buffer uf) +{ + short *addr_end; + + addr_end = uf + sizeof(UF_buffer)/sizeof(short); + while (uf < addr_end) + swap_2_bytes(uf++); +} + +enum UF_type {NOT_UF, TRUE_UF, TWO_BYTE_UF, FOUR_BYTE_UF}; + + +/*********************************************************************/ +/* */ +/* RSL_uf_to_radar_fp */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* September 22, 1995 */ +/*********************************************************************/ +Radar *RSL_uf_to_radar_fp(FILE *fp) +{ + union { + char buf[6]; + short sword; + int word; + } magic; + Radar *radar; + int nbytes; + short sbytes; + UF_buffer uf; + enum UF_type uf_type; +#define NEW_BUFSIZ 16384 + + + radar = NULL; + setvbuf(fp,NULL,_IOFBF,(size_t)NEW_BUFSIZ); /* Faster i/o? */ + if (fread(magic.buf, sizeof(char), 6, fp) <= 0) return NULL; +/* + * Check for fortran record length delimeters, NCAR kludge. + */ + if (strncmp("UF", magic.buf, 2) == 0) uf_type = TRUE_UF; + else if (strncmp("UF", &magic.buf[2], 2) == 0) uf_type = TWO_BYTE_UF; + else if (strncmp("UF", &magic.buf[4], 2) == 0) uf_type = FOUR_BYTE_UF; + else uf_type = NOT_UF; + + switch (uf_type) { + case FOUR_BYTE_UF: + if (radar_verbose_flag) fprintf(stderr,"UF file with 4 byte FORTRAN record delimeters.\n"); + /* Handle first record specially, since we needed magic information. */ + nbytes = magic.word; + if (little_endian()) swap_4_bytes(&nbytes); + memcpy(uf, &magic.buf[4], 2); + (void)fread(&uf[1], sizeof(char), nbytes-2, fp); + if (little_endian()) swap_uf_buffer(uf); + (void)fread(&nbytes, sizeof(int), 1, fp); + if (uf_into_radar(uf, &radar) == UF_DONE) break; + /* Now the rest of the file. */ + while(fread(&nbytes, sizeof(int), 1, fp) > 0) { + if (little_endian()) swap_4_bytes(&nbytes); + + (void)fread(uf, sizeof(char), nbytes, fp); + if (little_endian()) swap_uf_buffer(uf); + + (void)fread(&nbytes, sizeof(int), 1, fp); + + if (uf_into_radar(uf, &radar) == UF_DONE) break; + } + break; + + case TWO_BYTE_UF: + if (radar_verbose_flag) fprintf(stderr,"UF file with 2 byte FORTRAN record delimeters.\n"); + /* Handle first record specially, since we needed magic information. */ + sbytes = magic.sword; + if (little_endian()) swap_2_bytes(&sbytes); + memcpy(uf, &magic.buf[2], 4); + (void)fread(&uf[2], sizeof(char), sbytes-4, fp); + if (little_endian()) swap_uf_buffer(uf); + (void)fread(&sbytes, sizeof(short), 1, fp); + uf_into_radar(uf, &radar); + /* Now the rest of the file. */ + while(fread(&sbytes, sizeof(short), 1, fp) > 0) { + if (little_endian()) swap_2_bytes(&sbytes); + + (void)fread(uf, sizeof(char), sbytes, fp); + if (little_endian()) swap_uf_buffer(uf); + + (void)fread(&sbytes, sizeof(short), 1, fp); + + if (uf_into_radar(uf, &radar) == UF_DONE) break; + } + break; + + case TRUE_UF: + if (radar_verbose_flag) fprintf(stderr,"UF file with no FORTRAN record delimeters. Good.\n"); + /* Handle first record specially, since we needed magic information. */ + memcpy(&sbytes, &magic.buf[2], 2); /* Record length is in word #2. */ + if (little_endian()) swap_2_bytes(&sbytes); /* # of 2 byte words. */ + + memcpy(uf, &magic.buf[0], 6); + (void)fread(&uf[3], sizeof(short), sbytes-3, fp); + if (little_endian()) swap_uf_buffer(uf); + uf_into_radar(uf, &radar); + /* Now the rest of the file. */ + while(fread(uf, sizeof(short), 2, fp) > 0) { + memcpy(&sbytes, &uf[1], 2); /* Record length is in word #2. */ + if (little_endian()) swap_2_bytes(&sbytes); + + (void)fread(&uf[2], sizeof(short), sbytes-2, fp); /* Have words 1,2. */ + if (little_endian()) swap_uf_buffer(uf); + + if (uf_into_radar(uf, &radar) == UF_DONE) break; + } + break; + + case NOT_UF: return NULL; break; + } + radar = reset_nsweeps_in_all_volumes(radar); + radar = RSL_prune_radar(radar); + + return radar; +} + + +/*********************************************************************/ +/* */ +/* RSL_uf_to_radar */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* September 22, 1995 */ +/*********************************************************************/ +Radar *RSL_uf_to_radar(char *infile) +{ +/* + * This routine ingests a UF file and fills the Radar structure. + * This routine allocates space via the system routine malloc. + * + * If *infile is NULL, read from stdin. + */ + FILE *fp; + Radar *radar; + + radar = NULL; + if (infile == NULL) { + int save_fd; + save_fd = dup(0); + fp = fdopen(save_fd, "r"); + } else if ((fp = fopen(infile, "r")) == NULL) { + perror(infile); + return radar; + } + fp = uncompress_pipe(fp); /* Transparently gunzip. */ + radar = RSL_uf_to_radar_fp(fp); + rsl_pclose(fp); + + return radar; +} diff --git a/volume.c b/volume.c new file mode 100644 index 0000000..4c17f95 --- /dev/null +++ b/volume.c @@ -0,0 +1,1620 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * Volume functions coded in this file: + * + * Default DZ_F and DZ_INVF. For VR, SW, CZ, ZT, DR and LR too. + * Volume *RSL_new_volume(int max_sweeps); + * Sweep *RSL_new_sweep(int max_rays); + * Ray *RSL_new_ray(int max_bins); + * Ray *RSL_clear_ray(Ray *r); + * Sweep *RSL_clear_sweep(Sweep *s); + * Volume *RSL_clear_volume(Volume *v); + * void RSL_free_ray(Ray *r); + * void RSL_free_sweep(Sweep *s); + * void RSL_free_volume(Volume *v); + * Ray *RSL_copy_ray(Ray *r); + * Sweep *RSL_copy_sweep(Sweep *s); + * Volume *RSL_copy_volume(Volume *v); + * Ray *RSL_get_ray_from_sweep(Sweep *s, float azim); + * float RSL_get_value_from_sweep(Sweep *s, float azim, float r); + * float RSL_get_value_from_ray(Ray *ray, float r); + * float RSL_get_value_at_h(Volume *v, float azim, float grnd_r, float h); + * Sweep *RSL_get_sweep(Volume *v, float elev); + * Ray *RSL_get_ray(Volume *v, float elev, float azimuth); + * float RSL_get_value(Volume *v, float elev, float azimuth, float range); + * Ray *RSL_get_ray_above(Volume *v, Ray *current_ray); + * Ray *RSL_get_ray_below(Volume *v, Ray *current_ray); + * Ray *RSL_get_matching_ray(Volume *v, Ray *ray); + * int RSL_get_sweep_index_from_volume + * + * See image_gen.c for the Volume image generation functions. + * + * See doc/rsl_index.html for HTML formatted documentation. + * + * All routines herein coded, unless otherwise stated, by: + * John Merritt + * Space Applications Corporation + * + * Contributions by + * Dennis Flanigan, Jr. + * flanigan@lance.colostate.edu + */ +#include +#include +#include +#include +#include +int strcasecmp(const char *s1, const char *s2); + +#define USE_RSL_VARS +#include "rsl.h" + +#define bin_azimuth(x, dx) (float)((float)x/dx) +#define bin_elevation(x, dx) (float)((float)x/dx) +#define bin_range(x, dx) (float)((float)x/dx) + +extern int radar_verbose_flag; + +/* Internal storage conversion functions. These may be any conversion and + * may be dynamically defined; based on the input data conversion. If you + * change any of the reserved values, ie. values that cannot be converted + * from/to internal storage (BADVAL, APFLAG, etc), be sure to change all + * functions, both XX_F and XX_INVF to handle it. It is best to have the + * reserved values stored at 0, 1, 2, on up. That way you merely need to + * provide an offset to the actual conversion function. See 'rsl.h' + * for the definition of the reserved values. Currently: BADVAL, RFVAL, + * APFLAG, NOECHO. + * + * The conversion functions may NOT be macros. + */ + +#ifdef USE_TWO_BYTE_PRECISION +#define F_FACTOR 100.0 +#define F_DR_FACTOR 1000.0 +#define F_DZ_RANGE_OFFSET 50 +#else +#define F_FACTOR 2.0 +#define F_DR_FACTOR 10.0 +#define F_DZ_RANGE_OFFSET 32 +#endif + +/* IMPORTANT: This is the offset from reserved values. This + * number must be exactly (or >=) the number of + * reserved values in XX_F and XX_INVF. + * + * You must change nsig_to_radar.c where F_OFFSET is used for optimization. + */ +#define F_OFFSET 4 + + +float DZ_F(Range x) { + if (x >= F_OFFSET) /* This test works when Range is unsigned. */ + return (((float)x-F_OFFSET)/F_FACTOR - F_DZ_RANGE_OFFSET); /* Default wsr88d. */ + if (x == 0) return BADVAL; + if (x == 1) return RFVAL; + if (x == 2) return APFLAG; + if (x == 3) return NOECHO; + return BADVAL; /* Can't get here, but quiets the compiler. */ +} + +float VR_F(Range x) { + float val; + if (x >= F_OFFSET) { /* This test works when Range is unsigned. */ + val = (((float)x-F_OFFSET)/F_FACTOR - 63.5); /* Default wsr88d coding. */ + /* fprintf(stderr, "x=%d, val=%f\n", x, val); */ + return val; + } + if (x == 0) return BADVAL; + if (x == 1) return RFVAL; + if (x == 2) return APFLAG; + if (x == 3) return NOECHO; + return BADVAL; /* Can't get here, but quiets the compiler. */ +} + +float DR_F(Range x) { /* Differential reflectivity */ + float val; + if (x >= F_OFFSET) { /* This test works when Range is unsigned. */ + val = (((float)x-F_OFFSET)/F_DR_FACTOR - 12.0); + return val; + } + if (x == 0) return BADVAL; + if (x == 1) return RFVAL; + if (x == 2) return APFLAG; + if (x == 3) return NOECHO; + return BADVAL; /* Can't get here, but quiets the compiler. */ +} + +float LR_F(Range x) {/* From MCTEX */ + if (x >= F_OFFSET) /* This test works when Range is unsigned. */ + return (float) (x - 250.)/6.; + if (x == 0) return BADVAL; + if (x == 1) return RFVAL; + if (x == 2) return APFLAG; + if (x == 3) return NOECHO; + return BADVAL; + } + +/**************************** + Sigmet RhoHV : one_byte values +> RohHV = sqrt((N-1)/253) +> 0 bad/no value +> 1 0.0000 +> 2 0.0629 +> 128 0.7085 +> 253 0.9980 +> 254 1.0000 +*******************************/ +float RH_F(Range x) { + if (x == 0) return BADVAL; + return (float)(sqrt((double)((x-1.0)/253.0))); + } + +/***************************** + Sigmet PhiDP : one_byte values +> PhiDP (mod 180) = 180 * ((N-1)/254) +> The range is from 0 to 180 degrees in steps of 0.71 as follows. +> 0 bad/no value +> 1 0.00 deg +> 2 0.71 deg +> 101 70.87 deg +> 254 179.29 deg +******************************/ +float PH_F(Range x) { + if (x == 0) return BADVAL; + return (float)(180.0*((x-1.0)/254.0)); + } + +float rsl_kdp_wavelen = 0.5; /* Default radar wavelen = .5 cm. See + * nsig_to_radar.c for the code that sets this. + */ +float KD_F(Range x) +{ + if (x >= F_OFFSET) { + x -= F_OFFSET; + if (rsl_kdp_wavelen == 0.0) return BADVAL; + if (x < 128) + return (float)( + -0.25 * pow((double)600.0,(double)((127-x)/126.0)) + )/rsl_kdp_wavelen; + else if (x > 128) + return (float)( + 0.25 * pow((double)600.0,(double)((x-129)/126.0)) + )/rsl_kdp_wavelen; + else + return 0.0; + } + if (x == 0) return BADVAL; + if (x == 1) return RFVAL; + if (x == 2) return APFLAG; + if (x == 3) return NOECHO; + return BADVAL; +} + +float SQ_F(Range x) { + if (x >= F_OFFSET) return (float)((x - F_OFFSET)/10000.); + if (x == 0) return BADVAL; + if (x == 1) return RFVAL; + if (x == 2) return APFLAG; + if (x == 3) return NOECHO; + return BADVAL; /* Can't get here, but quiets the compiler. */ +} + +float TI_F(Range x) +{ + if (x >= F_OFFSET) return (float)(x); + if (x == 0) return BADVAL; + if (x == 1) return RFVAL; + if (x == 2) return APFLAG; + if (x == 3) return NOECHO; + return BADVAL; +} + +float SW_F(Range x) { return VR_F(x); } +float CZ_F(Range x) { return DZ_F(x); } +float ZT_F(Range x) { return DZ_F(x); } +float ZD_F(Range x) { return DR_F(x); } /* Differential reflectivity */ +float CD_F(Range x) { return DR_F(x); } /* Differential reflectivity */ +float XZ_F(Range x) { return DZ_F(x); } +float MZ_F(Range x) { return (float)x; } /* DZ Mask */ +float MD_F(Range x) { return MZ_F(x); } /* ZD Mask */ +float ZE_F(Range x) { return DZ_F(x); } +float VE_F(Range x) { return VR_F(x); } +float DM_F(Range x) { return DZ_F(x); } +float DX_F(Range x) { return DZ_F(x); } +float CH_F(Range x) { return DZ_F(x); } +float AH_F(Range x) { return DZ_F(x); } +float CV_F(Range x) { return DZ_F(x); } +float AV_F(Range x) { return DZ_F(x); } + + + + +/* Unfortunately, floats are stored differently than ints/shorts. So, + * we cannot simply set up a switch statement and we must test for + * all the special cases first. We must test for exactness. + */ +Range DZ_INVF(float x) +{ + if (x == BADVAL) return (Range)0; + if (x == RFVAL) return (Range)1; + if (x == APFLAG) return (Range)2; + if (x == NOECHO) return (Range)3; + return (Range)(F_FACTOR*(x+F_DZ_RANGE_OFFSET)+.5 + F_OFFSET); /* Default wsr88d. */ +} + +Range VR_INVF(float x) +{ + if (x == BADVAL) return (Range)0; + if (x == RFVAL) return (Range)1; + if (x == APFLAG) return (Range)2; + if (x == NOECHO) return (Range)3; + return (Range)(F_FACTOR*(x+63.5)+.5 + F_OFFSET); /* Default wsr88d coding. */ +} + +Range DR_INVF(float x) /* Differential reflectivity */ +{ + if (x == BADVAL) return (Range)0; + if (x == RFVAL) return (Range)1; + if (x == APFLAG) return (Range)2; + if (x == NOECHO) return (Range)3; + return (Range)(F_DR_FACTOR*(x + 12.0) + F_OFFSET + 0.5); +} + +Range LR_INVF(float x) /* MCTEX */ +{ + if (x == BADVAL) return (Range)0; + if (x == RFVAL) return (Range)1; + if (x == APFLAG) return (Range)2; + if (x == NOECHO) return (Range)3; + return (Range)((6.*x + 250) + 0.5); /* Round */ +} + +/************************** + Sigmet RhoHV : one_byte values +> RohHV = sqrt((N-1)/253) +> 0 bad/no value +> 1 0.0000 +> 2 0.0629 +> 128 0.7085 +> 253 0.9980 +> 254 1.0000 +****************************/ +Range RH_INVF(float x) { + if (x == BADVAL) return (Range)0; + return (Range)(x * x * 253.0 + 1.0 + 0.5); +} + +/****************************** + Sigmet PhiDP : one_byte values +> PhiDP (mod 180) = 180 * ((N-1)/254) +> The range is from 0 to 180 degrees in steps of 0.71 as follows. +> 0 bad/no value +> 1 0.00 deg +> 2 0.71 deg +> 101 70.87 deg +> 254 179.29 deg +*******************************/ +Range PH_INVF(float x) { + if (x == BADVAL) return (Range)0; + return (Range)((x / 180.0) * 254.0 + 1.0 + 0.5); +} + +Range KD_INVF(float x) { + if (x == BADVAL) return (Range)0; + if (x == RFVAL) return (Range)1; + if (x == APFLAG) return (Range)2; + if (x == NOECHO) return (Range)3; + if (rsl_kdp_wavelen == 0.0) return (Range)0; + if (x < 0) { + x = 127 - + 126 * (log((double)-x) - log((double)(0.25/rsl_kdp_wavelen))) / + log((double)600.0) + + 0.5; + } else if (x > 0) { + x = 129 + + 126 * (log((double)x) - log((double)0.25/rsl_kdp_wavelen)) / + log((double)600.0) + + 0.5; + } else { + x = 128; + } + x += F_OFFSET; + return (Range) x; + +} + +Range SQ_INVF(float x) /* Signal Quality Index */ +{ + if (x == BADVAL) return (Range)0; + if (x == RFVAL) return (Range)1; + if (x == APFLAG) return (Range)2; + if (x == NOECHO) return (Range)3; + return (Range)(x * 10000. + F_OFFSET); +} + +Range TI_INVF(float x) /* MCTEX */ +{ + if (x == BADVAL) return (Range)0; + if (x == RFVAL) return (Range)1; + if (x == APFLAG) return (Range)2; + if (x == NOECHO) return (Range)3; + return (Range)(x); +} + + +Range SW_INVF(float x) { return VR_INVF(x); } +Range CZ_INVF(float x) { return DZ_INVF(x); } +Range ZT_INVF(float x) { return DZ_INVF(x); } +Range ZD_INVF(float x) { return DR_INVF(x); } /* Differential reflectivity */ +Range CD_INVF(float x) { return DR_INVF(x); } /* Differential reflectivity */ +Range XZ_INVF(float x) { return DZ_INVF(x); } +Range MZ_INVF(float x) { return (Range)x; } /* DZ Mask */ +Range MD_INVF(float x) { return MZ_INVF(x); } /* ZD Mask */ +Range ZE_INVF(float x) { return DZ_INVF(x); } +Range VE_INVF(float x) { return VR_INVF(x); } +Range DM_INVF(float x) { return DZ_INVF(x); } +Range DX_INVF(float x) { return DZ_INVF(x); } +Range CH_INVF(float x) { return DZ_INVF(x); } +Range AH_INVF(float x) { return DZ_INVF(x); } +Range CV_INVF(float x) { return DZ_INVF(x); } +Range AV_INVF(float x) { return DZ_INVF(x); } + + + +/**********************************************************************/ +/* M E M O R Y M A N A G E M E N T R O U T I N E S */ +/**********************************************************************/ +/**********************************************************************/ +/* */ +/* new_volume */ +/* new_sweep */ +/* new_ray */ +/* */ +/**********************************************************************/ +Volume *RSL_new_volume(int max_sweeps) +{ + /* + * A volume consists of a header section and an array of sweeps. + */ + Volume *v; + v = (Volume *)calloc(1, sizeof(Volume)); + if (v == NULL) perror("RSL_new_volume"); + v->sweep = (Sweep **) calloc(max_sweeps, sizeof(Sweep*)); + if (v->sweep == NULL) perror("RSL_new_volume, Sweep*"); + v->h.nsweeps = max_sweeps; /* A default setting. */ + return v; +} + +/* + * The 'Sweep_list' structure is internal to RSL. It maintains a list + * of sweeps allocated and it contains pointers to a hash table of Rays + * separately for each sweep. There is no reason to access this internal + * structure except when optimizing new RSL routines that access Rays. + * Otherwise, the RSL interfaces should suffice. + * + * The hash table is a means of finding rays, by azimuth, quickly. + * To find a ray is simple: use the hash function to get close + * to the ray, if not right on it the first time. Collisions of rays in + * the hash table are handled by a link list of rays from a hash entry. + * Typically, the first ray of the sweep is not the ray with the smallest + * azimuth angle. We are confident that the order of Rays in the Sweep + * is by azimuth angle, but that cannot be guarenteed. Therefore, this + * hash scheme is required. + * + * The 'Sweep_list' contains the address of the memory allocated to + * sweep. The list is sorted by addresses. There is no + * memory limit to the number of sweeps. If the number of sweeps exceeds + * the current allocation for the Sweep_list, then a new Sweep_list is + * allocated, which is bigger, and the old list copied to it. + * + * Sweep_list is at least as long as the number of sweeps allocated. + */ + +typedef struct { + Sweep *s_addr; + Hash_table *hash; +} Sweep_list; + +/* + * By design of RSL, this should be "#define STATIC static" + * + * It is OK to "#define STATIC static", but, if you do, then + * the examples (run by run_tests in examples/) will fail for + * those programs that test these data structures. I normally, + * don't set this #define, for that reason. + */ + +#define STATIC +STATIC int RSL_max_sweeps = 0; /* Initial allocation for sweep_list. + * RSL_new_sweep will allocate the space first + * time around. + */ +STATIC int RSL_nsweep_addr = 0; /* A count of sweeps in the table. */ +STATIC Sweep_list *RSL_sweep_list = NULL; +STATIC int RSL_nextents = 0; + +void FREE_HASH_NODE(Azimuth_hash *node) +{ + if (node == NULL) return; + FREE_HASH_NODE(node->next); /* Tail recursive link list removal. */ + free(node); +} + +void FREE_HASH_TABLE(Hash_table *table) +{ + int i; + if (table == NULL) return; + for (i=0; inindexes; i++) + FREE_HASH_NODE(table->indexes[i]); /* A possible linked list of Rays. */ + free(table->indexes); + free(table); +} + +void REMOVE_SWEEP(Sweep *s) +{ + int i; + int j; + /* Find where it goes, split the list and slide the tail down one. */ + for (i=0; i= RSL_max_sweeps) { /* Current list is too small. */ + RSL_nextents++; + new_list = (Sweep_list *) calloc(100*RSL_nextents, sizeof(Sweep_list)); + if (new_list == NULL) { + perror("INSERT_SWEEP"); + exit(2); + } + /* Copy the old list to the new one. */ + for (i=0; ii; j--) + RSL_sweep_list[j] = RSL_sweep_list[j-1]; + + RSL_sweep_list[i].s_addr = s; + RSL_sweep_list[i].hash = NULL; + RSL_nsweep_addr++; + return i; +} + +int SWEEP_INDEX(Sweep *s) +{ + /* Locate the sweep in the RSL_sweep_list. Return the index. */ + /* Simple linear search; but this will be a binary search. */ + int i; + for (i=0; iray = (Ray **) calloc(max_rays, sizeof(Ray*)); + if (s->ray == NULL) perror("RSL_new_sweep, Ray*"); + s->h.nrays = max_rays; /* A default setting. */ + return s; +} + +Ray *RSL_new_ray(int max_bins) +{ + /* + * A ray consists of a header section and an array of Range types (floats). + */ + Ray *r; + r = (Ray *)calloc(1, sizeof(Ray)); + if (r == NULL) perror("RSL_new_ray"); + r->range = (Range *) calloc(max_bins, sizeof(Range)); + if (r->range == NULL) perror("RSL_new_ray, Range"); + r->h.nbins = max_bins; /* A default setting. */ +/* fprintf(stderr,"range[0] = %x, range[%d] = %x\n", &r->range[0], max_bins-1, &r->range[max_bins-1]);*/ + return r; +} + +/**********************************************************************/ +/* */ +/* clear_ray */ +/* clear_sweep */ +/* clear_volume */ +/* */ +/**********************************************************************/ +Ray *RSL_clear_ray(Ray *r) +{ + if (r == NULL) return r; + memset(r->range, 0, sizeof(Range)*r->h.nbins); + return r; +} +Sweep *RSL_clear_sweep(Sweep *s) +{ + int i; + if (s == NULL) return s; + for (i=0; ih.nrays; i++) { + RSL_clear_ray(s->ray[i]); + } + return s; +} +Volume *RSL_clear_volume(Volume *v) +{ + int i; + if (v == NULL) return v; + for (i=0; ih.nsweeps; i++) { + RSL_clear_sweep(v->sweep[i]); + } + return v; +} +/**********************************************************************/ +/* */ +/* free_ray */ +/* free_sweep */ +/* free_volume */ +/* */ +/**********************************************************************/ +void RSL_free_ray(Ray *r) +{ + if (r == NULL) return; + if (r->range) free(r->range); + free(r); +} +void RSL_free_sweep(Sweep *s) +{ + int i; + if (s == NULL) return; + for (i=0; ih.nrays; i++) { + RSL_free_ray(s->ray[i]); + } + if (s->ray) free(s->ray); + REMOVE_SWEEP(s); /* Remove from internal Sweep list. */ + free(s); +} +void RSL_free_volume(Volume *v) +{ + int i; + if (v == NULL) return; + + for (i=0; ih.nsweeps; i++) + { + RSL_free_sweep(v->sweep[i]); + } + if (v->sweep) free(v->sweep); + free(v); +} + +/**********************************************************************/ +/* */ +/* copy_ray */ +/* copy_sweep */ +/* copy_volume */ +/* */ +/**********************************************************************/ +Ray *RSL_copy_ray(Ray *r) +{ + Ray *new_ray; + + if (r == NULL) return NULL; + new_ray = RSL_new_ray(r->h.nbins); + new_ray->h = r->h; + memcpy(new_ray->range, r->range, r->h.nbins*sizeof(Range)); + return new_ray; +} +Sweep *RSL_copy_sweep(Sweep *s) +{ + int i; + Sweep *n_sweep; + + if (s == NULL) return NULL; + n_sweep = RSL_new_sweep(s->h.nrays); + if (n_sweep == NULL) return NULL; + n_sweep->h = s->h; + + for (i=0; ih.nrays; i++) { + n_sweep->ray[i] = RSL_copy_ray(s->ray[i]); + } + return n_sweep; +} + + + +Volume *RSL_copy_volume(Volume *v) +{ + int i; + Volume *new_vol; + + if (v == NULL) return NULL; + new_vol = RSL_new_volume(v->h.nsweeps); + new_vol->h = v->h; + + for (i=0; ih.nsweeps; i++) { + new_vol->sweep[i] = RSL_copy_sweep(v->sweep[i]); + } + return new_vol; +} + + +/**********************************************************************/ +/**********************************************************************/ +/* G E N E R A L F U N C T I O N S */ +/**********************************************************************/ +/**********************************************************************/ + +double angle_diff(float x, float y) +{ + double d; + d = fabs((double)(x - y)); + if (d > 180) d = 360 - d; + return d; +} + +/**********************************************************************/ +/* */ +/* RSL_get_next_cwise_ray */ +/* Dennis Flanigan */ +/* Mods by John Merritt 10/20/95 */ +/**********************************************************************/ +Ray *RSL_get_next_cwise_ray(Sweep *s, Ray *ray) +{ + /* The fastest way to do this is to gain access to the hash table + * which maintains a linked list of sorted rays. + */ + Hash_table *hash_table; + Azimuth_hash *closest; + int hindex; + float ray_angle; + + if (s == NULL) return NULL; + if (ray == NULL) return NULL; + /* Find a non-NULL index close to hindex that we want. */ + hash_table = hash_table_for_sweep(s); + if (hash_table == NULL) return NULL; /* Nada. */ + ray_angle = ray->h.azimuth; + hindex = hash_bin(hash_table,ray_angle); + + /* Find hash entry with closest Ray */ + closest = the_closest_hash(hash_table->indexes[hindex],ray_angle); + + return closest->ray_high->ray; +} + +/**********************************************************************/ +/* */ +/* RSL_get_next_ccwise_ray */ +/* JHM 10/20/95 */ +/**********************************************************************/ +Ray *RSL_get_next_ccwise_ray(Sweep *s, Ray *ray) +{ + /* The fastest way to do this is to gain access to the hash table + * which maintains a linked list of sorted rays. + */ + Hash_table *hash_table; + Azimuth_hash *closest; + int hindex; + float ray_angle; + + if (s == NULL) return NULL; + if (ray == NULL) return NULL; + /* Find a non-NULL index close to hindex that we want. */ + hash_table = hash_table_for_sweep(s); + if (hash_table == NULL) return NULL; /* Nada. */ + ray_angle = ray->h.azimuth; + hindex = hash_bin(hash_table,ray_angle); + + /* Find hash entry with closest Ray */ + closest = the_closest_hash(hash_table->indexes[hindex],ray_angle); + + return closest->ray_low->ray; +} + + +/****************************************** + * * + * cwise_angle_diff * + * * + * Dennis Flanigan,Jr. 5/17/95 * + ******************************************/ +double cwise_angle_diff(float x,float y) + { + /* Returns the clockwise angle difference of x to y. + * If x = 345 and y = 355 return 10. + * If x = 345 and y = 335 return 350 + */ + double d; + + d = (double)(y - x); + if (d < 0) d += 360; + return d; + } + +/****************************************** + * * + * ccwise_angle_diff * + * * + * Dennis Flanigan,Jr. 5/17/95 * + ******************************************/ +double ccwise_angle_diff(float x,float y) + { + /* Returns the counterclockwise angle differnce of x to y. + * If x = 345 and y = 355 return 350. + * If x = 345 and y = 335 return 10 + */ + double d; + + d = (double)(x - y); + if (d < 0) d += 360; + return d; + } + +/***************************************** + * * + * the_closest_hash * + * * + * Dennis Flanigan,Jr. 4/29/95 * + *****************************************/ +Azimuth_hash *the_closest_hash(Azimuth_hash *hash, float ray_angle) + { + /* Return the hash pointer with the minimum ray angle difference. */ + + double clow,chigh,cclow; + Azimuth_hash *high,*low; + + if (hash == NULL) return NULL; + + /* Set low pointer to hash index with ray angle just below + * requested angle and high pointer to just above requested + * angle. + */ + + /* set low and high pointers to initial search locations*/ + low = hash; + high = hash->ray_high; + + /* Search until clockwise angle to high is less then clockwise + * angle to low. + */ + + clow = cwise_angle_diff(ray_angle,low->ray->h.azimuth); + chigh = cwise_angle_diff(ray_angle,high->ray->h.azimuth); + cclow = ccwise_angle_diff(ray_angle,low->ray->h.azimuth); + + while((chigh > clow) && (clow != 0)) + { + if (clow < cclow) + { + low = low->ray_low; + high = low->ray_high; /* Not the same low as line before ! */ + } + else + { + low = low->ray_high; + high = low->ray_high; /* Not the same low as line before ! */ + } + + clow = cwise_angle_diff(ray_angle,low->ray->h.azimuth); + chigh = cwise_angle_diff(ray_angle,high->ray->h.azimuth); + cclow = ccwise_angle_diff(ray_angle,low->ray->h.azimuth); + } + + if(chigh <= cclow) + { + return high; + } + else + { + return low; + } + } + + +/*******************************************************************/ +/* */ +/* get_closest_sweep_index */ +/* */ +/* Dennis Flanigan, Jr. 5/15/95 */ +/*******************************************************************/ +int get_closest_sweep_index(Volume *v,float sweep_angle) + { + Sweep *s; + int i,ci; + float delta_angle = 91; + float check_angle; + + if(v == NULL) return -1; + + ci = 0; + + for (i=0; ih.nsweeps; i++) + { + s = v->sweep[i]; + if (s == NULL) continue; + check_angle = fabs((double)(s->h.elev - sweep_angle)); + + if(check_angle <= delta_angle) + { + delta_angle = check_angle; + ci = i; + } + } + + return ci; + } + + + + + +/********************************************************************/ +/* */ +/* RSL_get_closest_sweep */ +/* */ +/* Dennis Flanigan, Jr. 5/15/95 */ +/********************************************************************/ +Sweep *RSL_get_closest_sweep(Volume *v,float sweep_angle,float limit) + { + /* Find closest sweep to requested angle. Assume PPI sweep for + * now. Meaning: sweep_angle represents elevation angle from + * 0->90 degrees + */ + Sweep *s; + float delta_angle; + int ci; + + if (v == NULL) return NULL; + + if((ci = get_closest_sweep_index(v,sweep_angle)) < 0) + { + return NULL; + } + + s = v->sweep[ci]; + + delta_angle = fabs((double)(s->h.elev - sweep_angle)); + + if( delta_angle <= limit) + { + return s; + } + else + { + return NULL; + } + } + +/**********************************************************************/ +/* These are more specific routines to make coding hierarchical. */ +/* */ +/* done 4/7/95 Ray *RSL_get_ray_from_sweep */ +/* done 3/31 float RSL_get_value_from_sweep */ +/* done 3/31 float RSL_get_value_from_ray */ +/* done 4/1 float RSL_get_value_at_h */ +/* */ +/**********************************************************************/ +Ray *RSL_get_ray_from_sweep(Sweep *s, float ray_angle) +{ + /* Locate the Ray * for ray_angle in the sweep. */ + + /* Sanity checks. */ + if (s == NULL) return NULL; + if (ray_angle < 0) ray_angle += 360.0; /* Only positive angles. */ + if (ray_angle >= 360) ray_angle -= 360; + + return RSL_get_closest_ray_from_sweep(s,ray_angle,s->h.horz_half_bw); +} + +/********************************************** + * * + * hash_bin * + * * + * Dennis Flanigan, Jr. 4/27/95 * + **********************************************/ +int hash_bin(Hash_table *table,float angle) +{ + /* Internal Routine to calculate the hashing bin index + * of a given angle. + */ + int hash; + float res; + + res = 360.0/table->nindexes; + hash = (int)(angle/res + res/2.0);/*Centered about bin.*/ + + if(hash >= table->nindexes) hash = hash - table->nindexes; + + /* Could test see which direction is closer, but + * why bother? + */ + while(table->indexes[hash] == NULL) { + hash++; + if(hash >= table->nindexes) hash = 0; + } + + return hash; +} + +Hash_table *hash_table_for_sweep(Sweep *s) +{ + int i; + + i = SWEEP_INDEX(s); + if (i==-1) { /* Obviously, an unregistered sweep. Most likely the + * result of pointer assignments. + */ + i = INSERT_SWEEP(s); + } + + if (RSL_sweep_list[i].hash == NULL) { /* First time. Construct the table. */ + RSL_sweep_list[i].hash = construct_sweep_hash_table(s); + } + + return RSL_sweep_list[i].hash; +} + +/*********************************************************************/ +/* */ +/* RSL_get_closest_ray_from_sweep */ +/* */ +/* Dennis Flanigan 4/30/95 */ +/*********************************************************************/ +Ray *RSL_get_closest_ray_from_sweep(Sweep *s,float ray_angle, float limit) + { + /* + * Return closest Ray in Sweep within limit (angle) specified + * in parameter list. Assume PPI mode. + */ + int hindex; + Hash_table *hash_table; + Azimuth_hash *closest; + double close_diff; + + if (s == NULL) return NULL; + /* Find a non-NULL index close to hindex that we want. */ + hash_table = hash_table_for_sweep(s); + if (hash_table == NULL) return NULL; /* Nada. */ + + hindex = hash_bin(hash_table,ray_angle); + + /* Find hash entry with closest Ray */ + closest = the_closest_hash(hash_table->indexes[hindex],ray_angle); + + /* Is closest ray within limit parameter ? If + * so return ray, else return NULL. + */ + + close_diff = angle_diff(ray_angle,closest->ray->h.azimuth); + + if(close_diff <= limit) return closest->ray; + + return NULL; + } + + +/*********************************************************************/ +/* */ +/* Rsl_get_value_from_sweep */ +/* */ +/*********************************************************************/ +float RSL_get_value_from_sweep(Sweep *s, float azim, float r) +{ + /* Locate the polar point (r,azim) in the sweep. */ + Ray *ray; + if (s == NULL) return BADVAL; + ray = RSL_get_ray_from_sweep(s, azim); + if (ray == NULL) return BADVAL; + return RSL_get_value_from_ray(ray, r); +} + + +/*********************************************************************/ +/* */ +/* RSL_get_range_of_range_index */ +/* D. Flanigan 8/18/95 */ +/*********************************************************************/ +float RSL_get_range_of_range_index(Ray *ray, int index) + { + if (ray == NULL) return 0.0; + if (index >= ray->h.nbins) return 0.0; + return ray->h.range_bin1/1000.0 + index*ray->h.gate_size/1000.0; + } + + +/************************************/ +/* RSL_get_value_from_ray */ +/* */ +/* Updated 4/4/95 D. Flanigan */ +/* */ +/************************************/ +float RSL_get_value_from_ray(Ray *ray, float r) + { + int bin_index; + float rm; + + rm = r * 1000; + + if (ray == NULL) return BADVAL; + + if(ray->h.gate_size == 0) + { + if(radar_verbose_flag) + { + fprintf(stderr,"RSL_get_value_from_ray: ray->h.gate_size == 0\n"); + } + return BADVAL; + } + + /* range_bin1 is range to center of first bin */ + bin_index = (int)(((rm - ray->h.range_bin1)/ray->h.gate_size) + 0.5); + + /* Bin indexes go from 0 to nbins - 1 */ + if (bin_index >= ray->h.nbins || bin_index < 0) return BADVAL; + + return ray->h.f(ray->range[bin_index]); + } + + +/*********************************************************************/ +/* */ +/* RSL_get_value_at_h */ +/* */ +/*********************************************************************/ +float RSL_get_value_at_h(Volume *v, float azim, float grnd_r, float h) +{ + float elev, r; + + RSL_get_slantr_and_elev(grnd_r, h, &r, &elev); + return RSL_get_value(v, elev, azim, r); +} + + +/**********************************************************************/ +/* These take a Volume and return the appropriate structure. */ +/* */ +/* done 4/21/95 Sweep *RSL_get_sweep */ +/* done 4/1 Ray *RSL_get_ray */ +/* done 4/1 float *RSL_get_value */ +/* done 5/3 Ray *RSL_get_ray_above */ +/* done 5/3 Ray *RSL_get_ray_below */ +/* done 5/12 Ray *RSL_get_ray_from_other_volume */ +/* */ +/**********************************************************************/ + + + +/*********************************************************************/ +/* */ +/* RSL_get_sweep */ +/* */ +/* Updated 5/15/95 Dennis Flanigan, Jr. */ +/*********************************************************************/ +Sweep *RSL_get_sweep(Volume *v, float sweep_angle) + { + /* Return a sweep with +/- 1/2 beam_width of 'elev', if found. */ + int i = 0; + + if (v == NULL) return NULL; + while(v->sweep[i] == NULL) i++; + + return RSL_get_closest_sweep(v,sweep_angle,v->sweep[i]->h.vert_half_bw); + } + + +/*********************************************************************/ +/* */ +/* RSL_get_ray */ +/* */ +/*********************************************************************/ +Ray *RSL_get_ray(Volume *v, float elev, float azimuth) +{ + /* Locate 'elev' and 'azimuth' in the Volume v by a simple +/- epsilon on + * the elevation angle and azimuth angle. + */ + + /* + * 1. Locate sweep using azimuth; call RSL_get_sweep. + * 2. Call RSL_get_ray_from_sweep + */ + + return RSL_get_ray_from_sweep( RSL_get_sweep( v, elev ), azimuth ); +} + +/*********************************************************************/ +/* */ +/* RSL_get_value */ +/* */ +/*********************************************************************/ +float RSL_get_value(Volume *v, float elev, float azimuth, float range) +{ + /* Locate 'elev' and 'azimuth' and 'h.elev)) < 0) return NULL; + + i++; + while( i < v->h.nsweeps) + { + if(v->sweep[i] != NULL) break; + i++; + } + + if(i >= v->h.nsweeps) return NULL; + + return RSL_get_ray_from_sweep(v->sweep[i], current_ray->h.azimuth); + } + + +/*********************************************************************/ +/* */ +/* RSL_get_ray_below */ +/* */ +/* Updated 5/15/95, Dennis Flanigan, Jr. */ +/*********************************************************************/ +Ray *RSL_get_ray_below(Volume *v, Ray *current_ray) + { + int i; + + if (v == NULL) return NULL; + if (current_ray == NULL) return NULL; + + /* Find index of current Sweep */ + if(( i = get_closest_sweep_index(v,current_ray->h.elev)) < 0) return NULL; + + i--; + while( i >= 0) + { + if(v->sweep[i] != NULL) break; + i--; + } + + if(i < 0) return NULL; + + return RSL_get_ray_from_sweep(v->sweep[i], current_ray->h.azimuth); + } + +/*********************************************************************/ +/* */ +/* RSL_get_matching_ray */ +/* */ +/*********************************************************************/ +Ray *RSL_get_matching_ray(Volume *v, Ray *ray) +{ + + /* + * Locate the closest matching ray in the Volume 'v' to 'ray'. + * Typically, use this function when finding a similiar ray in another + * volume. + */ + if (v == NULL) return NULL; + if (ray == NULL) return NULL; + + return RSL_get_ray(v, ray->h.elev, ray->h.azimuth); +} + +/*********************************************************************/ +/* */ +/* RSL_get_first_ray_of_sweep */ +/* RSL_get_first_ray_of_volume */ +/* */ +/*********************************************************************/ +Ray *RSL_get_first_ray_of_sweep(Sweep *s) +{ +/* Because a sorting of azimuth angles may have been performed, + * we need to test on the ray_num member and look for the smallest + * one. + */ + int i; + Ray *r; + int smallest_ray_num; + + r = NULL; + smallest_ray_num = 9999999; + if (s == NULL) return r; + for (i=0; ih.nrays; i++) + if (s->ray[i]) { + if (s->ray[i]->h.ray_num <= 1) return s->ray[i]; + if (s->ray[i]->h.ray_num < smallest_ray_num) { + r = s->ray[i]; + smallest_ray_num = r->h.ray_num; + } + } + return r; +} + +Ray *RSL_get_first_ray_of_volume(Volume *v) +{ + int i; + if (v == NULL) return NULL; + for (i=0; ih.nsweeps; i++) + if (v->sweep[i]) return RSL_get_first_ray_of_sweep(v->sweep[i]); + return NULL; +} + +/*********************************************************************/ +/* */ +/* RSL_get_first_sweep_of_volume */ +/* */ +/*********************************************************************/ +Sweep *RSL_get_first_sweep_of_volume(Volume *v) +{ + int i; + if (v == NULL) return NULL; + for (i=0; ih.nsweeps; i++) + if (RSL_get_first_ray_of_sweep(v->sweep[i])) return v->sweep[i]; + return NULL; +} + +#define N_SPECIAL_NAMES 2 +/* + * Unfortunately in C, there is no way around initializing static + * arrays by specifying repetition. + * + * There is another solution and that is to have RSL_new_radar set + * a flag indicating if the application has called 'RSL_select_fields' + * prior to calling the ingest routine. I choose the static = {...}; method + * for now. + */ + +/* Could be static and force use of 'rsl_query_field' */ +int rsl_qfield[MAX_RADAR_VOLUMES] = { + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + }; + + +/*********************************************************************/ +/* */ +/* RSL_select_fields */ +/* */ +/*********************************************************************/ +void RSL_select_fields(char *field_type, ...) +{ + /* + * 10/15/96 + * field_type = Case insensitive: + * "all" - default, if never this routine is never called. + * "none" - No fields are ingestd. Useful for getting header + * information. + * "dz" - Ingest DZ volume. + * "vr" - Ingest VR volume. + * ... - Just list additional fields. + * + * The last argument must be NULL. This signals this routine + * when to stop parsing the field types. + * + * Action or side-effect: + * A second call to this fuction overrides any previous settings. + * In other words, multiple calls are not additive. So, to get both + * DZ and VR volumes, use: + * RSL_select_fields("dz", "vr"); - Read both DZ and VR. + * and not: + * RSL_select_fields("dz"); - Read only DZ. + * RSL_select_fields("vr"); - Read only VR, no DZ. + * + * An RSL hidden array is set to flag which fields are selected. + * This array is examined inside all ingest code. It is not available + * to the application. + */ + + va_list ap; + char *c_field; + int i; + + for (i=0; i> specified.\n", c_field); + } + } + c_field = va_arg(ap, char *); + } + + if (radar_verbose_flag) fprintf(stderr,"\n"); + va_end(ap); + +} + + +int rsl_query_field(char *c_field) +{ + /* + * 10/15/96 + * RSL interface, for library code developers, to rsl ingest code, + * which is intended to be part of RSL ingest code, which access + * the hidden array 'rsl_qfield' and reports if that field is to + * be ingested. + * + * Return 1 if YES, meaning yes ingest this field type. + * Return 0 if NO. + */ + + /* + * All ingest code is meant to use this routine to decide whether + * or not to allocate memory for a field type. For data formats + * that are very large, this will help optimize the ingest on + * small memory machines and hopefully avoid unnessary swapping. + * + * LASSEN is a good example where there may be 10 or 12 input field + * types, but the application only wants 2 or 3 of them. + * + * The application interface is RSL_select_fields. + */ + int i; + + /* Quiet the compilier when -pedantic. :-) */ + RSL_f_list[0] = RSL_f_list[0]; + RSL_invf_list[0] = RSL_invf_list[0]; + + for (i=0; i> specified.\n", c_field); + } + + /* 'i' is the index. Is it set? */ + return rsl_qfield[i]; +} + + +/* Could be static and force use of 'rsl_query_sweep' */ +int *rsl_qsweep = NULL; /* If NULL, then read all sweeps. Otherwise, + * read what is on the list. + */ +#define RSL_MAX_QSWEEP 500 /* It'll be rediculious to have more. :-) */ +int rsl_qsweep_max = RSL_MAX_QSWEEP; + +/*********************************************************************/ +/* */ +/* RSL_read_these_sweeps */ +/* */ +/*********************************************************************/ +void RSL_read_these_sweeps(char *csweep, ...) +{ + va_list ap; + char *c_sweep; + int i, isweep; + + /* "all", "none", "0", "1", "2", "3", ... */ + + /* # arguments, should be <= 'max # sweeps expected', but, what is it? + * We can handle typo's and redundancies. Each is processed in the + * order they appear. + */ + + c_sweep = csweep; + va_start(ap, csweep); + + rsl_qsweep_max = -1; + if (rsl_qsweep == NULL) + rsl_qsweep = (int *)calloc(RSL_MAX_QSWEEP, sizeof(int)); + + /* else Clear the array - a second call to this function over-rides + * any previous settings. This holds even if the second call has + * bad arguments. + */ + else + for(i = 0;i< RSL_MAX_QSWEEP; i++) + rsl_qsweep[i] = 0; + + + if (radar_verbose_flag) fprintf(stderr,"Selected sweeps for ingest:"); + for (;c_sweep; c_sweep = va_arg(ap, char *)) + { + /* CHECK EACH FIELD. This is a fancier case statement than C provides. */ + if (radar_verbose_flag) fprintf(stderr," %s", c_sweep); + if (strcasecmp(c_sweep, "all") == 0) { + for (i=0; i RSL_MAX_QSWEEP) { + if (radar_verbose_flag) fprintf(stderr,"\nRSL_read_these_sweeps: parameter %s not in [0,%d). Ignoring.\n", c_sweep, RSL_MAX_QSWEEP); + continue; + } + + if (isweep > rsl_qsweep_max) rsl_qsweep_max = isweep; + rsl_qsweep[isweep] = 1; + } + } + + if (radar_verbose_flag) fprintf(stderr,"\n"); + va_end(ap); +} + +#include +void RSL_fix_time (Ray *ray) +{ + struct tm the_time; + float fsec; + /* Fixes possible overflow values in month, day, year, hh, mm, ss */ + /* Normally, ss should be the overflow. This code ensures end of + * month, year and century are handled correctly by using the Unix + * time functions. + */ + if (ray == NULL) return; + memset(&the_time, 0, sizeof(struct tm)); + the_time.tm_sec = ray->h.sec; + fsec = ray->h.sec - the_time.tm_sec; + the_time.tm_min = ray->h.minute; + the_time.tm_hour = ray->h.hour; + the_time.tm_mon = ray->h.month - 1; + the_time.tm_year = ray->h.year - 1900; + the_time.tm_mday = ray->h.day; + the_time.tm_isdst = -1; + (void) mktime(&the_time); + /* The time is fixed. */ + ray->h.sec = the_time.tm_sec; + ray->h.sec += fsec; + ray->h.minute = the_time.tm_min; + ray->h.hour = the_time.tm_hour; + ray->h.month = the_time.tm_mon + 1; + ray->h.year = the_time.tm_year + 1900; + ray->h.day = the_time.tm_mday; + return; +} + +/*********************************************************************/ +/* */ +/* RSL_add_dbz_offset_to_ray */ +/* */ +/*********************************************************************/ +/* + Add the calibration factor 'dbz_offset' to each ray bin which + contains a valid value. +*/ +void RSL_add_dbz_offset_to_ray(Ray *r, float dbz_offset) +{ + int ibin; + float val; + + if (r == NULL) return; + for (ibin=0; ibinh.nbins; ibin++) + { + val = r->h.f(r->range[ibin]); + if ( val >= (float)NOECHO ) continue; /* Invalid value */ + r->range[ibin] = r->h.invf(val + dbz_offset); + } +} + +/*********************************************************************/ +/* */ +/* RSL_add_dbz_offset_to_sweep */ +/* */ +/*********************************************************************/ +void RSL_add_dbz_offset_to_sweep(Sweep *s, float dbz_offset) +{ + int iray; + if (s == NULL) return; + for (iray=0; irayh.nrays; iray++) + RSL_add_dbz_offset_to_ray(s->ray[iray], dbz_offset); +} + +/*********************************************************************/ +/* */ +/* RSL_add_dbz_offset_to_volume */ +/* */ +/*********************************************************************/ +void RSL_add_dbz_offset_to_volume(Volume *v, float dbz_offset) +{ + int isweep; + if (v == NULL) return; + for (isweep=0; isweeph.nsweeps; isweep++) + RSL_add_dbz_offset_to_sweep(v->sweep[isweep], dbz_offset); +} diff --git a/wsr88d.c b/wsr88d.c new file mode 100644 index 0000000..3339851 --- /dev/null +++ b/wsr88d.c @@ -0,0 +1,975 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + *------------------------------------------------------------ + * v1.14 5/12/95 + *------------------------------------------------------------ + * Procedures: + * wsr88d_open + * wsr88d_close + * wsr88d_read_file_header + * wsr88d_read_tape_header + * wsr88d_read_sweep + * wsr88d_read_ray + * wsr88d_perror + * wsr88d_ray_to_float + * + * Functions: + * wsr88d_get_nyquist + * wsr88d_get_atmos_atten_factor + * wsr88d_get_velocity_resolution + * wsr88d_get_volume_coverage + * wsr88d_get_elevation_angle + * wsr88d_get_azimuth + * wsr88d_get_range + * wsr88d_get_data + * wsr88d_get_time + * wsr88d_get_vcp_info(int vcp_num,int el_num) + * wsr88d_get_fix_angle(Wsr88d_ray *ray) + * wsr88d_get_pulse_count(Wsr88d_ray *ray) + * wsr88d_get_azimuth_rate(Wsr88d_ray *ray) + * wsr88d_get_pulse_width(Wsr88d_ray *ray) + * wsr88d_get_prt(Wsr88d_ray *ray) + * wsr88d_get_prf(Wsr88d_ray *ray) + * wsr88d_get_wavelength(Wsr88d_ray *ray) + * wsr88d_get_frequency(Wsr88d_ray *ray) + * + * Misc. routines: (canidates for possible inclusion into the library) + * print_head + * print_packet_info + * free_and_clear_sweep + * clear_sweep + * print_sweep_info + * Cvt_date <- From Dan Austin + * Cvt_time <- From Dan Austin + * + */ +#include +#include +#include +#include + +#include "wsr88d.h" + +static int little_endian(void) +{ + union { + unsigned char byte[4]; + int val; + } word; + word.val = 0; + word.byte[3] = 0x1; + return word.val != 1; +} + + +static void swap_4_bytes(void *word) +{ + unsigned char *byte; + unsigned char temp; + byte = word; + temp = byte[0]; + byte[0] = byte[3]; + byte[3] = temp; + temp = byte[1]; + byte[1] = byte[2]; + byte[2] = temp; +} + +static void swap_2_bytes(void *word) +{ + unsigned char *byte; + unsigned char temp; + byte = word; + temp = byte[0]; + byte[0] = byte[1]; + byte[1] = temp; +} + +/**********************************************************************/ +/* D E B U G G I N G R O U T I N E S F O L L O W */ +/**********************************************************************/ +/************************************************ + * Cvt_date- convert the date in days since 1/1/70 (Julian) to mm/dd/yy + * parameters: + * long int date_in - input julian date + * returns: output date + * calls from: Cvt_pckt_hdr + * calls to: none + ************************************************/ + +#include +int Cvt_date(long int date_in) +{ + int mm, dd, yy; + time_t itime; + struct tm *tm_time; + itime = date_in - 1; + itime *= 24*60*60; /* Seconds/day * days. */ + + tm_time = gmtime(&itime); + mm = tm_time->tm_mon+1; + dd = tm_time->tm_mday; + yy = tm_time->tm_year; + + return 10000.0*yy+100.0*mm+dd; +} + +/************************************************ + * Cvt_time- converts 24 hr time in msecs after midnight to hhmmss + * parameters: + * long int time_in - input time in msecs after midnight + * returns: double *time_out - output time + * calls from: Cvt_pckt_hdr + * calls to: none + ************************************************/ +float Cvt_time(long int time_in) +{ + double t; + int hh,mm; + + t = time_in; + t /= 1000.0; + hh = t/3600; + t -= hh*3600; + mm = t/60; + t -= mm*60; + + return hh*10000 + mm*100 + (float) t; +} +/**********************************************************************/ +/* */ +/* done 2/28 print_head */ +/* */ +/**********************************************************************/ +void print_head(Wsr88d_file_header h) +{ + int i; + fprintf(stderr,"Filename : "); + for (i=0;i<9;i++) fprintf(stderr,"%c", h.title.filename[i]); printf("\n"); + + fprintf(stderr,"Extension: "); + for (i=0;i<3;i++) fprintf(stderr,"%c", h.title.ext[i]); printf("\n"); + + fprintf(stderr,"Julian date: %d\n", Cvt_date(h.title.file_date)); + fprintf(stderr," time: %f\n", Cvt_time(h.title.file_time)); + + +} + +void print_packet_info(Wsr88d_packet *p) +{ + fprintf(stderr,"%5hd %5hd %5hd %5hd %5hd %5hd %5hd %10.3f %6d\n", + p->msg_type, p->id_seq, p->azm, p->ray_num, p->ray_status, p->elev, p->elev_num, + Cvt_time((int)p->ray_time), Cvt_date((int)p->ray_date)); +} + + + + +/**********************************************************************/ +/* End of debug routines. */ +/**********************************************************************/ + +void free_and_clear_sweep(Wsr88d_sweep *s, int low, int high) +{ +/* Frees and sets the ray pointers to NULL. + * Assumes that rays pointers have been allocated. + */ + int i; + for (i=low; iray[i] != NULL) { + free(s->ray[i]); + s->ray[i] = NULL; + } +} + +void clear_sweep(Wsr88d_sweep *s, int low, int high) +{ +/* + * Simply set all sweep pointers to NULL. + */ + int i; + for (i=low; iray[i] = NULL; +} + +void wsr88d_print_sweep_info(Wsr88d_sweep *s) +{ + int i; + + fprintf(stderr,"Mtype ID azim ray# rstat elev elev# time date\n"); + fprintf(stderr,"----- ----- ----- ----- ----- ----- ----- ---------- ------\n"); + + for (i=0; iray[i] != NULL) + print_packet_info((Wsr88d_packet *) s->ray[i]); + } +} + +/**********************************************************************/ +/* */ +/* done 2/28 wsr88d_open */ +/* */ +/**********************************************************************/ + +Wsr88d_file *wsr88d_open(char *filename) +{ + Wsr88d_file *wf = (Wsr88d_file *)malloc(sizeof(Wsr88d_file)); + int save_fd; + + if ( strcmp(filename, "stdin") == 0 ) { + save_fd = dup(0); + wf->fptr = fdopen(save_fd,"r"); + } else { + wf->fptr = fopen(filename, "r"); + } + + if (wf->fptr == NULL) return NULL; + wf->fptr = uncompress_pipe(wf->fptr); +#define NEW_BUFSIZ 16384 + setvbuf(wf->fptr,NULL,_IOFBF,(size_t)NEW_BUFSIZ); /* Faster i/o? */ + return wf; +} + + +/**********************************************************************/ +/* */ +/* done 2/28 wsr88d_perror */ +/* */ +/**********************************************************************/ +int wsr88d_perror(char *message) +{ +/* + * I want to use a global 'wsr88d_errno' and + * have this routine print an appropriate message. + */ + + /* This is a simple model now. */ + fprintf(stderr, "wsr88d_error: "); + perror(message); + return 0; +} + +/**********************************************************************/ +/* */ +/* done 2/28 wsr88d_close */ +/* */ +/**********************************************************************/ +int wsr88d_close(Wsr88d_file *wf) +{ + int rc; + rc = rsl_pclose(wf->fptr); + free(wf); + return rc; +} + + +/**********************************************************************/ +/* */ +/* wsr88d_swap_file_header */ +/* */ +/**********************************************************************/ +void wsr88d_swap_file_header(Wsr88d_file_header *header) +{ + swap_4_bytes(&header->title.file_date); + swap_4_bytes(&header->title.file_time); +} + +/**********************************************************************/ +/* */ +/* done 2/28 wsr88d_read_file_header */ +/* */ +/**********************************************************************/ +int wsr88d_read_file_header(Wsr88d_file *wf, + Wsr88d_file_header *wsr88d_file_header) +{ + int n; + n = fread(&wsr88d_file_header->title, + sizeof(wsr88d_file_header->title), 1, wf->fptr); + if (little_endian()) + wsr88d_swap_file_header(wsr88d_file_header); + return n; +} + +/**********************************************************************/ +/* */ +/* done 8/18 wsr88d_read_tape_header */ +/* */ +/**********************************************************************/ +int wsr88d_read_tape_header(char *first_file, + Wsr88d_tape_header *wsr88d_tape_header) +{ + FILE *fp; + int n; + char c; + + if ((fp = fopen(first_file, "r")) == NULL) { + perror(first_file); + return 0; + } + + n = fread(wsr88d_tape_header, sizeof(Wsr88d_tape_header), 1, fp); + if (n == 0) { + fprintf(stderr, "WARNING: %s is smaller than 31616 bytes. It is not a tape header file.\n", first_file); + } else { + /* Try to read one more character. If we can, then this is not a + * tape header file. I suppose that we could look for '.' as the + * 9-th character and if it were there, then too this is not a tape + * header file. + */ + if (fread(&c, sizeof(char), 1, fp) > 0) { + fprintf(stderr, "WARNING: %s is larger than 31616 bytes. It is not a tape header file.\n", first_file); + memset(wsr88d_tape_header, 0, sizeof(Wsr88d_tape_header)); + n = 0; + } else { /* Ok so far. Now check the first 8 bytes for "ARCHIVE2" */ + if (strncmp(wsr88d_tape_header->archive2, "ARCHIVE2", 8) != 0) { + fprintf(stderr, "WARNING: %s is 31616 bytes. However, the first 8 bytes are not 'ARCHIVE2'.\n", first_file); + memset(wsr88d_tape_header, 0, sizeof(Wsr88d_tape_header)); + n = 0; + } + } + + } + fclose(fp); + return n; +} + + + +/**********************************************************************/ +/* */ +/* not done N/A wsr88d_read_header */ +/* */ +/**********************************************************************/ +int wsr88d_read_header(Wsr88d_file *wf, Wsr88d_header *wsr88d_header) +{ + fprintf(stderr,"Routine: wsr88d_read_header\n"); + return 0; +} + + +/**********************************************************************/ +/* */ +/* done 3/2 wsr88d_read_sweep */ +/* */ +/**********************************************************************/ +int wsr88d_read_sweep(Wsr88d_file *wf, Wsr88d_sweep *wsr88d_sweep) +{ + int n; + Wsr88d_ray wsr88d_ray; + int nrec; + int end_of_volume; + int ray_num; + +/* One sweep is defined as staying at the same RDA elevation number. */ +/* We can read the file and check for that, however, we will need to + * buffer our input. The solution is to read the file and check the + * radial status. If it is '2' then we have reached the END OF ELEVATION. + * Here is a complete list of radial status codes: + * 0 = Start of new elevation. + * 1 = Intermediate radial. + * 2 = End of elevation. + * 3 = Beginning of volume scan. + * 4 = End of volume scan. + */ + +/* Algorithm steps: + * 1. Skip packets until. Start of new elevation or + * Beginning of Volume scan. STAT=0 or 3. + * 2. Read until End of elevation. STAT=2 or 4. Skip message type != 1. + */ + + nrec = 0; + ray_num = 0; + n = wsr88d_read_ray(wf, &wsr88d_ray); + +/* Step 1. */ + while ((wsr88d_ray.msg_type & 15) != 1 && n > 0) { + /* + fprintf(stderr,"SKIPPING packet: type %d, radial status %d\n", + wsr88d_ray.msg_type, wsr88d_ray.ray_status); + */ + n = wsr88d_read_ray(wf, &wsr88d_ray); + } + + if (n <= 0) return n; /* Read failure. */ + end_of_volume = 0; +/* Step 2. */ + while ( ! end_of_volume ) { + if ((wsr88d_ray.msg_type & 15) != 1) { + /* + fprintf(stderr,"SKIPPING (amid a sweep) packet: type %d, " + "radial status %d\n", + wsr88d_ray.msg_type, wsr88d_ray.ray_status); + */ + + } else { + /* Load this ray into the sweep. */ + ray_num = wsr88d_ray.ray_num; + /* Double check against # records we've seen. */ + /* It is possible that a reset occurs and we begin to overwrite + * previously loaded rays. I've seen this occur, rarely, in the + * WSR88D data. I must trust 'ray_num'. + */ + /* + if (nrec+1 != ray_num) { + fprintf(stderr, "Data says %d is ray_num, but, I've seen %d " + "records.\n", ray_num, nrec+1); + } + */ + if (wsr88d_sweep->ray[ray_num] == NULL) { + wsr88d_sweep->ray[ray_num] = (Wsr88d_ray *) malloc (sizeof(Wsr88d_ray)); + } + memcpy(wsr88d_sweep->ray[ray_num], &wsr88d_ray, sizeof(Wsr88d_ray)); + } + n = wsr88d_read_ray(wf, &wsr88d_ray); + if (n > 0) nrec++; + end_of_volume = wsr88d_ray.ray_status == 2 || + wsr88d_ray.ray_status == 4 || + n <= 0; + } + + /* Process the last packet of the input data. */ + if (wsr88d_ray.ray_status == 2 || wsr88d_ray.ray_status == 4) { + /* Load this ray into the sweep. */ + ray_num = wsr88d_ray.ray_num; + if (wsr88d_sweep->ray[ray_num] == NULL) { + wsr88d_sweep->ray[ray_num] = (Wsr88d_ray *) malloc (sizeof(Wsr88d_ray)); + } + memcpy(wsr88d_sweep->ray[ray_num], &wsr88d_ray, sizeof(Wsr88d_ray)); + } + + /* Just to be safe, clear all ray pointers left in this sweep to + * the maximum MAX_RAYS_IN_SWEEP. This is required when the + * wsr88d_sweep is reused and not cleared. + */ + free_and_clear_sweep(wsr88d_sweep, ray_num+1, MAX_RAYS_IN_SWEEP); + +/* + fprintf(stderr,"Processed %d records for elevation number %d\n", + nrec+1, wsr88d_ray.elev_num); + wsr88d_print_sweep_info(wsr88d_sweep); +*/ + return nrec; +} + +/**********************************************************************/ +/* */ +/* wsr88d_swap_ray */ +/* */ +/**********************************************************************/ +void wsr88d_swap_ray(Wsr88d_ray *wsr88d_ray) +{ + short *half_word; + half_word = (short *)wsr88d_ray; + for (; half_word<(short *)&wsr88d_ray->msg_time; half_word++) + swap_2_bytes(half_word); + + swap_4_bytes(&wsr88d_ray->msg_time); + swap_2_bytes(&wsr88d_ray->num_seg); + swap_2_bytes(&wsr88d_ray->seg_num); + swap_4_bytes(&wsr88d_ray->ray_time); + + half_word = (short *) &wsr88d_ray->ray_date; + for (; half_word<(short *)&wsr88d_ray->sys_cal; half_word++) + swap_2_bytes(half_word); + + swap_4_bytes(&wsr88d_ray->sys_cal); + + half_word = (short *) &wsr88d_ray->refl_ptr; + for (; half_word<(short *)&wsr88d_ray->data[0]; half_word++) + swap_2_bytes(half_word); + +} + +/**********************************************************************/ +/* */ +/* done 2/28 wsr88d_read_ray */ +/* */ +/**********************************************************************/ +int wsr88d_read_ray(Wsr88d_file *wf, Wsr88d_ray *wsr88d_ray) +{ + int n; + n = fread(wsr88d_ray, sizeof(Wsr88d_ray), 1, wf->fptr); +/* if (n > 0) print_packet_info(wsr88d_ray); */ + if (little_endian()) + wsr88d_swap_ray(wsr88d_ray); + + return n; +} + +/**********************************************************************/ +/* */ +/* not done N/A wsr88d_read_ray_header */ +/* */ +/**********************************************************************/ +int wsr88d_read_ray_header(Wsr88d_file *wf, + Wsr88d_ray_header *wsr88d_ray_header) +{ + fprintf(stderr,"Stub routine: wsr88d_read_ray_header.\n"); + return 0; +} + +/**********************************************************************/ +/* */ +/* done 3/3 wsr88d_ray_to_float */ +/* */ +/**********************************************************************/ +int wsr88d_ray_to_float(Wsr88d_ray *ray, + int THE_DATA_WANTED, float v[], int *n) +{ +/* + * Input: *ray - WSR-88D packet + * Output: THE_DATA_WANTED - Indicates which field to convert. Fields: + * WSR88D_DZ, WSR88D_VR, WSR88D_SW + * v[] - The output vector of float values. + * n - Length of the output vector. 0 = no data. + * + * Returns n. + * + * No allocation of space for the output vector performed here. + */ + +/* Code from Dan Austin (cvt_pckt_data.c) was the template for this. */ + + /* declarations */ + int num_ref_gates,num_vel_gates,num_spec_gates; + int refl_ptr, vel_ptr,spec_ptr,res_flag; + int ival; + int i; + + *n = 0; + num_ref_gates = ray->num_refl; + num_vel_gates = ray->num_dop; + num_spec_gates = ray->num_dop; /* 'num_dop', this is not a typo. */ + +/* The data pointers are specified from the begining of the + * 'Digital Radar Data (Message) Header'. Since we have a structure + * that defines all the header variables and a member called 'data'. + * we must subtract the length of the 'message header' from the data + * pointer. Hopefully, the reflecivity pointer will be 0 meaning the + * first element of the 'data' member; ray->data[0]; + */ +#define LENGTH_OF_MESSAGE 100 + if (num_ref_gates > 0) refl_ptr = ray->refl_ptr - LENGTH_OF_MESSAGE; + else refl_ptr = 0; + + vel_ptr = ray->vel_ptr - LENGTH_OF_MESSAGE; + spec_ptr = ray->spc_ptr - LENGTH_OF_MESSAGE; + + res_flag = ray->vel_res; + + +/* + fprintf(stderr,"refl_ptr = %d #g = %d, ", refl_ptr, num_ref_gates); + fprintf(stderr," vel_ptr = %d #g = %d, ", vel_ptr, num_vel_gates); + fprintf(stderr,"spec_ptr = %d #g = %d, ", spec_ptr, num_spec_gates); + fprintf(stderr,"res_flag = %d\n", res_flag); +*/ + + if (THE_DATA_WANTED == WSR88D_DZ) { + /* do the reflectivity data (dbZ)*/ + if (refl_ptr+num_ref_gates > 2300) + fprintf(stderr, "WARNING: # refl index (%d) exceeds maximum (2300)\n", + refl_ptr+num_ref_gates); + else { + for(i=0; idata[refl_ptr+i]; + if(ival > 1) + v[i] = (((ival-2.0)/2.0)-32.0); + else if (ival == 1) + v[i] = WSR88D_RFVAL; + else /* ival = 0 */ + v[i] = WSR88D_BADVAL; + } + *n = num_ref_gates; + } + + } else if (THE_DATA_WANTED == WSR88D_VR) { + /* do the velocity data (M/S) */ + if (vel_ptr+num_vel_gates > 2300) + fprintf(stderr, "WARNING: # vel index (%d) exceeds maximum (2300)\n", + vel_ptr+num_vel_gates); + else { + for(i=0; idata[vel_ptr+i]; + if(ival > 1) + if (res_flag == 2) /* High resolution: 0.5 m/s */ + v[i] = (((ival-2.0)/2.0)-63.5); + else + v[i] = ((ival-2.0)-127.0); + else if (ival == 1) + v[i] = WSR88D_RFVAL; + else /* ival = 0 */ + v[i] = WSR88D_BADVAL; + } + *n = num_vel_gates; + } + + } else if (THE_DATA_WANTED == WSR88D_SW) { + /* now do the spectrum width data (M/S)*/ + if (spec_ptr+num_spec_gates > 2300) + fprintf(stderr, "WARNING: # spec index (%d) exceeds maximum (2300)\n", + spec_ptr+num_spec_gates); + else { + for(i=0;idata[spec_ptr+i]; + if(ival > 1) + v[i] = (((ival-2)/2.0)-63.5); + else if (ival == 1) + v[i] = WSR88D_RFVAL; + else /* ival = 0 */ + v[i] = WSR88D_BADVAL; + } + *n = num_spec_gates; + } + } + + return *n; +} + + + +/**********************************************************************/ +/* Functions that convert some message header values. */ +/**********************************************************************/ +/**********************************************************************/ +/* */ +/* done 3/3 float wsr88d_get_nyquist */ +/* done 3/3 float wsr88d_get_atmos_atten_factor */ +/* done 3/3 float wsr88d_get_velocity_resolution */ +/* done 3/3 int wsr88d_get_volume_coverage */ +/* done 3/3 float wsr88d_get_elevation_angle */ +/* done 3/3 float wsr88d_get_azimuth */ +/* done 3/3 float wsr88d_get_range */ +/* done 3/3 void wsr88d_get_date */ +/* done 3/3 void wsr88d_get_time */ +/* done 5/20 int *wsr88d_get_vcp_info */ +/* done 5/20 float wsr88d_get_fix_angle */ +/* done 5/20 int wsr88d_get_pulse_count */ +/* done 5/20 float wsr88d_get_azimuth_rate */ +/* done 5/20 float wsr88d_get_pulse_width */ +/* done 5/20 float wsr88d_get_prf */ +/* done 5/20 float wsr88d_get_prt */ +/* done 5/20 float wsr88d_get_wavelength */ +/* done 5/20 float wsr88d_get_frequency */ +/* */ +/**********************************************************************/ +float wsr88d_get_nyquist(Wsr88d_ray *ray) +{ + return ray->nyq_vel/100.0; +} + +float wsr88d_get_atmos_atten_factor(Wsr88d_ray *ray) +{ + return ray->atm_att/1000.0; +} + +float wsr88d_get_velocity_resolution(Wsr88d_ray *ray) +{ + if (ray->vel_res == 2) return 0.5; + return 0.0; +} + +int wsr88d_get_volume_coverage(Wsr88d_ray *ray) +{ + if (ray->vol_cpat == 11) return 11; + if (ray->vol_cpat == 12) return 12; + if (ray->vol_cpat == 21) return 21; + if (ray->vol_cpat == 31) return 31; + if (ray->vol_cpat == 32) return 32; + if (ray->vol_cpat == 121) return 121; + return 0; +} + +float wsr88d_get_elevation_angle(Wsr88d_ray *ray) +{ + return ray->elev/8.0*(180.0/4096.0); +} + +float wsr88d_get_azimuth(Wsr88d_ray *ray) +{ + return ray->azm/8.0*(180.0/4096.0); +} + +float wsr88d_get_range(Wsr88d_ray *ray) +{ + return ray->unam_rng/10.0; +} + +#include +void wsr88d_get_date(Wsr88d_ray *ray, int *mm, int *dd, int *yy) +{ +/* + * mm (1-12) + * dd (1-31) + * yy (ex. 93) + */ + time_t itime; + struct tm *tm_time; + if (ray == NULL) { + *mm = *dd = *yy = 0; + return; + } + + itime = ray->ray_date - 1; + itime *= 24*60*60; /* Seconds/day * days. */ + + tm_time = gmtime(&itime); + *mm = tm_time->tm_mon+1; + *dd = tm_time->tm_mday; + *yy = tm_time->tm_year; +} + +void wsr88d_get_time(Wsr88d_ray *ray, int *hh, int *mm, int *ss, float *fsec) +{ + /* + * hh (0-23) + * mm (0-59) + * ss (0-59) + * fsec (fraction of second) + */ + double t; + + if (ray == NULL) { + *hh = *mm = *ss = *fsec = 0; + return; + } + t = ray->ray_time; + t /= 1000.0; + *hh = t/3600; + t -= *hh*3600; + *mm = t/60; + t -= *mm*60; + *ss = (int)t; + *fsec = t - *ss; +} + + + +/* + * Get_vcp_info - gets info about the volume coverage pattern for this scan + * parameters: + * int vcp_num - volume coverage pattern number + * int el_num - elevation number w/in vcp + * returns: int *vcp_info - ptr to array w/vcp info + * calls from: Nexrad2uf + * calls to: none + */ + +/* this database contains volume coverage patterns & associated info: */ +/* (0)= vcp # (1)=pulse width for vcp "Id$" */ +/* line[1-n]: (n,0)= elev. # for vcp (n,1)= (fixed angle)*8*(4096/180) */ +/* (n,2)= pulse count (n,3)= (azimuthal sweep rate)*8*(4096/45) */ + +static int vcp11[68] ={11,514,88,17,13600,88,0,14000,264,16,12664,264,0,14000,440,6,11736,608,6,24760,784,6,24760,952,10,12712,1128,10,12720,1368,0,18328,1584,0,18496,1824,0,18512,2184,0,18544,2552,0,18576,3040,0,18640,3552,0,18712}; + +static int vcp12[53]={12,514,91,15,15401,91,0,18204,164,15,15401,164,0,18204,237,15,15401,237,0,18204,328,3,19297,437,3,20393,564,3,20393,728,3,20393,928,3,20393,1165,0,20680,1456,0,20680,1820,0,21033,2276,0,20929,2840,0,20929,3550,0,20929}; + +static int vcp21[48]={21,514,88,28,8256,88,0,8272,264,28,8256,264,0,8272,440,8,7888,608,8,7888,784,8,8160,1096,12,8160,1800,0,10640,2656,0,10432,3552,0,10496}; + +static int vcp31[36]={31,516,88,63,3672,88,0,3688,272,63,3672,272,0,3688,456,63,3672,456,0,3688,640,0,3688,816,0,3688}; + +static int vcp32[32]={32,514,88,64,3616,88,0,3312,272,64,3616,272,0,3312,456,11,2960,640,11,2960,816,11,2960}; + +static int vcp121[62]={121,514,91,11,21336,91,0,21696,91,0,19952,91,0,15584,264,11,21336,264,0,21696,264,0,19952,264,0,15584,437,6,13985,437,0,19952,437,0,15584,610,6,15729,610,0,19952,610,0,15584,783,6,11872,783,0,21481,1092,6,14712,1802,0,21481,2658,0,21696,3550,0,21696}; + +static int vcp300[20]={300,514,88,28,8256,88,0,8272,440,8,8160,1800,0,10384}; + +int *wsr88d_get_vcp_info(int vcp_num,int el_num) +{ +/* + * This routine from Dan Austin. Program component of nex2uf. + */ + static int vcp_info[4]; + int fix_angle; + int pulse_cnt; + int az_rate; + int pulse_width; + + /* case statement to get vcp info */ + switch(vcp_num) { + case 11: + fix_angle = vcp11[(3*el_num)-1]; + pulse_cnt = vcp11[(3*el_num)]; + az_rate = vcp11[(3*el_num)+1]; + pulse_width = vcp11[1]; + break; + case 12: + fix_angle = vcp12[(3*el_num)-1]; + pulse_cnt = vcp12[(3*el_num)]; + az_rate = vcp12[(3*el_num)+1]; + pulse_width = vcp12[1]; + break; + case 21: + fix_angle = vcp21[(3*el_num)-1]; + pulse_cnt = vcp21[(3*el_num)]; + az_rate = vcp21[(3*el_num)+1]; + pulse_width = vcp21[1]; + break; + case 31: + fix_angle = vcp31[(3*el_num)-1]; + pulse_cnt = vcp31[(3*el_num)]; + az_rate = vcp31[(3*el_num)+1]; + pulse_width = vcp31[1]; + break; + case 32: + fix_angle = vcp32[(3*el_num)-1]; + pulse_cnt = vcp32[(3*el_num)]; + az_rate = vcp32[(3*el_num)+1]; + pulse_width = vcp32[1]; + break; + case 300: + fix_angle = vcp300[(3*el_num)-1]; + pulse_cnt = vcp300[(3*el_num)]; + az_rate = vcp300[(3*el_num)+1]; + pulse_width = vcp300[1]; + break; + case 121: + fix_angle = vcp121[(3*el_num)-1]; + pulse_cnt = vcp121[(3*el_num)]; + az_rate = vcp121[(3*el_num)+1]; + pulse_width = vcp121[1]; + break; + case 211: + fix_angle = vcp11[(3*el_num)-1]; + pulse_cnt = vcp11[(3*el_num)]; + az_rate = vcp11[(3*el_num)+1]; + pulse_width = vcp11[1]; + break; + case 212: + fix_angle = vcp12[(3*el_num)-1]; + pulse_cnt = vcp12[(3*el_num)]; + az_rate = vcp12[(3*el_num)+1]; + pulse_width = vcp12[1]; + break; + case 221: + fix_angle = vcp21[(3*el_num)-1]; + pulse_cnt = vcp21[(3*el_num)]; + az_rate = vcp21[(3*el_num)+1]; + pulse_width = vcp21[1]; + break; + default: + fix_angle = 0; + pulse_cnt = 0; + az_rate = 0; + pulse_width= 0; + break; + } + + /* get array for output */ + vcp_info[0]=fix_angle; + vcp_info[1]=pulse_cnt; + vcp_info[2]=az_rate; + vcp_info[3]=pulse_width; + + + /* return the value array */ + return(vcp_info); +} + + +float wsr88d_get_fix_angle(Wsr88d_ray *ray) +{ + int *vcp_info; + vcp_info = wsr88d_get_vcp_info(ray->vol_cpat, ray->elev_num); + return vcp_info[0]/8.0*180./4096.0; +} +int wsr88d_get_pulse_count(Wsr88d_ray *ray) +{ + int *vcp_info; + vcp_info = wsr88d_get_vcp_info(ray->vol_cpat, ray->elev_num); + return vcp_info[1]; +} +float wsr88d_get_azimuth_rate(Wsr88d_ray *ray) +{ + int *vcp_info; + vcp_info = wsr88d_get_vcp_info(ray->vol_cpat, ray->elev_num); + return vcp_info[2]/8.0*45./4096.0; +} +float wsr88d_get_pulse_width(Wsr88d_ray *ray) +{ + int *vcp_info; + vcp_info = wsr88d_get_vcp_info(ray->vol_cpat, ray->elev_num); + return vcp_info[3]/299.792458; +} + +float wsr88d_get_prf(Wsr88d_ray *ray) +{ + float prf; + float c = 299792458.0; + float range; + + range = wsr88d_get_range(ray)*1000.0; + if (range != 0) prf = c/(2*range); + else prf = 0.0; + + return prf; +} + +float wsr88d_get_prt(Wsr88d_ray *ray) +{ + float prf; + float prt; + + prf = wsr88d_get_prf(ray); + if (prf != 0) prt = 1.0/prf; + else prt = 0; + return prt; +} + +/* Note: wsr88d_get_wavelength() below is no longer used because of differences + * in wavelength for velocity and reflectivity. The function computes + * wavelength when Nyquist is present, but returns a constant wavelength + * otherwise. Nyquist is present for velocity, but not for reflectivity. The + * fact is that WSR-88D radars use a constant wavelength, 10.7 cm., which is + * the value now used where this function was formerly called in + * wsr88d_load_sweep_into_volume(). + */ + +float wsr88d_get_wavelength(Wsr88d_ray *ray) +{ + float wavelength; + float prf; + float nyquist; + + prf = wsr88d_get_prf(ray); + nyquist = wsr88d_get_nyquist(ray); + /* If required info to determine wavelength does not exist, + just use 10 cm. All wsr88d radars are 10cm. MJK */ + if ((prf == 0) || (nyquist == 0.0)) wavelength = 0.10; + else wavelength = 4*nyquist/prf; + return wavelength; +} + +float wsr88d_get_frequency(Wsr88d_ray *ray) +{ + float freq; + float c = 299792458.0; + + /* Carrier freq (GHz). Revised 12 Jun 97. MJK */ + freq = (c / wsr88d_get_wavelength(ray)) * 1.0e-9; + return freq; +} + diff --git a/wsr88d.h b/wsr88d.h new file mode 100644 index 0000000..cc607c7 --- /dev/null +++ b/wsr88d.h @@ -0,0 +1,219 @@ +#ifndef _wsr88d +#define _wsr88d +#include + +/* Modify the following to point to the file that contains the + * nexrad (wsr88d) location information for each radar site. + * The directory should be the same as the LIBDIR in the makefile. + */ +#ifndef WSR88D_SITE_INFO_FILE +#define WSR88D_SITE_INFO_FILE "/usr/local/trmm/GVBOX/lib/wsr88d_locations.dat" +#endif +/*===============================================================*/ +typedef struct { + char archive2[8]; /* Always ARCHIVE2 */ + char site_id[4]; /* 4-leter site ID. e.g. KLMB */ + char tape_num[6]; /* NCDC tape number. e.g. N00001 */ + char b1; /* Blank. */ + char date[9]; /* Date tape written. dd-MMM-yy e.g. 19-FEB-93 */ + char b2; /* Blank. */ + char time[8]; /* Time tape written. hh:mm:ss. e.g. 10:22:59 */ + char b3; /* Blank. */ + char data_center[5]; /* Data Center writing tape: RDASC or NCDC. */ + char wban_num[5]; /* WBAN number of this NEXRAD site. This is a + unique 5-digit number assigned at + NCDC. Numbers are contained in the NCDC + NEXRAD Station History file. The file + also contains the four letter site ID, + Latitude, Longitude, Elevation, and + common location name. */ + char tape_mode[5]; /* Tape output mode. Current values are 8200, 8500, + 8500c. */ + char volume_num[5]; /* A volume number to be used for copies and + extractions of data from tapes. The form + would be VOL01, VOL02, VOL03 ... VOLnn. */ + char b4[6]; /* Blank. Available for future use. */ + char b5[31552]; /* May be used for internal controls or + other information at each archive center. + Information of value to users will be + documented at the time of tape shipment. */ +} Wsr88d_tape_header; + + +/* Title record structure for nexrad archive2 data file. + The first record of each nexrad data file is a title record */ +typedef struct + { + char filename[9]; + char ext[3]; + int file_date; /* modified Julian date */ + int file_time; /* milliseconds of day since midnight */ + char unused1[4]; + } +nr_archive2_title; + +/* message packet structure for nexrad radar data */ +typedef struct + { + short ctm[6]; /* not used */ + + /* halfword 7 : message header information */ + short msg_size; /* # halfwords from here to end of record? */ + short msg_type; /* Digital Radar Data. This message may contain + * a combination of either reflectivity, + * aliased velocity, or spectrum width. + */ + short id_seq; /* I.d. Seq = 0 to 7FFF, then roll over to 0 */ + short msg_date; /* modified Julian date from 1/1/70 */ + int msg_time; /* packet generation time in ms past midnite */ + short num_seg; + short seg_num; + + /* halfword 15 : data header information */ + int ray_time; /* collection time for this ray in ms */ + short ray_date; /* modified Julian date for this ray */ + short unam_rng; /* unambiguous range */ + short azm; /* coded azimuth angle */ + short ray_num; /* ray no. within elevation scan */ + short ray_status;/* ray status flag */ + short elev; /* coded elevation angle */ + short elev_num; /* elevation no. within volume scan */ + + /* halfword 24 : gate/bin information*/ + short refl_rng; /* range to first gate of refl data */ + short dop_rng; /* range to first gate of doppler data */ + short refl_size; /* refl data gate size */ + short dop_size; /* doppler data gate size */ + short num_refl; /* no. of reflectivity gates */ + short num_dop; /* no. of doppler gates */ + + /* halfword 30 */ + short sec_num; /* sector no. within cut */ + float sys_cal; /* gain calibration constant */ + + /* halfword 33 : data parameters */ + short refl_ptr; /* reflectivity data ptr */ + short vel_ptr; /* velocity data ptr */ + short spc_ptr; /* spectrum width ptr */ + short vel_res; /* Doppler velocity resolution */ + short vol_cpat; /* volume coverage pattern */ + short unused1[4]; + + /* halfword 42 : data pointers for Archive II playback */ + short ref_ptrp; + short vel_ptrp; + short spc_ptrp; + + /* halfword 45 */ + short nyq_vel; /* Nyquist velocity */ + short atm_att; /* atmospheric attenuation factor */ + short min_dif; + + /* halfwords 48 to 64 */ + short unused2[17]; + + /* halfwords 65 to 1214 */ + unsigned char data[2300]; + + /* last 4 bytes : frame check sequence */ + unsigned char fts[4]; + } +Wsr88d_packet; + +/* structure for the radar site parameters */ +typedef struct radar_site { + int number; /* arbitrary number of this radar site */ + char name[4]; /* Nexrad site name */ + char city[15]; /* nearest city to radaar site */ + char state[2]; /* state of radar site */ + int latd; /* degrees of latitude of site */ + int latm; /* minutes of latitude of site */ + int lats; /* seconds of latitude of site */ + int lond; /* degrees of longitude of site */ + int lonm; /* minutes of longitude of site */ + int lons; /* seconds of longitude of site */ + int height; /* height of site in meters above sea level*/ + int bwidth; /* bandwidth of site (mhz) */ + int spulse; /* length of short pulse (ns)*/ + int lpulse; /* length of long pulse (ns) */ +} Wsr88d_site_info; + +typedef struct { + FILE *fptr; +} Wsr88d_file; + +#define PACKET_SIZE 2432 +typedef Wsr88d_packet Wsr88d_ray; /* Same thing, different name. */ + + +#define MAX_RAYS_IN_SWEEP 400 +typedef struct { + Wsr88d_ray *ray[MAX_RAYS_IN_SWEEP]; /* Expected maximum is around 366. */ +} Wsr88d_sweep; + +typedef union { + nr_archive2_title title; + Wsr88d_packet p; +} Wsr88d_file_header; + +typedef struct { + int dummy; /* Structure not used yet. */ +} Wsr88d_header; + +typedef struct { + int dummy; /* Structure not used yet. */ +} Wsr88d_ray_header; + +/* Selected so we can boolean or use them for a data mask. */ +#define WSR88D_DZ 0x1 +#define WSR88D_VR 0x2 +#define WSR88D_SW 0x4 +#define WSR88D_BADVAL 0500 /* non-meaningful value (500 octal) */ +#define WSR88D_RFVAL (WSR88D_BADVAL-1) /* ival = 0 means below SNR, + = 1 means range folded. */ + + +/***********************************************************************/ +/* */ +/* Function specification. */ +/* */ +/***********************************************************************/ +Wsr88d_file *wsr88d_open(char *filename); +int wsr88d_perror(char *message); +int wsr88d_close(Wsr88d_file *wf); +int wsr88d_read_file_header(Wsr88d_file *wf, + Wsr88d_file_header *wsr88d_file_header); +int wsr88d_read_tape_header(char *first_file, + Wsr88d_tape_header *wsr88d_tape_header); +int wsr88d_read_sweep(Wsr88d_file *wf, Wsr88d_sweep *wsr88d_sweep); +int wsr88d_read_ray(Wsr88d_file *wf, Wsr88d_ray *wsr88d_ray); +int wsr88d_read_ray_header(Wsr88d_file *wf, + Wsr88d_ray_header *wsr88d_ray_header); +int wsr88d_ray_to_float(Wsr88d_ray *ray, + int THE_DATA_WANTED, float v[], int *n); +float wsr88d_get_nyquist(Wsr88d_ray *ray); +float wsr88d_get_atmos_atten_factor(Wsr88d_ray *ray); +float wsr88d_get_velocity_resolution(Wsr88d_ray *ray); +int wsr88d_get_volume_coverage(Wsr88d_ray *ray); +float wsr88d_get_elevation_angle(Wsr88d_ray *ray); +float wsr88d_get_azimuth(Wsr88d_ray *ray); +float wsr88d_get_range(Wsr88d_ray *ray); +void wsr88d_get_date(Wsr88d_ray *ray, int *mm, int *dd, int *yy); +void wsr88d_get_time(Wsr88d_ray *ray, int *hh, int *mm, int *ss, float *fsec); +Wsr88d_site_info *wsr88d_get_site(char *in_sitenm); /* Courtesy of Dan Austin. */ +int *wsr88d_get_vcp_info(int vcp_num,int el_num); /* Courtesy of Dan Austin. */ +float wsr88d_get_fix_angle(Wsr88d_ray *ray); +int wsr88d_get_pulse_count(Wsr88d_ray *ray); +float wsr88d_get_azimuth_rate(Wsr88d_ray *ray); +float wsr88d_get_pulse_width(Wsr88d_ray *ray); +float wsr88d_get_prf(Wsr88d_ray *ray); +float wsr88d_get_prt(Wsr88d_ray *ray); +float wsr88d_get_wavelength(Wsr88d_ray *ray); +float wsr88d_get_frequency(Wsr88d_ray *ray); + +int no_command (char *cmd); +FILE *uncompress_pipe (FILE *fp); +FILE *compress_pipe (FILE *fp); +int rsl_pclose(FILE *fp); + +#endif diff --git a/wsr88d_get_site.c b/wsr88d_get_site.c new file mode 100644 index 0000000..6b5f661 --- /dev/null +++ b/wsr88d_get_site.c @@ -0,0 +1,98 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + * get_site - fills structure containing radar site info + * parameters: + * char *in_sitenm - ptr to radar site name + * returns: struct radar_site *currsite->- ptr to current site structure + * Returns NULL on failure of 'in_sitenm' lookup. + * calls from: Proc_file +*/ + +#include +#include +int strcasecmp(const char *s1, const char *s2); +#include +#include "wsr88d.h" + +Wsr88d_site_info *wsr88d_get_site(char *in_sitenm) +{ + /* variable declarations */ + char line[100]; + int scan_count,i; + int in_number,in_latd,in_latm,in_lats,in_lond,in_lonm,in_lons; + int in_height; + char in_site[5],in_city[16],in_state[4]; /* One extra for \0 */ + struct radar_site *currsite=NULL; + FILE *in_file; + + if((in_file=fopen(WSR88D_SITE_INFO_FILE, "r")) !=NULL) + { + /* read each line */ + while (fgets(line,sizeof(line),in_file) != NULL) + { + scan_count=sscanf(line,"%d %s %s %s %d %d %d %d %d %d %d",&in_number,in_site,in_city,in_state,&in_latd,&in_latm,&in_lats,&in_lond,&in_lonm,&in_lons,&in_height); + if(scan_count != 11 && scan_count != 0) + fprintf(stderr,"get_site: sitedb read"); + else + { + /* get the radar site info */ + + /* check for the matching site name*/ + if(strcasecmp(in_sitenm,in_site)== 0) + { + if((currsite=(struct radar_site *)malloc(sizeof(struct radar_site)))==NULL) { + perror("wsr88d_get_site"); + return NULL; + } + currsite->number = in_number; + for(i=0;i<4;i++) + currsite->name[i] = in_site[i]; + for(i=0;i<15;i++) + currsite->city[i] = in_city[i]; + for(i=0;i<2;i++) + currsite->state[i] = in_state[i]; + currsite->latd = in_latd; + currsite->latm = in_latm; + currsite->lats = in_lats; + currsite->lond = in_lond; + currsite->lonm = in_lonm; + currsite->lons = in_lons; + currsite->height = in_height; + currsite->bwidth = -999; + currsite->spulse = 1530; + currsite->lpulse = 4630; + break; + } + } + } + /* close the file */ + (void)fclose(in_file); + } + else + perror(WSR88D_SITE_INFO_FILE); + + + return(currsite); +} + diff --git a/wsr88d_locations.dat b/wsr88d_locations.dat new file mode 100644 index 0000000..d044206 --- /dev/null +++ b/wsr88d_locations.dat @@ -0,0 +1,146 @@ +14929 KABR ABERDEEN SD 45 27 21 -98 24 47 397 +3019 KABX ALBUQUERQUE NM 35 8 59 -106 49 26 1789 +93773 KAKQ NORFOLK/RICH VA 36 59 2 -77 0 26 34 +23047 KAMA AMARILLO TX 35 14 0 -101 42 33 1093 +12899 KAMX MIAMI FL 25 36 40 -80 24 46 4 +4837 KAPX GAYLORD MI 44 54 26 -84 43 11 446 +94987 KARX LA_CROSSE WI 43 49 22 -91 11 28 389 +94287 KATX SEATTLE WA 48 11 40 -122 29 45 151 +93240 KBBX BEALE_AFB CA 39 29 46 -121 37 54 53 +4725 KBGM BINGHAMTON NY 42 11 59 -75 59 5 490 +94289 KBHX EUREKA CA 40 29 54 -124 17 31 732 +24011 KBIS BISMARCK ND 46 46 15 -100 45 38 505 +94046 KBLX BILLINGS MT 45 51 14 -108 36 24 1097 +53823 KBMX BIRMINGHAM AL 33 10 20 -86 46 12 197 +54765 KBOX BOSTON MA 41 57 21 -71 8 13 36 +12919 KBRO BROWNSVILLE TX 25 54 58 -97 25 8 7 +14733 KBUF BUFFALO NY 42 56 56 -78 44 12 211 +92804 KBYX KEY_WEST FL 24 35 51 -81 42 11 3 +13883 KCAE COLUMBIA SC 33 56 55 -81 7 6 70 +94625 KCBW HOULTON ME 46 2 22 -67 48 24 227 +4101 KCBX BOISE ID 43 29 27 -116 14 8 933 +54764 KCCX STATE_COLLEGE PA 40 55 23 -78 0 13 733 +14820 KCLE CLEVELAND OH 41 24 47 -81 51 35 233 +53845 KCLX CHARLESTON SC 32 39 20 -81 2 31 30 +12924 KCRP CORP_CHRISTI TX 27 47 3 -97 30 40 13 +54774 KCXX BURLINGTON VT 44 30 40 -73 10 1 97 +24018 KCYS CHEYENNE WY 41 9 7 -104 48 22 1868 +93235 KDAX SACRAMENTO CA 38 30 4 -121 40 40 9 +13985 KDDC DODGE_CITY KS 37 45 39 -99 58 7 789 +22015 KDFX LAUGHLIN_AFB TX 29 16 22 -100 16 50 345 +93771 KDIX PHILADELPHIA PA 39 56 49 -74 24 39 45 +14913 KDLH DULUTH MN 46 50 13 -92 12 35 435 +94984 KDMX DES_MOINES IA 41 43 53 -93 43 22 299 +93770 KDOX DOVER_AFB DE 38 49 32 -75 26 24 15 +4830 KDTX DETROIT MI 42 41 59 -83 28 18 327 +94982 KDVN DAVENPORT IA 41 36 42 -90 34 51 230 +3987 KDYX DYESS_AFB TX 32 32 18 -99 15 15 462 +3983 KEAX KANSAS_CITY MO 38 48 37 -94 15 52 303 +53112 KEMX TUCSON AZ 31 53 37 -110 37 49 1586 +54766 KENX ALBANY NY 42 35 11 -74 3 50 557 +53851 KEOX FORT_RUCKER AL 31 27 38 -85 27 34 132 +3020 KEPZ EL_PASO TX 31 52 23 -106 41 53 1251 +53110 KESX LAS_VEGAS NV 35 42 4 -114 53 29 1483 +53825 KEVX EGLIN_AFB FL 30 33 52 -85 55 17 43 +12971 KEWX AUSTIN/S_ANT TX 29 42 14 -98 1 42 193 +53114 KEYX EDWARDS_AFB CA 35 5 52 -117 33 39 840 +53831 KFCX ROANOKE VA 37 1 28 -80 16 26 874 +3981 KFDR ALTUS_AFB OK 34 21 44 -98 58 35 386 +3022 KFDX CANNON_AFB NM 34 38 7 -103 37 48 1417 +53819 KFFC ATLANTA GA 33 21 49 -84 33 57 262 +14944 KFSD SIOUX_FALLS SD 43 35 16 -96 43 46 436 +53113 KFSX FLAGSTAFF AZ 34 34 28 -111 11 52 2261 +3018 KFTG DENVER CO 39 47 12 -104 32 45 1675 +3985 KFWS DALLAS/FTW TX 32 34 23 -97 18 11 208 +94008 KGGW GLASGOW MT 48 12 23 -106 37 30 694 +3025 KGJX GRAND_JUNCT CO 39 3 44 -108 12 50 3046 +23065 KGLD GOODLAND KS 39 21 59 -101 42 2 1113 +14898 KGRB GREEN_BAY WI 44 29 54 -88 6 41 208 +3992 KGRK FORT_HOOD TX 30 43 19 -97 22 59 164 +94860 KGRR GRAND_RAPIDS MI 42 53 38 -85 32 41 237 +3870 KGSP GREER SC 34 52 0 -82 13 12 287 +53837 KGWX COLUMBUS_AFB MS 33 53 48 -88 19 44 145 +54762 KGYX PORTLAND ME 43 53 29 -70 15 24 125 +3023 KHDX HOLLOMAN_AFB NM 33 4 35 -106 7 22 1287 +3980 KHGX HOUSTON TX 29 28 19 -95 4 45 5 +53111 KHNX SAN_JOAQUIN_V CA 36 18 51 -119 37 56 75 +53839 KHPX FORT_CAMPBELL KY 36 44 12 -87 17 6 176 +53857 KHTX HUNTSVILLE AL 34 55 50 -86 05 00 537 +3928 KICT WICHITA KS 37 39 17 -97 26 34 407 +13841 KILN CINCINNATI OH 39 25 13 -83 49 18 322 +4833 KILX LINCOLN IL 40 9 2 -89 20 13 177 +93819 KIND INDIANAPOLIS IN 39 42 27 -86 16 49 241 +3984 KINX TULSA OK 36 10 30 -95 33 53 204 +23104 KIWA PHOENIX AZ 33 17 21 -111 40 12 412 +3940 KJAN JACKSON MS 32 19 4 -90 4 48 91 +13889 KJAX JACKSONVILLE FL 30 29 5 -81 42 7 10 +53824 KJGX ROBINS_AFB GA 32 40 30 -83 21 4 159 +3889 KJKL JACKSON KY 37 35 27 -83 18 47 415 +23042 KLBB LUBBOCK TX 33 39 14 -101 48 51 993 +3937 KLCH LAKE_CHARLES LA 30 7 31 -93 12 57 4 +53813 KLIX NEW_ORLEANS LA 30 20 12 -89 49 32 7 +94049 KLNX NORTH_PLATTE NE 41 57 28 -100 34 35 905 +4831 KLOT CHICAGO IL 41 36 17 -88 5 5 202 +4108 KLRX ELKO NV 40 44 23 -116 48 10 2056 +3982 KLSX ST_LOUIS MO 38 41 56 -90 40 58 185 +93774 KLTX WILMINGTON NC 33 59 22 -78 25 44 20 +53827 KLVX LOUISVILLE KY 37 58 31 -85 56 38 219 +93767 KLWX STERLING VA 38 58 31 -77 28 40 83 +3952 KLZK LITTLE_ROCK AR 34 50 12 -92 15 44 173 +23023 KMAF MIDLAND/ODSSA TX 31 56 36 -102 11 21 874 +94296 KMAX MEDFORD OR 42 4 52 -122 43 2 2290 +94048 KMBX MINOT_AFB ND 48 23 33 -100 51 54 455 +93768 KMHX MOREHEAD_CITY NC 34 46 34 -76 52 34 9 +4834 KMKX MILWAUKEE WI 42 58 4 -88 33 2 292 +12838 KMLB MELBOURNE FL 28 6 48 -80 39 15 11 +13894 KMOB MOBILE AL 30 40 46 -88 14 23 63 +94983 KMPX MINNEAPOLIS MN 44 50 56 -93 33 56 288 +94850 KMQT MARQUETTE MI 46 31 52 -87 32 54 430 +53832 KMRX KNOXVILLE TN 36 10 7 -83 24 6 408 +4103 KMSX MISSOULA MT 47 2 28 -113 59 10 2394 +4104 KMTX SALT_LAKE_CTY UT 41 15 46 -112 26 52 1969 +93236 KMUX SAN_FRANCISCO CA 37 9 18 -121 53 54 1057 +94986 KMVX GRAND_FORKS ND 47 31 40 -97 19 32 300 +53826 KMXX MAXWELL_AFB AL 32 32 12 -85 47 23 122 +53115 KNKX SAN_DIEGO CA 32 55 8 -117 2 31 291 +93839 KNQA MEMPHIS TN 35 20 41 -89 52 24 86 +94980 KOAX OMAHA NE 41 19 13 -96 22 0 350 +53833 KOHX NASHVILLE TN 36 14 50 -86 33 45 176 +94703 KOKX NEW_YORK_CITY NY 40 51 56 -72 51 50 26 +4106 KOTX SPOKANE WA 47 40 49 -117 37 36 727 +3816 KPAH PADUCAH KY 37 4 6 -88 46 19 119 +4832 KPBZ PITTSBURGH PA 40 31 54 -80 13 6 361 +24155 KPDT PENDLETON OR 45 41 26 -118 51 10 462 +3993 KPOE FORT_POLK LA 31 9 20 -92 58 33 124 +3021 KPUX PUEBLO CO 38 27 34 -104 10 53 1600 +93772 KRAX RALEIGH/DUR NC 35 39 56 -78 29 23 106 +53104 KRGX RENO NV 39 45 19 -119 27 44 2530 +24061 KRIW RIVERTON WY 43 3 58 -108 28 38 1697 +53834 KRLX CHARLESTON WV 38 18 40 -81 43 23 329 +54763 KRMX GRIFFISS_AFB NY 43 28 4 -75 27 29 462 +94288 KRTX PORTLAND OR 45 42 53 -122 57 56 479 +4107 KSFX POCATELLO ID 43 6 21 -112 41 10 1364 +13995 KSGF SPRINGFIELD MO 37 14 7 -93 24 2 390 +13957 KSHV SHREVEPORT LA 32 27 3 -93 50 29 83 +23034 KSJT SAN_ANGELO TX 31 22 17 -100 29 33 576 +53117 KSOX SANTA_ANA_MT CA 33 49 4 -117 38 9 923 +92801 KTBW TAMPA FL 27 42 20 -82 24 6 12 +4102 KTFX GREAT_FALLS MT 47 27 35 -111 23 7 1132 +93805 KTLH TALLAHASSEE FL 30 23 51 -84 19 44 19 +3979 KTLX OKLAHOMA_CITY OK 35 19 59 -97 16 40 370 +3986 KTWX TOPEKA KS 38 59 49 -96 13 57 417 +94047 KUDX RAPID_CITY SD 44 7 30 -102 49 47 919 +94981 KUEX HASTINGS NE 40 19 15 -98 26 31 602 +53856 KVAX MOODY_AFB GA 30 53 25 -83 0 6 54 +94234 KVBX VANDENBRG_AFB CA 34 50 17 -120 23 45 376 +3995 KVNX VANCE_AFB OK 36 44 27 -98 7 40 369 +53101 KVTX LOS_ANGELES CA 34 24 42 -119 10 47 831 +53116 KYUX YUMA AZ 32 29 43 -114 39 24 53 +26548 PAHG ANCHORAGE AK 60 43 33 -151 21 5 74 +25404 PAIH MIDDLETON_IS AK 59 27 41 -146 18 11 20 +24690 PAPD FAIRBANKS AK 65 2 6 -147 30 6 790 +41417 PGUA ANDERSEN_AFB GU 13 27 16 144 48 30 80 +22548 PHKI SOUTH_KAUAI HI 21 53 39 -159 33 8 55 +43216 RKSG CMP_HUMPHRYS KOR 36 57 21 127 1 16 16 +42219 RODN KADENA OKI 26 18 7 127 54 35 66 +33771 KDGX JACKSON MS 32 16 33 -89 58 48 151 diff --git a/wsr88d_m31.c b/wsr88d_m31.c new file mode 100644 index 0000000..3c260a7 --- /dev/null +++ b/wsr88d_m31.c @@ -0,0 +1,781 @@ +/* + NASA/TRMM, Code 613 + This is the TRMM Office Radar Software Library. + Copyright (C) 2008 + Bart Kelley + SSAI + Lanham, Maryland + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +/* + * This file contains routines for processing Message Type 31, the digital + * radar message type introduced in WSR-88D Level II Build 10. + */ + +#include "rsl.h" +#include "wsr88d.h" + +/* Data descriptions in the following data structures are from the "Interface + * Control Document for the RDA/RPG", Build 10.0 Draft, WSR-88D Radar + * Operations Center. + */ + +typedef struct { + short rpg[6]; /* Unused. Not really part of message header, but is + * inserted by RPG Communications Manager for each message. + */ + unsigned short msg_size; /* for this segment, in halfwords */ + unsigned char channel; /* RDA Redundant Channel */ + unsigned char msg_type; /* Message Type */ + unsigned short id_seq; /* I.d. Seq = 0 to 7FFF, then roll over to 0 */ + unsigned short msg_date; /* modified Julian date from 1/1/70 */ + unsigned int msg_time; /* packet generation time in ms past midnite */ + unsigned short num_segs; + unsigned short seg_num; +} Wsr88d_msg_hdr; + +typedef struct { + char radar_id[4]; + unsigned int ray_time; /* Data collection time in milliseconds past midnight GMT */ + unsigned short ray_date; /* Julian date - 2440586.5 (1/01/1970) */ + unsigned short azm_num ; /* Radial number within elevation scan */ + float azm; /* Azimuth angle in degrees (0 to 359.956055) */ + unsigned char compression_code; /* 0 = uncompressed, 1 = BZIP2, 2 = zlib */ + unsigned char spare; /* for word alignment */ + unsigned short radial_len; /* radial length in bytes, including data header block */ + unsigned char azm_res; + unsigned char radial_status; + unsigned char elev_num; + unsigned char sector_cut_num; + float elev; /* Elevation angle in degrees (-7.0 to 70.0) */ + unsigned char radial_spot_blanking; + unsigned char azm_indexing_mode; + unsigned short data_block_count; + /* Data Block Pointers */ + unsigned int dbptr_vol_const; + unsigned int dbptr_elev_const; + unsigned int dbptr_radial_const; + unsigned int dbptr_ref; + unsigned int dbptr_vel; + unsigned int dbptr_sw; + unsigned int dbptr_zdr; + unsigned int dbptr_phi; + unsigned int dbptr_rho; +} Ray_header_m31; /* Called Data Header Block in RDA/RPG document. */ + +typedef struct { + char dataname[4]; + unsigned int reserved; + unsigned short ngates; + short range_first_gate; + short range_samp_interval; + short thresh_not_overlayed; + short snr_thresh; + unsigned char controlflag; + unsigned char datasize_bits; + float scale; + float offset; +} Data_moment_hdr; + +typedef struct { + Data_moment_hdr data_hdr; + /* TODO: data type will need to be changed to "void" to handle Dual Pole: + * some data are in 2-byte words. + */ + unsigned char *data; +} Data_moment; + +typedef struct { + Ray_header_m31 ray_hdr; + short unamb_rng; + short nyq_vel; + /* Pointers to data */ + /* TODO: Replace data moment pointers with single pointer to radial. + * Can simply make unsigned char array as in MSG1 version. + * Maximum radial length is 14288 bytes. + */ + Data_moment *ref; + Data_moment *vel; + Data_moment *sw; +} Wsr88d_ray_m31; + +#define MAXRAYS_M31 800 +#define MAXSWEEPS 20 + +enum {START_OF_ELEV, INTERMED_RADIAL, END_OF_ELEV, BEGIN_VOS, END_VOS}; + + +void wsr88d_swap_m31_hdr(Wsr88d_msg_hdr *msghdr) +{ + swap_2_bytes(&msghdr->msg_size); + swap_2_bytes(&msghdr->id_seq); + swap_2_bytes(&msghdr->msg_date); + swap_4_bytes(&msghdr->msg_time); + swap_2_bytes(&msghdr->num_segs); + swap_2_bytes(&msghdr->seg_num); +} + + +void wsr88d_swap_m31_ray(Ray_header_m31 *wsr88d_ray) +{ + int *fullword; + + swap_4_bytes(&wsr88d_ray->ray_time); + swap_2_bytes(&wsr88d_ray->ray_date); + swap_2_bytes(&wsr88d_ray->azm_num); + swap_4_bytes(&wsr88d_ray->azm); + swap_2_bytes(&wsr88d_ray->radial_len); + swap_4_bytes(&wsr88d_ray->elev); + swap_2_bytes(&wsr88d_ray->data_block_count); + fullword = (int *) &wsr88d_ray->dbptr_vol_const; + for (; fullword <= (int *) &wsr88d_ray->dbptr_rho; fullword++) + swap_4_bytes(fullword); +} + + +void wsr88d_swap_data_moment(Data_moment_hdr *this_field) +{ + short *halfword; + halfword = (short *) &this_field->ngates; + for (; halfword < (short *) &this_field->controlflag; halfword++) + swap_2_bytes(halfword); + swap_4_bytes(&this_field->scale); + swap_4_bytes(&this_field->offset); +} + + +void testprt(Ray_header_m31 ray_hdr) +{ + /* For testing: Print some values from data block header. */ + printf("\nray_time: %d\n",ray_hdr.ray_time); + printf("ray_date: %d\n",ray_hdr.ray_date); + printf("azm_num: %d\n",ray_hdr.azm_num); + printf("azm: %f\n",ray_hdr.azm); + printf("radial_len: %d\n",ray_hdr.radial_len); + printf("elev: %f\n",ray_hdr.elev); + printf("data block count: %d\n",ray_hdr.data_block_count); + printf("dbptr_vol_const: %d\n",ray_hdr.dbptr_vol_const); + printf("dbptr_elev_const: %d\n",ray_hdr.dbptr_elev_const); + printf("dbptr_radial_const: %d\n",ray_hdr.dbptr_radial_const); + printf("dbptr_ref: %d\n",ray_hdr.dbptr_ref); + printf("dbptr_vel: %d\n",ray_hdr.dbptr_vel); + printf("dbptr_sw: %d\n",ray_hdr.dbptr_sw); +} + + +float wsr88d_get_angle(short bitfield) +{ + short mask = 1; + int i; + float angle = 0.; + float value[13] = {0.043945, 0.08789, 0.17578, 0.35156, .70313, 1.40625, + 2.8125, 5.625, 11.25, 22.5, 45., 90., 180.}; + + /* find which bits are set and sum corresponding values to get angle. */ + + bitfield = bitfield >> 3; /* 3 least significant bits aren't used. */ + for (i = 0; i < 13; i++) { + if (bitfield & mask) angle += value[i]; + bitfield = bitfield >> 1; + } + return angle; +} + + +float wsr88d_get_azim_rate(short bitfield) +{ + short mask = 1; + int i; + float rate = 0.; + float value[12] = {0.0109863, 0.021972656, 0.043945, 0.08789, 0.17578, + 0.35156, .70313, 1.40625, 2.8125, 5.625, 11.25, 22.5}; + + /* Find which bits are set and sum corresponding values to get rate. */ + + bitfield = bitfield >> 3; /* 3 least significant bits aren't used. */ + for (i = 0; i < 12; i++) { + if (bitfield & mask) rate += value[i]; + bitfield = bitfield >> 1; + } + if (bitfield >> 15) rate = -rate; + return rate; +} + +#define WSR88D_MAX_SWEEPS 20 + +typedef struct { + int vcp; + int num_cuts; + float vel_res; + float fixed_angle[WSR88D_MAX_SWEEPS]; + float azim_rate[WSR88D_MAX_SWEEPS]; + int waveform[WSR88D_MAX_SWEEPS]; + int super_res_ctrl[WSR88D_MAX_SWEEPS]; + int surveil_prf_num[WSR88D_MAX_SWEEPS]; + int doppler_prf_num[WSR88D_MAX_SWEEPS]; +} VCP_data; + +static VCP_data vcp_data; + +void wsr88d_get_vcp_data(short *msgtype5) +{ + short azim_rate, fixed_angle, vel_res; + short sres_and_survprf; /* super res ctrl and surveil prf, one byte each */ + short chconf_and_waveform; + int i; + + vcp_data.vcp = (unsigned short) msgtype5[2]; + vcp_data.num_cuts = msgtype5[3]; + if (little_endian()) { + swap_2_bytes(&vcp_data.vcp); + swap_2_bytes(&vcp_data.num_cuts); + } + vel_res = msgtype5[5]; + if (little_endian()) swap_2_bytes(&vel_res); + vel_res = vel_res >> 8; + if (vel_res == 2) vcp_data.vel_res = 0.5; + else if (vel_res == 4) vcp_data.vel_res = 1.0; + else vcp_data.vel_res = 0.0; + /* Get elevation related information for each sweep. */ + for (i=0; i < vcp_data.num_cuts; i++) { + fixed_angle = msgtype5[11 + i*23]; + azim_rate = msgtype5[15 + i*23]; + chconf_and_waveform = msgtype5[12 + i*23]; + sres_and_survprf = msgtype5[13 + i*23]; + vcp_data.doppler_prf_num[i] = msgtype5[23 + i*23]; + if (little_endian()) { + swap_2_bytes(&fixed_angle); + swap_2_bytes(&azim_rate); + swap_2_bytes(&chconf_and_waveform); + swap_2_bytes(&sres_and_survprf); + swap_2_bytes(&vcp_data.doppler_prf_num[i]); + } + vcp_data.fixed_angle[i] = wsr88d_get_angle(fixed_angle); + vcp_data.azim_rate[i] = wsr88d_get_azim_rate(azim_rate); + vcp_data.waveform[i] = chconf_and_waveform & 0xff; + vcp_data.super_res_ctrl[i] = sres_and_survprf >> 8; + vcp_data.surveil_prf_num[i] = sres_and_survprf & 0xff; + } +} + + +Data_moment *read_data_moment(unsigned char *radial, int begin_data_block) +{ + Data_moment *this_field; + unsigned char* data; + unsigned char* dptr; + int hdr_size, n; + + /* + printf("read_data_moment: "); + printf("sizeof(Data_moment) = %d\n", sizeof(Data_moment)); + printf("sizeof(Data_moment_hdr) = %d\n", sizeof(Data_moment_hdr)); + */ + this_field = malloc(sizeof(Data_moment)); + hdr_size = sizeof(Data_moment_hdr); + /* printf("hdr_size = %d\n", hdr_size); */ + + dptr = radial + begin_data_block; + memcpy(&this_field->data_hdr, dptr, hdr_size); + dptr += hdr_size; + + if (little_endian()) wsr88d_swap_data_moment(&this_field->data_hdr); + data = (unsigned char *) malloc(this_field->data_hdr.ngates); + memcpy(data, dptr, this_field->data_hdr.ngates); + this_field->data = data; + return this_field; +} + + +int read_wsr88d_ray_m31(Wsr88d_file *wf, int msg_size, + Wsr88d_ray_m31 *wsr88d_ray) +{ + Ray_header_m31 ray_hdr; + int n, begin_data_block, bytes_to_read, ray_hdr_len; + unsigned char *radial; + + /* Read ray data header block */ + n = fread(&wsr88d_ray->ray_hdr, sizeof(Ray_header_m31), 1, wf->fptr); + if (n < 1) { + fprintf(stderr,"read_wsr88d_ray_m31: Read failed.\n"); + return 0; + } + if (little_endian()) wsr88d_swap_m31_ray(&wsr88d_ray->ray_hdr); + + ray_hdr = wsr88d_ray->ray_hdr; + + /* + if (ray_hdr.azm_num == 1) testprt(wsr88d_ray->ray_hdr); + */ + + ray_hdr_len = sizeof(ray_hdr); + + /* Read in radial + * Use header_size offset with data pointers + * Copy data into structures + */ + + bytes_to_read = msg_size - ray_hdr_len; + radial = (unsigned char *) malloc(bytes_to_read); + n = fread(radial, bytes_to_read, 1, wf->fptr); + if (n < 1) { + fprintf(stderr,"read_wsr88d_ray_m31: Read failed.\n"); + return 0; + } + + + if (ray_hdr.dbptr_radial_const != 0) { + begin_data_block = ray_hdr.dbptr_radial_const - ray_hdr_len; + memcpy(&wsr88d_ray->unamb_rng, &radial[begin_data_block+6], 2); + memcpy(&wsr88d_ray->nyq_vel, &radial[begin_data_block+16], 2); + if (little_endian()) { + swap_2_bytes(&wsr88d_ray->unamb_rng); + swap_2_bytes(&wsr88d_ray->nyq_vel); + } + } + else { + wsr88d_ray->unamb_rng = 0; + wsr88d_ray->nyq_vel = 0; + } + + if (ray_hdr.dbptr_ref != 0) { + begin_data_block = ray_hdr.dbptr_ref - ray_hdr_len; + wsr88d_ray->ref = read_data_moment(radial, begin_data_block); + } + if (ray_hdr.dbptr_vel != 0) { + begin_data_block = ray_hdr.dbptr_vel - ray_hdr_len; + wsr88d_ray->vel = read_data_moment(radial, begin_data_block); + } + if (ray_hdr.dbptr_sw != 0) { + begin_data_block = ray_hdr.dbptr_sw - ray_hdr_len; + wsr88d_ray->sw = read_data_moment(radial, begin_data_block); + } + + + /* For testing: print reflectivity data. */ + int prtdata = 0; + { int i; + if (prtdata) { + for (i=0; i < wsr88d_ray->ref->data_hdr.ngates; i++) { + if (i % 10 == 0) printf("\n"); + printf(" %d", wsr88d_ray->ref->data[i]); + } + printf("\n"); + } + } + + free(radial); + return 1; +} + + +void wsr88d_load_ray_data(Data_moment *data_block, Ray *ray) +{ + Data_moment_hdr data_hdr; + int ngates; + int i; + float value, scale, offset; + unsigned char *data; + Range (*invf)(float x); + float (*f)(Range x); + + data_hdr = data_block->data_hdr; + data = data_block->data; + + /* + printf("wsr88d_load_ray_data: "); + printf(" DataName: %s\n", data_hdr.dataname); + */ + + ngates = data_hdr.ngates; + /* + printf(" ngates = %d\n", ngates); + printf(" scale = %f\n", data_hdr.scale); + printf(" offset = %f\n", data_hdr.offset); + */ + offset = data_hdr.offset; + scale = data_hdr.scale; + + /* Note: data range is 2-255. 0 means signal is below threshold, and 1 + * means range folded. + */ + + /* Test print + for (i=0; i < 10; i++) { + value = (data[i] - offset) / scale; + printf(" bytevalue = %d, value = %f\n", data[i], value); + } + */ + + /* Reflectivity */ + if (strncmp(data_hdr.dataname, "DREF", 4) == 0) { + /* convert data to float + * convert float to range and put in ray.range + */ + f = DZ_F; + invf = DZ_INVF; + for (i = 0; i < ngates; i++) { + if (data[i] > 1) + value = (data[i] - offset) / scale; + else value = (data[i] == 0) ? BADVAL : RFVAL; + ray->range[i] = invf(value); + ray->h.f = f; + ray->h.invf = invf; + } + } + + /* Velocity */ + if (strncmp(data_hdr.dataname, "DVEL", 4) == 0) { + /* convert data to float + * convert float to range and put in ray.range + */ + f = VR_F; + invf = VR_INVF; + for (i = 0; i < ngates; i++) { + if (data[i] > 1) + value = (data[i] - offset) / scale; + else value = (data[i] == 0) ? BADVAL : RFVAL; + ray->range[i] = invf(value); + ray->h.f = f; + ray->h.invf = invf; + } + } + + /* Spectrum Width */ + if (strncmp(data_hdr.dataname, "DSW", 3) == 0) { + /* convert data to float + * convert float to range and put in ray.range + */ + f = SW_F; + invf = SW_INVF; + for (i = 0; i < ngates; i++) { + if (data[i] > 1) + value = (data[i] - offset) / scale; + else value = (data[i] == 0) ? BADVAL : RFVAL; + ray->range[i] = invf(value); + ray->h.f = f; + ray->h.invf = invf; + } + } + ray->h.range_bin1 = data_hdr.range_first_gate; + ray->h.gate_size = data_hdr.range_samp_interval; + ray->h.nbins = ngates; +} + + + +void wsr88d_load_ray_hdr(Wsr88d_ray_m31 wsr88d_ray, Ray *ray) +{ + int month, day, year, hour, minute, sec; + float fsec; + Wsr88d_ray m1_ray; + Ray_header_m31 ray_hdr; + + ray_hdr = wsr88d_ray.ray_hdr; + m1_ray.ray_date = ray_hdr.ray_date; + m1_ray.ray_time = ray_hdr.ray_time; + + wsr88d_get_date(&m1_ray, &month, &day, &year); + wsr88d_get_time(&m1_ray, &hour, &minute, &sec, &fsec); + ray->h.year = year + 1900; + ray->h.month = month; + ray->h.day = day; + ray->h.hour = hour; + ray->h.minute = minute; + ray->h.sec = sec + fsec; + ray->h.azimuth = ray_hdr.azm; + ray->h.ray_num = ray_hdr.azm_num; + ray->h.elev = ray_hdr.elev; + ray->h.elev_num = ray_hdr.elev_num; + ray->h.unam_rng = wsr88d_ray.unamb_rng / 10.; + ray->h.nyq_vel = wsr88d_ray.nyq_vel / 100.; + int elev_index; + elev_index = ray_hdr.elev_num - 1; + ray->h.azim_rate = vcp_data.azim_rate[elev_index]; + ray->h.fix_angle = vcp_data.fixed_angle[elev_index]; + ray->h.vel_res = vcp_data.vel_res; + + /* Get some values using message type 1 routines. + * First load VCP and elevation numbers into msg 1 ray. + */ + m1_ray.vol_cpat = vcp_data.vcp; + m1_ray.elev_num = ray_hdr.elev_num; + m1_ray.unam_rng = wsr88d_ray.unamb_rng; + if (ray_hdr.azm_res != 1) + ray->h.beam_width = 1.0; + else ray->h.beam_width = 0.5; + ray->h.frequency = wsr88d_get_frequency(&m1_ray); + ray->h.pulse_width = wsr88d_get_pulse_width(&m1_ray); + ray->h.pulse_count = wsr88d_get_pulse_count(&m1_ray); + ray->h.prf = wsr88d_get_prf(&m1_ray); + ray->h.wavelength = 0.1071; +} + + +int wsr88d_get_vol_index(char* dataname) +{ + int vol_index; + + if (strncmp(dataname, "DREF", 4) == 0) vol_index = DZ_INDEX; + if (strncmp(dataname, "DVEL", 4) == 0) vol_index = VR_INDEX; + if (strncmp(dataname, "DSW", 3) == 0) vol_index = SW_INDEX; + /* TODO: Add the other data moments. */ + + return vol_index; +} + + +void wsr88d_load_ray_into_radar(Wsr88d_ray_m31 wsr88d_ray, int isweep, int iray, + Radar *radar) +{ + Ray *ray; + Range (*invf)(float x); + float (*f)(Range x); + int vol_index, waveform; + + enum waveforms {surveillance=1, doppler_ambres, doppler_no_ambres, batch}; + +/* for each data moment do + get the name of the data moment + get new volume if needed + get new sweep if needed + get new ray + put this data moment in ray + endfor each data moment +*/ + + /* Note: The data moment type can only be determined by the name within the + * individual data moment block. The name of the pointer is not reliable. + * For example, in legacy resolution mode, dbptr_ref points to the velocity + * data moment in velocity split cuts. Apparently the location of the first + * data moment is always stored in the reflectivity pointer (dbptr_ref), and + * sometimes this is velocity. When this occurs, the velocity data pointer + * (dbptr_vel) then points to spectrum width. + * With super resolution, there actually is reflectivity in the velocity + * split cut. It's there for use with the recombination algorithm. + */ + + if (wsr88d_ray.ray_hdr.dbptr_ref > 0) { + vol_index = wsr88d_get_vol_index(wsr88d_ray.ref->data_hdr.dataname); + switch (vol_index) { + case DZ_INDEX: f = DZ_F; invf = DZ_INVF; break; + case VR_INDEX: f = VR_F; invf = VR_INVF; break; + case SW_INDEX: f = SW_F; invf = SW_INVF; break; + default: f = DZ_F; invf = DZ_INVF; break; + } + /* If this is reflectivity, check the waveform type to make sure + * it isn't from a Doppler split cut. + * We only keep reflectivity if the waveform type is surveillance or + * batch, or the elevation is above the split cut elevations. + */ + waveform = vcp_data.waveform[isweep]; + if (vol_index != DZ_INDEX || + (waveform == surveillance || waveform == batch || + vcp_data.fixed_angle[isweep] >= 6.0)) + { + if (radar->v[vol_index] == NULL) { + radar->v[vol_index] = RSL_new_volume(MAXSWEEPS); + radar->v[vol_index]->h.f = f; + radar->v[vol_index]->h.invf = invf; + } + if (radar->v[vol_index]->sweep[isweep] == NULL) { + radar->v[vol_index]->sweep[isweep] = RSL_new_sweep(MAXRAYS_M31); + radar->v[vol_index]->sweep[isweep]->h.f = f; + radar->v[vol_index]->sweep[isweep]->h.invf = invf; + } + ray = RSL_new_ray(wsr88d_ray.ref->data_hdr.ngates); + wsr88d_load_ray_data(wsr88d_ray.ref, ray); + wsr88d_load_ray_hdr(wsr88d_ray, ray); + radar->v[vol_index]->sweep[isweep]->ray[iray] = ray; + radar->v[vol_index]->sweep[isweep]->h.nrays = iray+1; + } + } + + if (wsr88d_ray.ray_hdr.dbptr_vel > 0) { + vol_index = wsr88d_get_vol_index(wsr88d_ray.vel->data_hdr.dataname); + switch (vol_index) { + case DZ_INDEX: f = DZ_F; invf = DZ_INVF; break; + case VR_INDEX: f = VR_F; invf = VR_INVF; break; + case SW_INDEX: f = SW_F; invf = SW_INVF; break; + default: f = DZ_F; invf = DZ_INVF; break; + } + if (radar->v[vol_index] == NULL) { + radar->v[vol_index] = RSL_new_volume(MAXSWEEPS); + radar->v[vol_index]->h.f = f; + radar->v[vol_index]->h.invf = invf; + } + if (radar->v[vol_index]->sweep[isweep] == NULL) { + radar->v[vol_index]->sweep[isweep] = RSL_new_sweep(MAXRAYS_M31); + radar->v[vol_index]->sweep[isweep]->h.f = f; + radar->v[vol_index]->sweep[isweep]->h.invf = invf; + } + ray = RSL_new_ray(wsr88d_ray.vel->data_hdr.ngates); + wsr88d_load_ray_data(wsr88d_ray.vel, ray); + wsr88d_load_ray_hdr(wsr88d_ray, ray); + radar->v[vol_index]->sweep[isweep]->ray[iray] = ray; + radar->v[vol_index]->sweep[isweep]->h.nrays = iray+1; + } + + if (wsr88d_ray.ray_hdr.dbptr_sw > 0) { + vol_index = wsr88d_get_vol_index(wsr88d_ray.sw->data_hdr.dataname); + switch (vol_index) { + case DZ_INDEX: f = DZ_F; invf = DZ_INVF; break; + case VR_INDEX: f = VR_F; invf = VR_INVF; break; + case SW_INDEX: f = SW_F; invf = SW_INVF; break; + default: f = DZ_F; invf = DZ_INVF; break; + } + if (radar->v[vol_index] == NULL) { + radar->v[vol_index] = RSL_new_volume(MAXSWEEPS); + radar->v[vol_index]->h.f = f; + radar->v[vol_index]->h.invf = invf; + } + if (radar->v[vol_index]->sweep[isweep] == NULL) { + radar->v[vol_index]->sweep[isweep] = RSL_new_sweep(MAXRAYS_M31); + radar->v[vol_index]->sweep[isweep]->h.f = f; + radar->v[vol_index]->sweep[isweep]->h.invf = invf; + } + ray = RSL_new_ray(wsr88d_ray.sw->data_hdr.ngates); + wsr88d_load_ray_data(wsr88d_ray.sw, ray); + wsr88d_load_ray_hdr(wsr88d_ray, ray); + radar->v[vol_index]->sweep[isweep]->ray[iray] = ray; + radar->v[vol_index]->sweep[isweep]->h.nrays = iray+1; + } + +} + + + +void wsr88d_load_sweep_header(Radar *radar, int isweep, + Wsr88d_ray_m31 wsr88d_ray) +{ + int ivolume; + Ray_header_m31 ray_hdr; + Sweep *sweep; + int vcp; + + ray_hdr = wsr88d_ray.ray_hdr; + + for (ivolume=0; ivolume < MAX_RADAR_VOLUMES; ivolume++) { + if (radar->v[ivolume] != NULL && radar->v[ivolume]->sweep[isweep] != NULL) { + sweep = radar->v[ivolume]->sweep[isweep]; + radar->v[ivolume]->sweep[isweep]->h.sweep_num = ray_hdr.elev_num; + radar->v[ivolume]->sweep[isweep]->h.elev = + vcp_data.fixed_angle[isweep]; + if (ray_hdr.azm_res != 1) + sweep->h.beam_width = 1.0; + else sweep->h.beam_width = 0.5; + sweep->h.vert_half_bw = sweep->h.beam_width / 2.; + sweep->h.horz_half_bw = sweep->h.beam_width / 2.; + } + } +} + + +Radar *load_wsr88d_m31_into_radar(Wsr88d_file *wf) +{ + Wsr88d_msg_hdr msghdr; + Wsr88d_ray_m31 wsr88d_ray; + short non31_seg_remainder[1202]; /* Remainder after message header */ + int end_of_vos = 0, isweep = 0, iray = 0; + int msg_hdr_size, msg_size, n; + Radar *radar = NULL; + +/* Message type 31 is a variable length message, whereas all other message + * types are made up of 2432 byte segments. To handle this, we read the + * message header and check the message type. If it is not 31, then we read + * the remainder of the constant size segment. If message type is 31, we read + * the remainder of the message by the size given in message header. + * When reading the message header, we must include 12 bytes inserted + * by RPG, which we ignore, followed by the 8 halfwords (short integers) which + * make up the actual message header. + * For more information, see the "Interface Control Document for the RDA/RPG" + * at the WSR-88D Radar Operations Center web site. + */ + + n = fread(&msghdr, sizeof(Wsr88d_msg_hdr), 1, wf->fptr); + + /* printf("msgtype = %d\n", msghdr.msg_type); */ + msg_hdr_size = sizeof(Wsr88d_msg_hdr) - sizeof(msghdr.rpg); + + + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + + while (! end_of_vos) { + if (msghdr.msg_type == 31) { + if (little_endian()) wsr88d_swap_m31_hdr(&msghdr); + + /* Get size in bytes of message following message header. + * The size given in message header is in halfwords, so double it. + */ + msg_size = (int) msghdr.msg_size * 2 - msg_hdr_size; + + n = read_wsr88d_ray_m31(wf, msg_size, &wsr88d_ray); + if (n <= 0) return NULL; + + /* Load this ray into radar structure ray. */ + wsr88d_load_ray_into_radar(wsr88d_ray, isweep, iray, radar); + iray++; + } + else { /* msg_type not 31 */ + n = fread(&non31_seg_remainder, sizeof(non31_seg_remainder), 1, + wf->fptr); + if (n < 1) { + fprintf(stderr,"Warning: load_wsr88d_m31_into_radar: "); + if (feof(wf->fptr) != 0) + fprintf(stderr, "Unexpected end of file.\n"); + else fprintf(stderr,"Read failed.\n"); + fprintf(stderr,"Current sweep number: %d\n" + "Last ray read: %d\n", isweep+1, iray); + wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); + return radar; + } + if (msghdr.msg_type == 5) { + wsr88d_get_vcp_data(non31_seg_remainder); + radar->h.vcp = vcp_data.vcp; + /* printf("VCP = %d\n", vcp_data.vcp); */ + } + } + + /* Check for end of sweep */ + if (wsr88d_ray.ray_hdr.radial_status == END_OF_ELEV) { + wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); + isweep++; + iray = 0; + } + + if (wsr88d_ray.ray_hdr.radial_status != END_VOS) { + n = fread(&msghdr, sizeof(Wsr88d_msg_hdr), 1, wf->fptr); + if (n < 1) { + fprintf(stderr,"Warning: load_wsr88d_m31_into_radar: "); + if (feof(wf->fptr) != 0) fprintf(stderr, + "Unexpected end of file.\n"); + else fprintf(stderr,"Failed reading msghdr.\n"); + fprintf(stderr,"Current sweep number: %d\n" + "Last ray read: %d\n", isweep+1, iray); + wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); + return radar; + } + } + else { + end_of_vos = 1; + wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); + } + if (feof(wf->fptr) != 0) end_of_vos = 1; + } + + return radar; +} diff --git a/wsr88d_to_radar.c b/wsr88d_to_radar.c new file mode 100644 index 0000000..9ef0597 --- /dev/null +++ b/wsr88d_to_radar.c @@ -0,0 +1,433 @@ +/* + NASA/TRMM, Code 910.1. + This is the TRMM Office Radar Software Library. + Copyright (C) 1996, 1997 + John H. Merritt + Space Applications Corporation + Vienna, Virginia + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include +#include + +#include + +#include "rsl.h" +#include "wsr88d.h" + +extern int radar_verbose_flag; +/* + * These externals can be found in the wsr88d library; secret code. + */ +void print_head(Wsr88d_file_header wsr88d_file_header); +void clear_sweep(Wsr88d_sweep *wsr88d_sweep, int x, int n); +void free_and_clear_sweep(Wsr88d_sweep *wsr88d_sweep, int x, int n); +/* + * Secretly in uf_to_radar.c + */ +Volume *copy_sweeps_into_volume(Volume *new_volume, Volume *old_volume); + + +void float_to_range(float *x, Range *c, int n, Range (*function)(float x) ) +{ + while (n--) { + if (*x == WSR88D_BADVAL) *c = function(BADVAL); + else if (*x == WSR88D_RFVAL) *c = function(RFVAL); + else *c = function(*x); + c++; x++; + } +} + +/**********************************************************************/ +/* */ +/* done 3/23 wsr88d_load_sweep_into_volume */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* March 3, 1994 */ +/**********************************************************************/ +int wsr88d_load_sweep_into_volume(Wsr88d_sweep ws, + Volume *v, int nsweep, unsigned int vmask) +{ + int i; + int iray; + float v_data[1000]; + Range c_data[1000]; + int n; + + int mon, day, year; + int hh, mm, ss; + float fsec; + int vol_cpat; + + Ray *ray_ptr; + Range (*invf)(float x); + float (*f)(Range x); + + /* Allocate memory for MAX_RAYS_IN_SWEEP rays. */ + v->sweep[nsweep] = RSL_new_sweep(MAX_RAYS_IN_SWEEP); + if (v->sweep[nsweep] == NULL) { + perror("wsr88d_load_sweep_into_volume: RSL_new_sweep"); + return -1; + } + + v->sweep[nsweep]->h.nrays = 0; + f = (float (*)(Range x))NULL; + invf = (Range (*)(float x))NULL; + if (vmask & WSR88D_DZ) { invf = DZ_INVF; f = DZ_F; } + if (vmask & WSR88D_VR) { invf = VR_INVF; f = VR_F; } + if (vmask & WSR88D_SW) { invf = SW_INVF; f = SW_F; } + + v->h.invf = invf; + v->h.f = f; + v->sweep[nsweep]->h.invf = invf; + v->sweep[nsweep]->h.f = f; + + for (i=0,iray=0; i 0) { + wsr88d_get_date(ws.ray[i], &mon, &day, &year); + wsr88d_get_time(ws.ray[i], &hh, &mm, &ss, &fsec); + /* + fprintf(stderr,"n %d, mon %d, day %d, year %d, hour %d, min %d, sec %d, fsec %f\n", + n, mon, day, year, hh, mm, ss, fsec); + */ + /* + * Load the sweep/ray headar information. + */ + + v->sweep[nsweep]->ray[iray] = RSL_new_ray(n); + /*(Range *)calloc(n, sizeof(Range)); */ + + ray_ptr = v->sweep[nsweep]->ray[iray]; /* Make code below readable. */ + ray_ptr->h.f = f; + ray_ptr->h.invf = invf; + ray_ptr->h.month = mon; + ray_ptr->h.day = day; + ray_ptr->h.year = year + 1900; /* Yes 1900 makes this year 2000 compliant, due to wsr88d using unix time(). */ + ray_ptr->h.hour = hh; + ray_ptr->h.minute = mm; + ray_ptr->h.sec = ss + fsec; + ray_ptr->h.unam_rng = wsr88d_get_range (ws.ray[i]); + ray_ptr->h.azimuth = wsr88d_get_azimuth (ws.ray[i]); +/* -180 to +180 is converted to 0 to 360 */ + if (ray_ptr->h.azimuth < 0) ray_ptr->h.azimuth += 360; + ray_ptr->h.ray_num = ws.ray[i]->ray_num; + ray_ptr->h.elev = wsr88d_get_elevation_angle(ws.ray[i]); + ray_ptr->h.elev_num = ws.ray[i]->elev_num; + if (vmask & WSR88D_DZ) { + ray_ptr->h.range_bin1 = ws.ray[i]->refl_rng; + ray_ptr->h.gate_size = ws.ray[i]->refl_size; + } else { + ray_ptr->h.range_bin1 = ws.ray[i]->dop_rng; + ray_ptr->h.gate_size = ws.ray[i]->dop_size; + } + ray_ptr->h.vel_res = wsr88d_get_velocity_resolution(ws.ray[i]); + vol_cpat = wsr88d_get_volume_coverage(ws.ray[i]); + switch (vol_cpat) { + case 11: ray_ptr->h.sweep_rate = 16.0/5.0; break; + case 12: ray_ptr->h.sweep_rate = 17.0/4.2; break; + case 21: ray_ptr->h.sweep_rate = 11.0/6.0; break; + case 31: ray_ptr->h.sweep_rate = 8.0/10.0; break; + case 32: ray_ptr->h.sweep_rate = 7.0/10.0; break; + case 121:ray_ptr->h.sweep_rate = 20.0/5.5; break; + default: ray_ptr->h.sweep_rate = 0.0; break; + } + + ray_ptr->h.nyq_vel = wsr88d_get_nyquist(ws.ray[i]); + ray_ptr->h.azim_rate = wsr88d_get_azimuth_rate(ws.ray[i]); + ray_ptr->h.fix_angle = wsr88d_get_fix_angle(ws.ray[i]); + ray_ptr->h.pulse_count = wsr88d_get_pulse_count(ws.ray[i]); + ray_ptr->h.pulse_width = wsr88d_get_pulse_width(ws.ray[i]); + ray_ptr->h.beam_width = .95; + ray_ptr->h.prf = wsr88d_get_prf(ws.ray[i]); + ray_ptr->h.frequency = wsr88d_get_frequency(ws.ray[i]); + ray_ptr->h.wavelength = 0.1071; /* Previously called + * wsr88d_get_wavelength(ws.ray[i]). + * See wsr88d.c for explanation. + */ + + /* It is no coincidence that the 'vmask' and wsr88d datatype + * values are the same. We expect 'vmask' to be one of + * REFL_MASK, VEL_MASK, or SW_MASK. These match WSR88D_DZ, + * WSR88D_VR, and WSR88D_SW in the wsr88d library. + */ + ray_ptr->h.nbins = n; + memcpy(ray_ptr->range, c_data, n*sizeof(Range)); + v->sweep[nsweep]->h.nrays = iray+1; + v->sweep[nsweep]->h.elev += ray_ptr->h.elev; + v->sweep[nsweep]->h.sweep_num = ray_ptr->h.elev_num; + iray++; + } + } + } + v->sweep[nsweep]->h.beam_width = .95; + v->sweep[nsweep]->h.vert_half_bw = .475; + v->sweep[nsweep]->h.horz_half_bw = .475; + /* Now calculate the mean elevation angle for this sweep. */ + if (v->sweep[nsweep]->h.nrays > 0) + v->sweep[nsweep]->h.elev /= v->sweep[nsweep]->h.nrays; + else { + free(v->sweep[nsweep]); /* No rays loaded, free this sweep. */ + v->sweep[nsweep] = NULL; + } + + return 0; +} + +/**********************************************************************/ +/* */ +/* RSL_wsr88d_to_radar */ +/* */ +/* By: John Merritt */ +/* Space Applications Corporation */ +/* March 3, 1994 */ +/**********************************************************************/ + +Radar *RSL_wsr88d_to_radar(char *infile, char *call_or_first_tape_file) +/* + * Gets all volumes from the nexrad file. Input file is 'infile'. + * Site information is extracted from 'call_or_first_tape_file'; this + * is typically a disk file called 'nex.file.1'. + * + * -or- + * + * Uses the string in 'call_or_first_tape_file' as the 4 character call sign + * for the sight. All UPPERCASE characters. Normally, this call sign + * is extracted from the file 'nex.file.1'. + * + * Returns a pointer to a Radar structure; that contains the different + * Volumes of data. + */ +{ + Radar *radar; + Volume *new_volume; + Wsr88d_file *wf; + Wsr88d_sweep wsr88d_sweep; + Wsr88d_file_header wsr88d_file_header; + Wsr88d_tape_header wsr88d_tape_header; + int n; + int nsweep; + int iv; + int nvolumes; + int volume_mask[] = {WSR88D_DZ, WSR88D_VR, WSR88D_SW}; + char *field_str[] = {"Reflectivity", "Velocity", "Spectrum width"}; + Wsr88d_site_info *sitep; + char site_id_str[5]; + char *the_file; + int expected_msgtype = 0; + char version[8]; + + extern int rsl_qfield[]; /* See RSL_select_fields in volume.c */ + extern int *rsl_qsweep; /* See RSL_read_these_sweeps in volume.c */ + extern int rsl_qsweep_max; + + Radar *load_wsr88d_m31_into_radar(Wsr88d_file *wf); + + sitep = NULL; +/* Determine the site quasi automatically. Here is the procedure: + * 1. Determine if we have a call sign. + * 2. Try reading 'call_or_first_tape_file' from disk. This is done via + * wsr88d_read_tape_header. + * 3. If no valid site info, abort. + */ + if (call_or_first_tape_file == NULL) { + fprintf(stderr, "wsr88d_to_radar: No valid site ID info provided.\n"); + return(NULL); + } else if (strlen(call_or_first_tape_file) == 4) + sitep = wsr88d_get_site(call_or_first_tape_file); + else if (strlen(call_or_first_tape_file) == 0) { + fprintf(stderr, "wsr88d_to_radar: No valid site ID info provided.\n"); + return(NULL); + } + + if (sitep == NULL) + if (wsr88d_read_tape_header(call_or_first_tape_file, &wsr88d_tape_header) > 0) { + memcpy(site_id_str, wsr88d_tape_header.site_id, 4); + sitep = wsr88d_get_site(site_id_str); + } + if (sitep == NULL) { + fprintf(stderr,"wsr88d_to_radar: No valid site ID info found.\n"); + return(NULL); + } + if (radar_verbose_flag) + fprintf(stderr,"SITE: %c%c%c%c\n", sitep->name[0], sitep->name[1], + sitep->name[2], sitep->name[3]); + + + memset(&wsr88d_sweep, 0, sizeof(Wsr88d_sweep)); /* Initialize to 0 a + * heavily used variable. + */ + +/* 1. Open the input wsr88d file. */ + if (infile == NULL) the_file = "stdin"; /* wsr88d.c understands this to + * mean read from stdin. + */ + else the_file = infile; + + if ((wf = wsr88d_open(the_file)) == NULL) { + wsr88d_perror(the_file); + return NULL; + } + + + +/* 2. Read wsr88d headers. */ + /* Return # bytes, 0 or neg. on fail. */ + n = wsr88d_read_file_header(wf, &wsr88d_file_header); + /* + * Get the expected digital radar message type based on version string + * from the Archive II header. The message type is 31 for Build 10, and 1 + * for prior builds. Note that we consider AR2V0001 to be message type 1, + * because it has been in the past, but with Build 10 this officially + * becomes the version number for Evansville (KVWX), which will use message + * type 31. This could be a problem if RSL is used to process KVWX. + */ + if (n > 0) { + strncpy(version, wsr88d_file_header.title.filename, 8); + if (strncmp(version,"AR2V0004",8) == 0 || + strncmp(version,"AR2V0003",8) ==0 || + strncmp(version,"AR2V0002",8) == 0) { + expected_msgtype = 31; + } + else if (strncmp(version,"ARCHIVE2",8) == 0 || + strncmp(version,"AR2V0001",8) == 0) { + expected_msgtype = 1; + } + } + + if (n <= 0 || expected_msgtype == 0) { + fprintf(stderr,"RSL_wsr88d_to_radar: "); + if (n <= 0) + fprintf(stderr,"wsr88d_read_file_header failed\n"); + else + fprintf(stderr,"Archive II header contains unknown version " + ": '%s'\n", version); + wsr88d_close(wf); + free(radar); + return NULL; + } + + if (radar_verbose_flag) + print_head(wsr88d_file_header); + + + if (expected_msgtype == 31) { + + /* Get radar for message type 31. */ + nvolumes = 6; + radar = load_wsr88d_m31_into_radar(wf); + if (radar == NULL) return NULL; + } + else { + /* Get radar for message type 1. */ + nvolumes = 3; + /* Allocate all Volume pointers. */ + radar = RSL_new_radar(MAX_RADAR_VOLUMES); + if (radar == NULL) return NULL; + + /* Clear the sweep pointers. */ + clear_sweep(&wsr88d_sweep, 0, MAX_RAYS_IN_SWEEP); + + /* Allocate a maximum of 30 sweeps for the volume. */ + /* Order is important. WSR88D_DZ, WSR88D_VR, WSR88D_SW, is + * assigned to the indexes DZ_INDEX, VR_INDEX and SW_INDEX respectively. + */ + + for (iv=0; ivv[iv] = RSL_new_volume(20); + + + /* LOOP until EOF */ + nsweep = 0; + for (;(n = wsr88d_read_sweep(wf, &wsr88d_sweep)) > 0; nsweep++) { + if (rsl_qsweep != NULL) { + if (nsweep > rsl_qsweep_max) break; + if (rsl_qsweep[nsweep] == 0) continue; + } + if (radar_verbose_flag) + fprintf(stderr,"Processing for SWEEP # %d\n", nsweep); + + /* wsr88d_print_sweep_info(&wsr88d_sweep); */ + + for (iv=0; iv= radar->v[iv]->h.nsweeps) { + if (radar_verbose_flag) + fprintf(stderr,"Exceeded sweep allocation of %d. " + "Adding 20 more.\n", nsweep); + new_volume = RSL_new_volume(radar->v[iv]->h.nsweeps+20); + new_volume = copy_sweeps_into_volume(new_volume, radar->v[iv]); + radar->v[iv] = new_volume; + } + if (wsr88d_load_sweep_into_volume(wsr88d_sweep, + radar->v[iv], nsweep, volume_mask[iv]) != 0) { + RSL_free_radar(radar); + return NULL; + } + } + } + free_and_clear_sweep(&wsr88d_sweep, 0, MAX_RAYS_IN_SWEEP); + } + + for (iv=0; ivv[iv]->h.type_str = strdup(field_str[iv]); + radar->v[iv]->h.nsweeps = nsweep; + } + } + } + wsr88d_close(wf); + +/* + * Here we will assign the Radar_header information. Take most of it + * from an existing volume's header. + */ + radar_load_date_time(radar); /* Magic :-) */ + + radar->h.number = sitep->number; + memcpy(&radar->h.name, sitep->name, sizeof(sitep->name)); + memcpy(&radar->h.radar_name, sitep->name, sizeof(sitep->name)); /* Redundant */ + memcpy(&radar->h.city, sitep->city, sizeof(sitep->city)); + memcpy(&radar->h.state, sitep->state, sizeof(sitep->state)); + strcpy(radar->h.radar_type, "wsr88d"); + radar->h.latd = sitep->latd; + radar->h.latm = sitep->latm; + radar->h.lats = sitep->lats; + if (radar->h.latd < 0) { /* Degree/min/sec all the same sign */ + radar->h.latm *= -1; + radar->h.lats *= -1; + } + radar->h.lond = sitep->lond; + radar->h.lonm = sitep->lonm; + radar->h.lons = sitep->lons; + if (radar->h.lond < 0) { /* Degree/min/sec all the same sign */ + radar->h.lonm *= -1; + radar->h.lons *= -1; + } + radar->h.height = sitep->height; + radar->h.spulse = sitep->spulse; + radar->h.lpulse = sitep->lpulse; + + radar = RSL_prune_radar(radar); + return radar; +} -- 2.41.0