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; i<MAX_RADAR_VOLUMES; i++) if (rsl_qfield[i]) /* See RSL_select_fields in volume.c */ radar->v[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; i<nfields; i++) { if (little_endian()) swap_2_bytes(&uf_dh[3+2*i]); /* Unswap. */ if (strncmp((char *)&uf_dh[3+2*i], "DZ", 2) == 0) ifield = DZ_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "VR", 2) == 0) ifield = VR_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "SW", 2) == 0) ifield = SW_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "CZ", 2) == 0) ifield = CZ_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "UZ", 2) == 0) ifield = ZT_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "ZT", 2) == 0) ifield = ZT_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "DR", 2) == 0) ifield = DR_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "ZD", 2) == 0) ifield = ZD_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "DM", 2) == 0) ifield = DM_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "RH", 2) == 0) ifield = RH_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "PH", 2) == 0) ifield = PH_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "XZ", 2) == 0) ifield = XZ_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "CD", 2) == 0) ifield = CD_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "MZ", 2) == 0) ifield = MZ_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "MD", 2) == 0) ifield = MD_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "ZE", 2) == 0) ifield = ZE_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "VE", 2) == 0) ifield = VE_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "KD", 2) == 0) ifield = KD_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "TI", 2) == 0) ifield = TI_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "DX", 2) == 0) ifield = DX_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "CH", 2) == 0) ifield = CH_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "AH", 2) == 0) ifield = AH_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "CV", 2) == 0) ifield = CV_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "AV", 2) == 0) ifield = AV_INDEX; else if (strncmp((char *)&uf_dh[3+2*i], "SQ", 2) == 0) ifield = SQ_INDEX; else { /* etc. DON'T know how to handle this yet. */ field_type = (char *)&uf_dh[3+2*i]; fprintf(stderr, "Unknown field type %c%c\n", (char)field_type[0], (char)field_type[1]); continue; } switch (ifield) { 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; case CZ_INDEX: f = CZ_F; invf = CZ_INVF; break; case ZT_INDEX: f = ZT_F; invf = ZT_INVF; break; case DR_INDEX: f = DR_F; invf = DR_INVF; break; case ZD_INDEX: f = ZD_F; invf = ZD_INVF; break; case DM_INDEX: f = DM_F; invf = DM_INVF; break; case RH_INDEX: f = RH_F; invf = RH_INVF; break; case PH_INDEX: f = PH_F; invf = PH_INVF; break; case XZ_INDEX: f = XZ_F; invf = XZ_INVF; break; case CD_INDEX: f = CD_F; invf = CD_INVF; break; case MZ_INDEX: f = MZ_F; invf = MZ_INVF; break; case MD_INDEX: f = MD_F; invf = MD_INVF; break; case ZE_INDEX: f = ZE_F; invf = ZE_INVF; break; case VE_INDEX: f = VE_F; invf = VE_INVF; break; case KD_INDEX: f = KD_F; invf = KD_INVF; break; case TI_INDEX: f = TI_F; invf = TI_INVF; break; case DX_INDEX: f = DX_F; invf = DX_INVF; break; case CH_INDEX: f = CH_F; invf = CH_INVF; break; case AH_INDEX: f = AH_F; invf = AH_INVF; break; case CV_INDEX: f = CV_F; invf = CV_INVF; break; case AV_INDEX: f = AV_F; invf = AV_INVF; break; case SQ_INDEX: f = SQ_F; invf = SQ_INVF; break; default: f = DZ_F; invf = DZ_INVF; break; } /* Do we place the data into this volume? */ if (radar->v[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(uf_lu,"ZA",2) == 0 || strncmp(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; m<len_data; m++) { if (uf_data[m] == (short)UF_NO_DATA) ray->range[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; }
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 i; 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; iv<nvolumes; iv++) if (rsl_qfield[iv]) radar->v[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<nvolumes; iv++) { if (rsl_qfield[iv]) { /* Exceeded sweep limit. * Allocate more sweeps. * Copy all previous sweeps. */ if (nsweep >= 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; } } } if (nsweep == 0) { /* Get Volume Coverage Pattern number for radar header. */ i=0; while (i < MAX_RAYS_IN_SWEEP && wsr88d_sweep.ray[i] == NULL) i++; if (i < MAX_RAYS_IN_SWEEP) radar->h.vcp = wsr88d_get_volume_coverage( wsr88d_sweep.ray[i]); } free_and_clear_sweep(&wsr88d_sweep, 0, MAX_RAYS_IN_SWEEP); } for (iv=0; iv<nvolumes; iv++) { if (rsl_qfield[iv]) { radar->v[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; }
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], failid[]="KFTG"; char *the_file; 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; /* initialize site id to a failsafe value */ wsr88d_set_station_id(failid, -9999.0, -9999.0, -9999.0); 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) < 3) { /*fprintf(stderr, "wsr88d_to_radar: No valid site ID info provided, using default.\n"); strcpy(site_id_str,failid); sitep = wsr88d_get_site(site_id_str); -*enough for now. Message 31 contains ICAO and lat/lon */ /*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; } nvolumes = 3; radar = RSL_new_radar(MAX_RADAR_VOLUMES); /* Allocate all Volume pointers. */ if (radar == NULL) return NULL; /* 2. Read wsr88d headers. */ /* Return # bytes, 0 or neg. on fail. */ n = wsr88d_read_file_header(wf, &wsr88d_file_header); if (n <= 0 || (strncmp(wsr88d_file_header.title.filename, "ARCHIVE2.", 9) != 0 && strncmp(wsr88d_file_header.title.filename, "AR2V000", 7) != 0)) { wsr88d_close(wf); free(radar); return NULL; } if (radar_verbose_flag) print_head(wsr88d_file_header); /* 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; iv<nvolumes; iv++) if (rsl_qfield[iv]) radar->v[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<nvolumes; iv++) { if (rsl_qfield[iv]) { if (nsweep >= radar->v[iv]->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", 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; iv<nvolumes; iv++) { if (rsl_qfield[iv]) { radar->v[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. */ /* set the sitep info from level2 info, message31 if present (TODO) */ if ( sitep == NULL ) { float mess31_lat, mess31_lon, mess31_elev; float dms; wsr88d_get_station_id(site_id_str, &mess31_lat, &mess31_lon, &mess31_elev); sitep = wsr88d_get_site(site_id_str); mess31_lon = mess31_lon * -1.0; if ( sitep == NULL ) { printf("setting site information to ID %s lat %f lon %f elev %f\n", site_id_str, mess31_lat, mess31_lon, mess31_elev); sitep = (Wsr88d_site_info *)malloc(sizeof(Wsr88d_site_info)); sitep->number = -9999; sprintf(sitep->name,"%s\0",site_id_str); sprintf(sitep->city,"--\0"); sprintf(sitep->state,"--\0"); dms = fabs(mess31_lat); sitep->latd = floor(dms); dms = (dms - (float)sitep->latd)*60; sitep->latm = floor(dms); dms = (dms - (float)sitep->latm)*60; sitep->lats = floor(dms); dms = fabs(mess31_lon); sitep->lond = floor(dms); dms = (dms - (float)sitep->lond)*60; sitep->lonm = floor(dms); dms = (dms - (float)sitep->lonm)*60; sitep->lons = floor(dms); if ( mess31_lat < 0 ) { sitep->latd *= -1; sitep->latm *= -1; sitep->lats *= -1; } if ( mess31_lon < 0 ) { sitep->lond *= -1; sitep->lonm *= -1; sitep->lons *= -1; } sitep->height = (int)mess31_elev; sitep->bwidth = -9999; sitep->spulse = 1530; sitep->lpulse = 4630; } } 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; free(sitep); radar = RSL_prune_radar(radar); return radar; }